Snapshots

One accessibility bar for every screen, and the live product misses it

Waiting on you
  • The bar: 4.5 to 1 text contrast, visible focus, 44 px targets, reduced motion respected.
  • The live third text colour fails contrast and is used 787 times.
  • Every direction's kit passes on ink and muted text in both themes.
  • Four of five hero colours fall below 3 to 1 on the light page.
  • No screen reader pass has been run on the kit yet.
787Uses of failing text colour
Your call

Who runs the first screen reader pass, and when?

Design · 3.10

Accessibility

Needs youLast checked Mon Oct 26Owner Param

Answer

Every Brew screen meets one bar in both themes, 4.5 to 1 text contrast, a visible focus ring, 44 px targets on phones, real labels and stillness under reduced motion, and this page records what is measured, where the live product falls short and how we check.

Today

Checked 26 October 2026. Contrast ratios below were computed from the token hex values with the WCAG 2 relative luminance formula; they are token pairs, not rendered pixels.

The docs site, docs.joinsquareup.com

Fact Source
The docs site audit reported text contrast of at least 9.2 to 1 handbook brief, docs site audit 26 Oct; no audit file found in brand-directions or handbook
Recomputed from the docs tokens, ink on the page ground is 14.7 to 1 or more in every direction and theme brand-directions/docs2/build.mjs:253-259
Recomputed, muted text on the tinted second surface drops to 4.8 to 1 for Seeti light and 5.2 for Ocho light, so 9.2 holds for ink, not for muted text brand-directions/docs2/build.mjs:253-259
Tap targets are at least 44 px on phones: home mark, menu button, sub navigation, filters and track links brand-directions/docs2/src/site.css:371-377
Under reduced motion every animation and transition is off brand-directions/docs2/src/site.css:302
A skip to the page link and a 2 px focus outline exist brand-directions/docs2/src/site.css:10, 14-15

The screen kit, tomorrow's product

Fact Source
The contract asks ink and muted text at 4.5 to 1 or more on bg and surface, both themes brand-directions/_shared/kit-contract.md:36
Every direction passes: ink 13.2 to 18.5, muted 5.6 to 8.4 on bg, surface and surface2 brand-directions/docs2/data/dirs.json
Main button label on the hero colour: Fetch 11.8, Buzz 13.1, Scoop 6.8, Ocho 6.0, Seeti 5.1 to 1 brand-directions/docs2/data/dirs.json
The hero colour against the light page is 1.4 for Fetch, 1.3 for Buzz, 2.4 for Scoop, 2.8 for Ocho and 3.2 for Seeti, below 3 to 1 for four of five brand-directions/docs2/data/dirs.json
Focus colour against the page is 4.7 or more in every theme brand-directions/docs2/data/dirs.json
Warn and good text sit at 5.3 to 1 on light surfaces and 7.6 or more on dark brand-directions/_kit/kit.css:23, 27
Focus ring: 2 px outline in the focus token, 2 px offset, on focus-visible brand-directions/_kit/kit.css:33
Main, quiet and icon buttons are 46 px; menu rows 44; inputs 48; the paste button 54 brand-directions/_kit/kit.css:109, 116, 333, 348, 357
Below 44 px: small buttons 36, Back 36, chips 34, Make it tools 34, segment buttons 34, page tabs 40, the switch 28 tall brand-directions/_kit/kit.css:73, 120, 144, 305, 360, 365, 368
The Sample tag and micro labels use 11.5 px type brand-directions/_kit/kit.css:17, 55
A reduced motion block turns off every animation and transition in the frames; each direction's character motion sits inside a no preference query brand-directions/_kit/kit.css:564 brand-directions/_shared/kit-contract.md:25
The character image is aria hidden with empty alt brand-directions/_kit/render.js:54
No screen reader pass has been run on the kit brand-directions/book/content/d2.js:814

The live product, the gaps

Gap Source
The third text colour fails 4.5 to 1: #737373 on dark is 2.99 to 4.18, #808080 on light is 3.25 to 3.95 brew origin/main public/feed-system.css:12, 46
That colour is used 787 times across the live stylesheets, including every quiet page note brew origin/main public/*.css brew origin/main public/quiet.css:7
Icon buttons are 36 px, buttons 40 px, chips 30 px brew origin/main public/feed-system.css:91, 97, 180
124 font size declarations at 11 px or below brew origin/main public/*.css
45 declarations remove the outline; 51 focus-visible rules exist to replace it brew origin/main public/*.css
The html element has no lang attribute brew origin/main public/index.html:1
Sound plays unless the person turns it off brew origin/main public/app.js:1470
A reduced motion catch all exists on the app root: animations end almost at once brew origin/main public/feed-system.css:295-298
The loader holds still under reduced motion brew origin/main public/feed-system.css:157
Old first run ran a check page under a clock, which fails slow readers brand-directions/book/content/d2.js:894-896

Tomorrow

Rule Detail Version Tag
Contrast Ink and muted at 4.5 to 1 or more on bg, surface and surface2, both themes. The live third text colour goes v1 Changes
Hero as an indicator Where the hero colour alone marks state on light, such as the unseen story ring and the switch, pair it with a 3 to 1 edge or a shape v1 New
Targets 44 px or more on phones for anything you tap; small buttons and chips keep a 44 px hit area around a smaller look v1 Changes
Focus 2 px ring in the focus token, 2 px offset, never removed without a replacement v1 Changes
Order Top bar, tabs or rail, Need your yes, picks, See everything v1 New
Sheets Focus goes to the title, stays inside, returns to the opener on Close; Esc and swipe down close v1 Changes
Keys on laptop J, K, H, X, Enter, Esc, M; never needed on a phone; every gesture has a button v1 New
Labels Icon buttons named in 3 words or fewer: Heart, Not for me, More. Tab counts read as words: Today, 2 need your yes v1 Changes
Alt words Product photos say what is in them; the character is named only v1 Changes
Live regions Toasts speak once, politely, one at a time. Each reading source is announced once v1 New
Status Always a word, never colour alone v1 Stays
Motion Character motion only inside the no preference query; nothing carries meaning through motion; celebrations under two seconds v1 Changes
Sound Off on a first visit, one switch in Settings; every spoken line also shows as text v1 Changes
No timers No countdowns, Skip always reachable v1 Changes
Language lang set on the page v1 New
Text size Nothing below 11.5 px; layouts survive 200 percent zoom v1 Changes
v2 posting A scheduled post can be cancelled by keyboard and screen reader up to the moment it goes v2 New
v3 results Charts carry the same numbers as text v3 New
v4 rules Limits and approvals read as text beside each control v4 New

brand-directions/book/content/d2.js:802-915 brand-directions/_shared/product-model.md:113, 250

How we do it

  1. Compute contrast for any new token pair before it lands:
python3 -c "
def L(h):
  c=[int(h[i:i+2],16)/255 for i in (1,3,5)]
  c=[x/12.92 if x<=.03928 else ((x+.055)/1.055)**2.4 for x in c]
  return .2126*c[0]+.7152*c[1]+.0722*c[2]
import sys;a,b=sys.argv[1:3];x,y=sorted([L(a),L(b)]);print(round((y+.05)/(x+.05),2))
" '#a7ad9f' '#111410'
  1. Render every screen at 390 and 1280 wide, light and dark, and tab through it: the ring is visible, the order follows reading order, Esc closes, focus returns.
  2. Turn on reduced motion in the device settings: nothing animates.
  3. Measure tap targets in the browser at 390 wide: every tappable box 44 px or more.
  4. Run VoiceOver on iOS through first run, Today, a pick, Make it and Hand it off.
  5. Log each failure against the kit part, fix it in the kit, so every screen and every direction gets the fix.

Numbers

Number Definition Today Where it is measured Status
Lowest text contrast Worst ink or muted pair on any surface, both themes live 2.99 to 1, kit 5.6 to 1 Token script above Measured
Targets under 44 px on phone Count of tappable elements under 44 px at 390 wide not measured live; 7 kit parts Headless audit Proposed
Unlabelled controls Buttons or links with no accessible name not measured Headless audit Proposed
Screen reader tasks passed Of five core tasks, how many a VoiceOver user finishes none run Test session Proposed
Motion under reduce Animations still running with reduced motion on 0 found in kit CSS Headless audit Proposed

Open

  1. The 9.2 to 1 figure from the docs site audit has no file behind it, and recomputing the docs tokens gives 4.8 to 1 for muted text on Seeti light. Which elements did the audit measure? Proposal: rerun it, publish the script beside the docs and record ink and muted separately.
  2. Four directions' hero colours are below 3 to 1 on the light page. Is an edge or shape on hero indicators acceptable? Proposal: yes, add a 1 px ink edge to the unseen ring and the on switch in light themes.
  3. Should small buttons and chips grow to 44 px tall, or keep their look with a larger hit area? Proposal: a larger hit area, so rows stay quiet.
  4. Who runs the first screen reader pass and when? Proposal: Sai, on the chosen direction, before the restyle ships.
Sources
  • brand-directions/docs2/src/site.css:3, 302, 371-377
  • brand-directions/docs2/build.mjs:253-259
  • brand-directions/docs2/data/dirs.json tokens, contrast computed 26 Oct with the WCAG 2 formula
  • brand-directions/_kit/kit.css:33, 55, 73, 109-126, 144, 305, 333, 348, 360-365, 368, 564
  • brand-directions/_kit/render.js:53-54
  • brand-directions/_shared/kit-contract.md:31-37
  • brand-directions/_shared/product-model.md:113, 250
  • brand-directions/book/content/d2.js:802-915
  • brew origin/main b91e364: public/feed-system.css:10-12, 44-46, 91, 97, 157, 180, 295-298; public/index.html:1; public/app.js:1470; public/quiet.css:7; all public/*.css
  • Docs site audit figures as reported in the handbook brief, 26 Oct

Source file content/design/accessibility.md · For agents: Markdown · JSON