Skip to content

Replace decorative emoji with the icon set on the seven surfaces outside the refresh (game emoji excluded) #385

Description

@TortoiseWolfe

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:

surface decorative emoji now <Icon> uses
CookieConsent.tsx none 1
LocationButton.tsx none 2
app/schedule/page.tsx none 1
app/messages/setup/page.tsx none 1
BlogContent.tsx none 1
A11yDevOverlay.tsx 🎉 → fixed 3
SEOAnalysisPanel.tsx leave, see below 3

Two residual cases, handled without touching the open question:

  • A11yDevOverlay.tsx:252 said "No accessibility violations 🎉". Removed — an emoji cannot take currentColor and renders differently on every OS, which this ticket lists as real regardless of direction. The same line carried text-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: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:

  1. Do the design-specified surfaces get converted from icons to typographic marks (numerals 0104, 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.
  2. 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 01 02 03 04
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/A11yDevOverlay/A11yDevOverlay.tsx
  • src/components/molecular/SEOAnalysisPanel/SEOAnalysisPanel.tsx
  • src/components/map/LocationButton/LocationButton.tsx
  • src/app/schedule/page.tsx
  • src/app/messages/setup/page.tsx
  • src/components/molecular/BlogContent/BlogContent.tsx

Explicitly 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 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).

Design source: ScriptHammer visual refreshScriptHammer Site.dc.html

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.
  • A11y gates stay green: 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.
  • Touch targets stay 44px (min-h-11 min-w-11).
  • These are HTML mockups, not SVG wireframes — they do not belong in features/**/wireframes/ or the /wireframes pipeline.

Part of epic #376

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpriority:p3Low — defer (heavy work, polish, nice-to-haves)

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions