RelayCTX colour · v1
Interface colour · decided — flip rejected

Light mode can have
the bright teal.

It just has to stop putting white text on it. Dark mode worked this out already — and so, quietly, did the cookie banner.

Outcome (2026-08-26): built, rendered, rejected. The flip was shipped into the 29 app-v35 prototype screens so it could be judged in a real interface rather than as a swatch. Verdict on sight: “green with black text — it’s odd.” Dark-on-bright carries a small dense control like the consent button and does not survive being scaled up to a primary CTA. Light reverts to #0f766e + white (5.47:1); dark keeps its flip unchanged. The measurements below all still hold — which is the point of the page: the numbers cleared it and looking at it did not, so the numbers were never going to be the deciding input.

One durable finding survives the revert: the brand green cannot carry white text. The brightest teal keeping white at AA is #0e857b (4.51:1) — too close to the line to ship, given --indigo shipped broken at 4.467:1. With real headroom the ceiling is about #0e8077 (4.80:1), only marginally brighter than #0f766e. That is a property of the colour, not a decision available to anyone.

1 · What you actually pointed at

Two bright green buttons sit on the stealth page. One of them is broken and one of them is correct, and the difference between them is the ink.

Get accesssharpened.html · .btn
background  --rly-accent-fill  #0f766e
colour      --rly-on-accent    #ffffff
5.47:1AA
Keep me postedrelay-access.js · .rly-waitlist-btn
background  --rly-teal        #0d9488
colour      #fff                   — hardcoded
3.74:1fails AA
Allowrelay-consent.js · already shipping
background  --teal            #0d9488
colour      #001311              — ink flip
5.09:1AA

The bright teal was never the problem. White ink on it is. The consent banner has been shipping bright #0d9488 with near-black ink in light mode this whole time, and it passes — which makes the ink flip a thing Relay already does, not a thing Relay is being asked to try.

2 · The same button, four ways

Every ratio below is computed, not estimated. A button carries two contrast obligations, and measuring only the first is how the muted value got chosen in the first place — ink vs fill ≥ 4.5:1 so the label is readable (WCAG 1.4.3), and fill vs page ≥ 3:1 so the button is findable at all (WCAG 1.4.11).

Today · light
#0f766e
+ white
5.47:1 · AA
Bright + white
#0d9488
+ white
3.74:1 · fails
Bright + ink flip
#0d9488 + #0d1514
4.94 label · 3.75 page
passes both · v3.6
Brightest + ink flip
#2dd4bf + #0d1514
9.94 label · 1.86 page
button vanishes

Correction, 2026-08-08. An earlier version of this page recommended #2dd4bf for light on the strength of its 9.94:1 label contrast, and called it “the brightest option is also the most accessible.” That measured the label only. Against a white page the fill is 1.86:1 — far under the 3:1 a UI component needs — so the button stops reading as an object. Bright teal needs a dark ground to be findable, which is exactly why dark mode can use it and light mode cannot. The light answer is #0d9488 + #0d1514 (ratified as v3.6); dark keeps #2dd4bf + #0d1514, unchanged. They do not converge.

3 · In context, not in isolation

A swatch proves a ratio; it does not prove a look. Same fragment of app UI, with and without the flip.

Transfers
Auth unification handoffA9M4FG
Q3 roadmap briefRL2KXD
Design system reviewXXMNDA
View all transfers →

Deliberately unchanged in the flip: Codes stay #0f766e. A Code is text, and #0d9488 as text is 3.74:1. The flip applies to fills — buttons and active states — never to text. That role split is the part of the v3.5 system that is already right and should not be touched.

4 · The bigger problem underneath

Every semantic colour in light mode lands at roughly the same contrast against white. Colours of equal contrast read at equal loudness — so a screen using several of them has no hierarchy at all. It reads as mud.

Light tokenValueOn whitePerceived weight
accent-text#0f766e5.47:1
success#15803d5.02:1
warning#b453095.02:1
error#dc26264.83:1
indigo#585fee4.90:1

Dark mode has no such flattening — it runs 10.44 / 11.15 / 11.64 / 7.03, with real separation between them. tokens.css even labels the dark block “contrast mode; canonical orientation.” Light mode is the weaker theme, and it is weaker because every hue was darkened until it cleared 4.5:1 on white, draining all of them at once.

This is the real reason the app feels busier than the marketing page. The marketing page is near-black text, grey, hairlines and exactly one teal button. The app spends colour everywhere — and in light mode every colour costs the same, so none of it ranks. Fixing the button is worth doing. Fixing the hierarchy is worth more.

Correction, 2026-08-26 — the precedent. This page opens on the claim that the ink flip is “a thing Relay already does” because the cookie banner “quietly” ships near-black #001311 on #0d9488 in light mode at 5.09:1. The arithmetic is right — that pair does measure 5.09:1 — but no implementation ships it. Three were checked, plus the history of the value across the estate: relay-app’s consent bar is the only one using #001311, and it sets it on #2dd4bf (10.24:1) inside a dark-styled bar; the marketing banner used #0d9488 under white (3.74:1 — the failure, since fixed); the platform’s own script uses a green-tinted ghost button, not a filled one. So the flip was a proposal after all, not an observation. It does not change the outcome — the flip was built and rejected on sight regardless — but the page’s founding argument does not hold, and neither does the same sentence in the design history.

5 · The mark and the button are two greens

Raised on sight of the live stealth page — “isn’t that our main green now? What about the marks?” It is a fair read: on one screen the mark draws --rly-accent-ui and the primary button draws --rly-accent-fill, and since RCTX-240 (2026-08-12) those have not been the same value. §2 asks what colour the button should be. This asks whether it should match the mark at all — which is only visible when the two are shown together, so they are.

A · Today
RelayCTX
mark #0d9488
button #0f766e + white
two greens · AA
B · Unify up (the flip)
RelayCTX
both #0d9488
ink #0d1514
one green · rejected on sight
C · Unify down
RelayCTX
both #0f766e
+ white
one green · new identity value
D · Unify up, white ink
RelayCTX
both #0d9488
+ white
one green · 3.74:1 fails

There is no option where the button matches the mark and the page still passes — except one nobody has asked for. D is the 3.74:1 failure RCTX-240 was ratified to remove. B is the flip: it passes both obligations and was rejected on sight (see the top of this page), so it is closed on appearance, not on numbers. C is the only untried route — but it moves the identity value rather than a UI one: the mark, the favicon, the app icons, the social card and every PNG export would be redrawn and re-issued, and the brand would sit a step darker everywhere. That is a brand decision, not a contrast one.

And the gap is smaller than the token names suggest. Rendered at mark scale the two values barely separate — A and C above are near-indistinguishable in the lockup, and the difference only becomes legible at button size, where the fill covers enough area to read as a tone. Whatever this is, it is not a clash.

Worth knowing before treating this as a defect: the split is light-mode only. In dark, --rly-accent-ui, --rly-accent-text and --rly-accent-fill are all #2dd4bf — one green, no split. And the role split is the part of v3.5 that is already right: the mark is non-text so it may be the brighter value, while anything carrying a label must clear 4.5:1 against it. A is what that principle produces. It is a consequence, not an oversight.

6 · What needs deciding

A · Adopt the ink flip for fills in light mode?  BUILT IN v3.6, THEN REVERTED

Bright teal with near-black ink, matching dark mode and the consent banner. Brighter than today and measurably more accessible. The counter-argument is that dark-on-bright reads as a highlighter if it spreads beyond primary actions — so it is scoped to one primary button per surface, and active nav.

B · #0d9488 or #2dd4bf as the light fill?  RESOLVED — #0d9488

Settled by measurement rather than taste: #2dd4bf is only 1.86:1 against a white page, so the button ceases to be findable as a component regardless of how good its label contrast is. #0d9488 passes both obligations (4.94 label / 3.75 page) and keeps the brand green. Dark mode keeps #2dd4bf — on a dark ground it is 10.44:1 and entirely correct.

C · Rebuild the semantic ramp for hierarchy?

Bigger than the button question and independent of it. Would mean pulling most status colour out of light mode entirely — status carried by label and weight, colour reserved for the few states that genuinely need to interrupt. This is the change that would make the app feel like the marketing page.