Colour
One indigo accent does the interactive work; everything else is a calm neutral. Status colour never encodes planning content.
The accent
Exactly one. Indigo was chosen because it collides with no status hue and no zone hue on the map. A second accent is a design change, not a styling choice.
--gd-accent#4740DB#5F57E3filled primary buttons, the selected tab rule, the focus ring AA-nontext
--gd-accent-hover#362FBF#6D66E8hover on a filled accent surface
--gd-accent-pressed#2F2AA3#4740DBpressed
--gd-accent-ink#362FBF#8C86F0accent TEXT on a light ground — links, ghost buttons, the active contents item. The accent proper is 1.9:1 on charcoal and cannot be a link colour in the dark, which is why this forks from `accent` AA
--gd-accent-wash#EEF0FF#3B3866the accent surface — selected rows, count badges, accent chips
--gd-accent-wash-soft#F7F7FD#1C1B2Ethe softest accent ground, for editorial callouts where the full wash shouts
--gd-accent-tintrgba(71, 64, 219, .25)rgba(140, 134, 240, .3)the border of an accent-washed thing
--gd-accent-ringrgba(71, 64, 219, .14)rgba(140, 134, 240, .22)a soft accent halo — the selected parcel's glow on the map, and emphasis behind a chosen thing. NOT a focus indicator: focus is `border-focus-ring` everywhere, because a 14%-alpha wash cannot carry WCAG 1.4.11's 3:1
Ink ladder
Six steps, and each one names the smallest thing it may paint. The chrome is achromatic on purpose: the map already carries a council's zone cartography, so every hue spent on chrome is a hue taken away from something that means something.
--gd-ink#292A2E#F2F2F4headlines and primary text AA
--gd-ink-body#3D4047#C9CBD2body copy — the readable default for prose AA
--gd-ink-secondary#5C6068#9A9EA8supporting sentences beneath a title AA
--gd-ink-muted#6B6E75#8A8E96eyebrows, captions, hints, units — the smallest type that still carries meaning, so it must still clear AA AA
--gd-ink-faint#8A8E96#74777FLARGE type and non-text marks only (≥18.66px, or ≥14px bold). Never prose — see the header note AA-large
--gd-ink-placeholder#9A9EA8#5C606Ba disabled control's label, or a placeholder that only repeats its visible label. Fails AA by design and may carry nothing a user needs
--gd-ink-inverse#FFFFFF#F2F2F4text on `surface-inverse` AA
--gd-ink-on-solid#FFFFFF#101116text on `surface-solid` — the neutral CTA's label AA
--gd-ink-on-accent#FFFFFF#FFFFFFtext on a filled accent surface — white in both themes AA
--gd-ink-on-accent-body#E9E8FB#ECEBFCbody copy on a filled accent band (white at 88%, composited) AA
--gd-ink-on-accent-muted#CBCAF5#DCDAF9LARGE type (≥18.66px, or ≥14px bold) and non-text marks on an accent band — the floor of the ladder (white at 72% / 78%, composited) AA-large
Surfaces & lines
Hover and pressed are SURFACE changes, not shadow changes. A list row darkens; it does not lift. That keeps rows quiet in a long list and stops a panel shimmering as the pointer crosses it.
--gd-surface#FFFFFF#17181Ethe default ground for cards, panels and rows
--gd-surface-page#F4F4F2#101116the page behind everything — warm off-white in the light, the lowest charcoal in the dark
--gd-surface-subtle#FBFBFC#1D1F26table headers and glyph-tile grounds: a surface that is not quite the card it sits on
--gd-surface-sunken#F4F4F7#101116recessed groups — segmented tracks, icon tiles, layer lists. Sunken is the one people get wrong: a GROUP of things is recessed, not raised
--gd-surface-hover#FAFAFB#24262Epointer over a row. Hover is a SURFACE change, never a shadow change — a list that lifts under the pointer shimmers
--gd-surface-pressed#F4F4F7#2B2D36the moment of the click
--gd-surface-selected#EEF0FF#3B3866the chosen row or option
--gd-surface-disabled#F0F1F4#212329an inert control's fill
--gd-surface-inverse#14151A#24262Etoasts, code blocks, the ink CTA band — a surface that is dark in BOTH themes
--gd-surface-solid#14151A#F2F2F4the neutral high-emphasis CTA fill — near-black on a light page, near-white on a dark one. NOT `surface-inverse`, which stays dark in both
--gd-surface-map#F0EEE9#22242Bthe basemap ground. Deliberately not black in the dark, so parcel strokes and overlay fills keep the relationship to their ground that they have in daylight
--gd-surface-scrimrgba(20, 21, 26, 0.42)rgba(0, 0, 0, 0.55)the dimmer behind modal surfaces — dialog, drawer, palette. Deeper in the dark, because 42% charcoal over a charcoal page barely reads as a veil
--gd-surface-on-accentrgba(255, 255, 255, .10)rgba(255, 255, 255, .10)a card or row sitting ON a filled accent band
--gd-surface-on-accent-strongrgba(255, 255, 255, .16)rgba(255, 255, 255, .16)a chip on a filled accent band — one step up from the card it sits in
--gd-line#E8E9ED#2B2D36THE border — cards, inputs, panels
--gd-line-hairline#F0F1F4#212329a divider INSIDE a container that already has a border
--gd-line-soft#ECEEF1#212329the second line weight — nested rules, tracks
--gd-line-strong#D7D8DD#3A3D48a firmer boundary, and every dashed edge (upload zones, clear-space diagrams)
--gd-line-hover#C9CCD2#454955border under the pointer
--gd-line-on-accentrgba(255, 255, 255, .18)rgba(255, 255, 255, .18)the border of a card sitting on a filled accent band
--gd-line-on-accent-hairlinergba(255, 255, 255, .05)rgba(255, 255, 255, .05)the survey grid drawn over a filled accent band — the faintest mark the system has
--gd-line-control#8A8E96#6E7280a boundary that IS the control — an unchecked box, an off switch track. WCAG 1.4.11 applies and the design's #E0E1E6 is 1.2:1 here: an off switch drawn in it is invisible until it is already on, so you cannot tell the control exists. The same call v1 made for `--track`, for the same reason. Honest caveat: iOS and Material ship light tracks too and the knob's shadow is SOME affordance — 3:1 is the defensible reading, not the only one AA-nontext
Divergences from the design file
Two, both deliberate, both about contrast. They are recorded here because a divergence nobody can find is indistinguishable from a mistake.
Caution: Eyebrows and captions were darkened
#8A8E96, which is 3.29:1 on white — under AA for text that is not large, and eyebrows are 10–11px. They take --gd-ink-muted (#6B6E75, 5.11:1) instead, and #8A8E96 survives as --gd-ink-faint, restricted to large text and non-text marks. If a label needs to recede, reduce its size or weight — not its contrast. Caution: The off switch track was darkened
#E0E1E6 is 1.2:1 against the surface. An off switch drawn in it is invisible until it is already on, so you cannot tell the control is there — which WCAG 1.4.11 does not allow for something that is the control. --gd-line-control is 3.29:1. Honest caveat: iOS and Material ship light tracks too, and the knob's shadow is some affordance — 3:1 is the defensible reading, not the only one. A third value was promoted rather than diverged from: caution's #C9A21A is 2.41:1 on white, so the caution solid is the darker #A8850F the design already uses for its filled tile. #C9A21A survives only as a callout's left rule, where the heading ink beside it carries the meaning.