Colour: charts, tenant colours and artwork
Charts
Section titled “Charts”13. Chart colours need their own tokens, and a second cue besides colour.
- Problem. The chart default used the same fills as the UI, and dark charts reused light-mode inks, which are dim on black. Teal marks on the dark panel were too weak, and a colour-blind reader could not tell two series apart.
- Rule. Series colours come from a chart token set. A series’ colour is chosen by hashing its identity so it does not change when sorted or filtered, and each series also gets a dash pattern so colour is never the only cue.
- Values. Dashes: solid,
8 4,2 4,10 3 2 3. - Enforced.
tokens.jsonchart;chrome.cssdefines--chart-*. - Source. Design repo
a1869a2; appchrome.css. - Updated by SW-380 (Design System v2.0): same brights plus an edge. The original rule (light uses the dull
*-inkshades, dark usesaccent-inkand the brighter fills) is replaced. Series 1-5 are now the five bright brand colours (teal, orange, citron, sky, yellow), identical in light and dark, because one brand palette should look the same everywhere. The 3:1 graphics contrast that the dull inks used to buy now comes from--chart-edgeinstead: a 1px edge on every filled mark and a 4px casing under 2px lines (Deep Ink in light, Warm Cream in dark, at least 12:1 on every chart background). Never dull a fill to pass contrast; add or strengthen the edge. Red is not a series colour. Theaccent-inkrule in lesson 5 still holds for text.
Tenant and custom brand colours
Section titled “Tenant and custom brand colours”14. A space’s own colour may only touch public and member pages, and it must be proven readable in both themes.
- Problem. Tenant colours were stored and shipped but never rendered; when rendered naively, a pale tenant colour made white labels fail, and a dark one disappeared on the black page.
- Rule. Staff screens never change; they always use the Space Works palette, so every staff role sees the same screen. Public and member pages derive their brand fill, label, hover, active, soft and ink from the tenant’s two colours, separately for light and dark. The label colour is the first of Deep Ink, Cream, white or black that reaches 4.5:1 on the fill. The derived ink is blended toward the page-appropriate end until it reaches 4.5:1 on every surface and soft it can sit on. Orange emphasis is never overridden.
- Enforced.
frontend/src/lib/brandColours.ts(deriveBrandPalette,brandContrastReport) and its mirror in the backendapps/makerspaces/theme_contrast.py(the comment in the file says keep them in sync); a sweep test accepts all 4,096 three-digit colours in both themes. The server refuses a theme that fails. - Source. App
e023e5a0f; decision 324; design spec H.5 and section I.
15. Do not reject a colour. Fix it, and tell the person.
- Problem. An early guard refused mid-tone colours such as
#777outright, which frustrated space managers. - Rule. Accept any valid colour, then choose a readable label and derive hover and active shades; if a derived state would fall below 4.5:1, degrade to the previous algorithm rather than reject. Where a fill is weak against the page (below 3:1), show an advisory. Offer a one-click fix that moves the lightness the smallest amount (1% steps) until nothing fails.
- Enforced.
frontend/src/lib/colourFix.ts(issuesOf,suggestFix);colourSurfaces.tsexplains in the settings screen which surfaces use which colour (staff: none; member and public: derived; printed and TV: link colour only). - Source. App
e023e5a0f,3c534e6a9(colours panel in the staff console); decision 324; design spec H.5.
Logos and illustrations
Section titled “Logos and illustrations”16. Use the supplied logo variant for each surface. Never recolour the symbol.
- Rule. There are three families: full colour (for light grounds), reversed Cream (for dark grounds) and
one-colour Deep Ink (for single-colour print). Dark mode swaps
lockup-stacked.svgforlockup-stacked-reversed.svg, and the same for the horizontal lockup and the symbol. The monochrome marks have a hollow opening so all four flaps stay visible, which is why recolouring the full-colour symbol is not equivalent. Keep clear space of a quarter of the symbol height; symbol at least 48 px, stacked lockup at least 180 px wide. - Enforced.
SpaceWorksLogotakesground: "light" | "dark", maps only to the supplied files, clamps size to the minimums and has no colour or transform passthrough. Tenant logos are shown as supplied and never animate. - Source. Design spec F; design repo
logo/; decision 362.
17. Scrims and shadows on black: decide deliberately. (Derived from the tokens, not from a shipped fix.)
- Rule. The dialog scrim token is Deep Ink in light and pure black in dark. Because a black scrim over a black
page changes nothing, a dark dialog gets its separation from being a raised
panelwith a 1 pxlineborder, not from the backdrop. The shadow colour is also black in dark, so overlay shadows add almost nothing there: do not rely on them. Cards carry no shadows in either theme; only popovers, menus, modals, drawers and toasts get the one overlay shadow. - Values.
scrimlight#142C2A, dark#000000;--shadow-colorlight20 44 42, dark0 0 0; overlay shadow0 2px 6px rgb(var(--shadow-color)/.06), 0 12px 32px rgb(var(--shadow-color)/.10). - Source. Design repo
tokens.json, README changelog (scrim added in v2.0); design spec E.
18. The mascot on dark gets a thin Cream sticker border.
- Problem. Patch’s thick dark outline nearly vanishes on dark surfaces: 1.0 to 2.3:1 against Deep Ink, against 6 to 14.5:1 on Warm Cream. The first fix put Patch on a Cream card in dark mode.
- Rule. Use
mascot/dark/on dark surfaces only: a 4 px-per-256 px Warm Cream die-cut border, art untouched, same canvas so a dark file drops in for its light twin. Use the plain files on light surfaces. The border is the one approved exception to the “no outlines” rule. Pick the file from the page theme so only one downloads. - Enforced.
site/scripts/dark-mascot.mjsbuilds the dark set from the originals; app serves light and dark files by theme. - Source. Design repo
89e618b,b93db0a; app5b1c10029,48b48f1b0; decisions 55, 56, 57.
19. Illustrations and brand artwork get light and dark twins.
- Rule. Every illustration, empty-state glyph and landing graphic ships as a light and dark pair, chosen by
theme (for example with a
<picture>element andprefers-color-schemeor the app’s ownhtml.dark). Dark artwork keeps its Deep Ink content rather than going teal-tinted. README banners and ID/badge templates also ship both (card templates recolour only the text that sits on the card background in dark). - Source. Decisions 32, 56; INVARIANTS cards.
20. Photos and the Citron field on black. (Partly derived.)
- Rule. The light console search field is a Citron slab with Deep Ink text; on a black page a full Citron slab
glares. In dark the console search becomes a
surfacefield with a Citron border and a Citron-ink icon, so the brand cue survives without a bright block. The public hero search keeps the Citron field in both themes, because it sits on a teal field. Uploaded photos and tenant logos are never recoloured; give them alineborder on black if their edge would merge with the page. - Enforced.
FilterBarhasvariant: "console" | "hero". - Source. App
6e60c20c4.
21. A dark island inside a light page must re-join the black family when the page goes dark.
- Problem. The Deep Ink panel kept for light mode (
.sw-island-dark) showed a green field on a black page. - Rule. In dark, the island is re-mapped to the same black family. Use the island only as the light-mode inverted panel.
- Enforced.
:root.dark .sw-island-darkblock inindex.css, checked bydarkTokens.test.ts. - Source. Design spec D1; decision 316.
Part of Design lessons learned, published from docs/lessons-learned.md. Edit it there.