Put the app on the culpeo palette - #72
Merged
Merged
Conversation
The blue/teal/purple/green scheme had four accent hues doing work that wording and icons already did, and its neutrals were cool greys sitting against what is now a warm canvas — two palettes running against each other. This moves to the same ten roles the web app was rewritten onto, so a place looks the same wherever it's opened and there is one declaration per role rather than one per shade. Accent is now spent only where the style guide sanctions it: the primary button, map pins, focus rings, and selected states. Badges, chips, category labels, and the avatar go neutral. Search results were told apart by the hue behind each glyph — three colours 1.1:1 apart in luminance, which is no distinction at all without colour vision — and now share one treatment, since the section headings above them already say which is which. Several colours turned out to be supplied by dependencies rather than by us, and no grep of this repo would have found them: MapLibre hardcodes a blue location puck in its layer paint, the emoji picker ships a fixed light theme that opened as a white sheet in dark mode, and the switch, every spinner, the caret and the ripple all drew from Android's theme instead of ours. Those are pinned explicitly, via values-night/ where the platform is the only thing that can reach them. Two fixes that are corrections to the shared palette, not ports of it: - Focus was invisible. Inputs used the same neutral border at rest and focused, so focusing a field changed nothing on screen. The new TextField moves the border to accent with a ring. - `line` was doing two jobs with two different bars. As a divider it can be as quiet as it likes, but it was also the border of a text input — whose surface fill is only 1.06:1 against the canvas, so the border is the entire affordance. In dark mode that measured 1.32:1: a field you cannot find at night. Split out `lineControl` (one value for both schemes) for boundaries that are load-bearing; dividers keep `line` and are unchanged. Basemap goes from `liberty` to `positron` for the same reason web moved to a dataviz style: 44 declared colours at 0.178 mean saturation down to 29 at 0.026. The pins are the content, the map is context. Every control boundary and text pairing now clears WCAG AA in both schemes, worst case 3.29:1 against the 3:1 non-text bar. Not yet driven on a device — the states that need eyes on them are a focused field, the Completed toggle, the emoji picker, and the map at night. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Moves the app off the blue/teal/purple/green scheme onto the same ten semantic roles the web app was rewritten onto (
canvas,surface,ink,muted,line,accent,accentText,onAccent,danger, plus three alpha variants). One declaration per role, noisDark ? … : …at any use site.The old palette had four accent hues carrying meaning that wording and icons already carried, and its neutrals were cool greys against what is now a warm canvas — effectively two palettes fighting.
What changed
Accent is spent only where the guide sanctions it — primary button, map pins, focus rings, selected states. Badges, chips, category labels and the avatar go neutral. The "Completed" tag traded green for a ✓.
Search results no longer distinguish by hue. The three result kinds had accent/purple/grey circles behind their glyphs — three colours ~1.1:1 apart in luminance, i.e. indistinguishable without colour vision. They share one neutral treatment now; the section headings already say which is which.
Colours that came from dependencies, not from us. None would turn up in a grep of this repo:
#33B5E5hardcoded in its layer paint<UserLocation>'schildrenthemeprop, mapped onto tokens<Switch>colorPrimarymutedon /line/30off<ActivityIndicator>colorAccentstyles.xml+ newvalues-night/Basemap
liberty→positron— 44 declared colours at 0.178 mean saturation down to 29 at 0.026, for the same reason web moved to a dataviz style. The pins are the content; the map is context.Navigator theme built from our tokens instead of React Navigation's, so the gap during a push transition is the canvas.
Two corrections to the shared palette
Both apply to web too, at the same ratios:
TextFieldmoves the border toaccentwith a ring, and owns the placeholder/caret/selection colours.linewas doing two jobs with two different bars. As a divider it can be as quiet as it likes; but it was also a text input's border, andsurfaceis only 1.06:1 againstcanvas(1.10:1 dark), so the border is the whole affordance. In dark mode that measured 1.32:1 — a field you can't find at night. Split outlineControl(#7a6f69, one value for both schemes) for load-bearing boundaries. Dividers keeplineand are unchanged.Verification
tsc,biome check, 51 tests, and:app:processDebugResourcesall pass.Every control boundary and text pairing clears WCAG AA in both schemes — worst case 3.29:1 against the 3:1 non-text bar, 4.04:1 → 13.24:1 for chip text after moving
line/15fills toink(mutedonline/15fails AA in light).Not yet driven on a device. A linter can't catch "focus produces no visible change," so the states that need eyes on them: a focused field, the Completed toggle, the emoji picker, the map at night, and a cold start for the window background.
Findings worth porting back to web are written up in
addendum.mdalongside the style guide.