You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SEOAnalysisPanel.tsx:42 builds ✗ ${w} into a plain-text clipboard string, not markup. An icon component cannot go in text the user pastes into a document, and a plain-text marker is the correct instrument there. Deliberately unchanged.
What is actually left, and why I am not deciding it
Only the design-direction question in the audit above:
on surfaces the design actually specifies (home, docs, blog, themes, status, sign-in), the marks should become typographic. On chrome the design never draws — the cookie banner, the a11y overlay, the location button, the password toggle — an icon is still better than an emoji, and those are where PR #405's work should stay.
That splits into two owner calls:
Do the design-specified surfaces get converted from icons to typographic marks (numerals 01–04, terminal blocks, large figures, colour swatches, typographic arrows, ⌘K)? The feedback on feat(#385): replace the chrome emoji with the icon set #405's shipped result was "bland, basic" beside the design, which argues yes — but it is a reversal of work already merged, on surfaces owned by their own page children, not by this ticket.
Does the <Icon> set stay for chrome? The audit says yes. If so, nothing further is needed there and this ticket is done.
I am not choosing between these. This ticket's own audit records what happens when that argument gets implemented without weighing it against the design, and making the same call silently a second time would repeat it.
To unblock: answer (1) and (2). If (2) is "yes, icons stay on chrome" and (1) is deferred to the page tickets, this closes now.
🔍 AUDIT vs the real design — 2026-07-28. The design uses no pictograms.
Source now in the repo at docs/design/2a/. PR #405 replaced 18 emoji with a hand-drawn 24px line-icon set. Checked against the design, that was the wrong instrument.
This ticket's own body already said so:"2a uses zero icons; its only marks are typographic." It then argued for replacing the emoji anyway, to avoid removing an icon system and losing scanability. I implemented that argument without weighing it against the design — and the design is unambiguous.
What the design uses instead of icons:
where
the mark
module cards
numerals 01020304
hero proof
a terminal block
stats
large figures — 2,400+ · 32 · 46 · AA
themes
colour swatches
links
typographic arrows — "Read it →", "← Previous", "Next →"
search
the ⌘K glyph
status
a mono uppercase pill in green
Owner feedback on the shipped result was that the SVGs read as "bland, basic" beside the design. That is consistent: a thin line-icon set is a different visual language from numerals-and-terminals, and it sits awkwardly against it.
What is genuinely worth keeping regardless of direction:
Emoji cannot take currentColor and render differently on every OS. That problem was real.
The accessible-name work stands on its own — every replacement was decided per site against the label already beside it, and BlogContent's copy button gained a real sr-only name where it previously had none.
The <Icon> component and its grid tests are sound and cost nothing while unused.
Needs an owner decision, not a silent choice: on surfaces the design actually specifies (home, docs, blog, themes, status, sign-in), the marks should become typographic. On chrome the design never draws — the cookie banner, the a11y overlay, the location button, the password toggle — an icon is still better than an emoji, and those are where PR #405's work should stay.
Replace decorative emoji with the icon set adopted in the Foundation child, on the surfaces not covered by their own page child.
The repo has no icon library — emoji are the icon system, across 11 files. Each of the six refreshed surfaces handles its own as part of its restyle; this ticket covers the remainder.
In scope
src/components/privacy/CookieConsent/CookieConsent.tsx (🍪 at :74)
src/components/organisms/CaptainShipCrewWithNPC/, CaptainShipCrew/, DiceTray/ — 🎲, ship, captain and crew are content, not chrome. Leave them.
Why replace rather than delete
2a uses zero icons; its only marks are typographic. But deleting the emoji would remove an icon system rather than replacing one, and cost scanability on card grids. The real problem with the current emoji is that they cannot take the theme colour and render differently on every OS — which a monochrome currentColor set fixes.
Accessible names
Today's emoji carry them explicitly — CookieConsent.tsx:74 is <span className="text-lg" role="img" aria-label="Cookie">. Replacements must be aria-hidden="true" when a visible text label sits alongside, or carry their own accessible name when standalone. Changing this silently alters what axe and the name-based E2E locators see.
Acceptance criteria
No decorative emoji remain in the listed files.
Game components are untouched.
Every replaced icon either is aria-hidden beside a text label, or has an equivalent accessible name.
Icons inherit currentColor and change with the theme.
Per-component axe suites and pnpm run test:a11y stay green.
No measurable increase in the shared vendor chunk.
Part of the 2a "Machine Shop" visual refresh epic (see the epic for the depth primitives, type
decision and shared guardrails).
Presentational only. No changes to data fetching, auth, Supabase calls or Edge Functions.
Accessible names are an API.performSignIn() (tests/e2e/utils/test-user-factory.ts:1159-1167) is called by ~20 specs and uses getByLabel('Email'), getByLabel('Password', { exact: true }), getByRole('button', { name: 'Sign In' }). exact: true means a Password label change breaks it.
5-file component pattern is CI-enforced — use pnpm run generate:component.
BLOCKED ON AN OWNER DECISION — and the implementation work is essentially already done — 2026-07-30
Measured the seven in-scope surfaces. PR #405 already converted all of them; five have no decorative glyph left at all:
<Icon>usesCookieConsent.tsxLocationButton.tsxapp/schedule/page.tsxapp/messages/setup/page.tsxBlogContent.tsxA11yDevOverlay.tsxSEOAnalysisPanel.tsx✗→ leave, see belowTwo residual cases, handled without touching the open question:
A11yDevOverlay.tsx:252said "No accessibility violations 🎉". Removed — an emoji cannot takecurrentColorand renders differently on every OS, which this ticket lists as real regardless of direction. The same line carriedtext-base-content/60, measured 5.20:1 on base-100 in the light theme (text-base-content/80 fails AAA on base-200 in the light theme — the safe opacity depends on the surface #462); now solid.SEOAnalysisPanel.tsx:42builds✗ ${w}into a plain-text clipboard string, not markup. An icon component cannot go in text the user pastes into a document, and a plain-text marker is the correct instrument there. Deliberately unchanged.What is actually left, and why I am not deciding it
Only the design-direction question in the audit above:
That splits into two owner calls:
01–04, terminal blocks, large figures, colour swatches, typographic arrows,⌘K)? The feedback on feat(#385): replace the chrome emoji with the icon set #405's shipped result was "bland, basic" beside the design, which argues yes — but it is a reversal of work already merged, on surfaces owned by their own page children, not by this ticket.<Icon>set stay for chrome? The audit says yes. If so, nothing further is needed there and this ticket is done.I am not choosing between these. This ticket's own audit records what happens when that argument gets implemented without weighing it against the design, and making the same call silently a second time would repeat it.
To unblock: answer (1) and (2). If (2) is "yes, icons stay on chrome" and (1) is deferred to the page tickets, this closes now.
The repo has no icon library — emoji are the icon system, across 11 files. Each of the six refreshed surfaces handles its own as part of its restyle; this ticket covers the remainder.
In scope
src/components/privacy/CookieConsent/CookieConsent.tsx(🍪 at:74)src/components/organisms/A11yDevOverlay/A11yDevOverlay.tsxsrc/components/molecular/SEOAnalysisPanel/SEOAnalysisPanel.tsxsrc/components/map/LocationButton/LocationButton.tsxsrc/app/schedule/page.tsxsrc/app/messages/setup/page.tsxsrc/components/molecular/BlogContent/BlogContent.tsxExplicitly out of scope
src/components/organisms/CaptainShipCrewWithNPC/,CaptainShipCrew/,DiceTray/— 🎲, ship, captain and crew are content, not chrome. Leave them.Why replace rather than delete
2a uses zero icons; its only marks are typographic. But deleting the emoji would remove an icon system rather than replacing one, and cost scanability on card grids. The real problem with the current emoji is that they cannot take the theme colour and render differently on every OS — which a monochrome
currentColorset fixes.Accessible names
Today's emoji carry them explicitly —
CookieConsent.tsx:74is<span className="text-lg" role="img" aria-label="Cookie">. Replacements must bearia-hidden="true"when a visible text label sits alongside, or carry their own accessible name when standalone. Changing this silently alters what axe and the name-based E2E locators see.Acceptance criteria
aria-hiddenbeside a text label, or has an equivalent accessible name.currentColorand change with the theme.pnpm run test:a11ystay green.Part of the 2a "Machine Shop" visual refresh epic (see the epic for the depth primitives, type
decision and shared guardrails).
Design source: ScriptHammer visual refresh —
ScriptHammer Site.dc.htmlShared guardrails
performSignIn()(tests/e2e/utils/test-user-factory.ts:1159-1167) is called by ~20 specs and usesgetByLabel('Email'),getByLabel('Password', { exact: true }),getByRole('button', { name: 'Sign In' }).exact: truemeans a Password label change breaks it.pnpm run generate:component.config/pa11yci.json(AAA, 4 routes),config/pa11yci-auth.json(AA, 5 auth pages),tests/e2e/color-contrast.spec.ts, ~60 per-component axe tests.min-h-11 min-w-11).features/**/wireframes/or the/wireframespipeline.Part of epic #376