Skip to content

Colour: charts, tenant colours and artwork

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.json chart; chrome.css defines --chart-*.
  • Source. Design repo a1869a2; app chrome.css.
  • Updated by SW-380 (Design System v2.0): same brights plus an edge. The original rule (light uses the dull *-ink shades, dark uses accent-ink and 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-edge instead: 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. The accent-ink rule in lesson 5 still holds for text.

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 backend apps/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 #777 outright, 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.ts explains 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.

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.svg for lockup-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. SpaceWorksLogo takes ground: "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 panel with a 1 px line border, 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. scrim light #142C2A, dark #000000; --shadow-color light 20 44 42, dark 0 0 0; overlay shadow 0 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.mjs builds the dark set from the originals; app serves light and dark files by theme.
  • Source. Design repo 89e618b, b93db0a; app 5b1c10029, 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 and prefers-color-scheme or the app’s own html.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 surface field 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 a line border on black if their edge would merge with the page.
  • Enforced. FilterBar has variant: "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-dark block in index.css, checked by darkTokens.test.ts.
  • Source. Design spec D1; decision 316.

Part of Design lessons learned, published from docs/lessons-learned.md. Edit it there.