editorzero — Meridian Zero

Theme

14 screens of the editorzero product surface in the locked Meridian Zero system — each shown desktop (left) + mobile (right). Switch themes above to re-skin every screen live from one set of :root tokens — the proof that a theme is just a CSS-variable override (curated, or your own).

01 · Dashboard / Home — Org overview

open ↗
DS 9mobile 8token 10a11y 10motion ✓

FRAME / APPROACH - Rendered as the live application frame, not a gallery card: I drop the design-01 `.screen`/`.screen-tab` wrapper and override `.dashboard-viewport` to max-width:none, padding:0, min-height:100dvh so `.win` (248px + 1fr) fills the viewport edge-to-edge. Sidebar is sticky full-height; main column scrolls independently on desktop. Composition follows the canonical reference order (statgrid -> cols2 -> spaces) but denser and more real. DENSITY ADDED OVER REFERENCE - All 4 stat cards carry a cold signal (sparkbar or avatar stack), matching the brief's "4-up statgrid with cold sparkbars." Stat 3 = Active editors incl. agents: an .editors-stack of 3 human squares + 2 notched-cyan agents with a "3 AI" split and a live cyan dot; Stat 4 = Pending suggestions (11, agent-ink) sourced from 3 agents. - Recent-docs .tt extended to 6 rows + a Status column using .status-tag (st-pub/st-draft/st-rev); .editors-stack mixes human + notched agent avatars + AI chips. - Activity ledger extended to 7 entries; human rows use .rail.u (ultramarine), agent rows .rail.ag (cyan) with .ev.ag cyan capability codes (doc.suggest/doc.update). Live AUDIT chip + footer link to the full audit log (every-mutation-one-entry model). - Spaces grid filled to all 6 (reference had 3), 3-up on desktop. HUMANS + AGENTS AS PEERS (throughout) - Human = square ultramarine .av--u/--u2/--u3; agent = notched cyan .av--agent everywhere (stat stack, table, spaces, sidebar). Sidebar "Agents · live" roster lists 4 principals with role scope (editor/author/r-only/idle) and live cyan .dot--agent. Cyan is reserved exclusively for agents, the system's second cold signal. MOBILE / PWA - The base sheet only HIDES .side at <=1120px, so I add navigation back two ways: (1) off-canvas left drawer — .dashboard-side becomes position:fixed; translateX(-100%), opened via .dashboard-shell.is-open (toggled by the .dashboard-burger in the bar) with a dimming .dashboard-scrim; (2) a fixed 5-slot .dashboard-tabbar bottom tab bar <=640px (Overview/Docs/New/Spaces/Agents) with the center "New" as ultramarine primary and an agent tab in cyan. Tab targets >=56px tall; burger sits in a 44px+ row. env(safe-area-inset-bottom) padding for notched phones; body adds bottom padding so content clears the bar. On phone the table drops the Status column + path/label sublines and the stat grid stacks into a single-column ledger — no horizontal scroll. JS contract (static markup here): toggle `is-open` on .dashboard-shell, flip the burger's aria-expanded, and the `hidden` attr on .dashboard-scrim. THEMING / TOKEN PURITY - Zero hard-coded hex in the CSS — every colour is a token (--paper/--surface/--ink*/--steel*/--hair*/--ultra*/--agent*/--ok). Structural metrics use --rule/--rule-2/--radius/--radius-chip; remaining px are layout geometry (widths, clamps, drawer size), not themeable colour. A curated or user theme is just a :root override; this screen inherits it untouched. (Inline styles in the HTML reference tokens too, e.g. color:var(--agent-ink).) ACCESSIBILITY - Contrast: agent text uses --agent-ink (#02646d) not --agent; "co-editing now"/pending lines pair --agent-ink/--ok with the dot as decoration. No standalone body copy on --steel-2. st-pub keeps green text at the darker --ok. - Reduced motion: a prefers-reduced-motion block kills all transitions/animations incl. the .live pulse and the drawer slide. - Semantics: nav landmarks with aria-label, aria-current="page", a real input type=search with aria-label, aria-controls/aria-expanded on the burger, decorative glyphs/dots aria-hidden. Square ultramarine focus-visible ring on every interactive element (links, buttons, [tabindex], tab bar). NEW CLASSES (all dashboard- prefixed) - Layout: dashboard-viewport, dashboard-shell, dashboard-side, dashboard-main, dashboard-bar, dashboard-body, dashboard-page-h, dashboard-cols2, dashboard-statgrid, dashboard-spaces-sec, dashboard-spaces, dashboard-sec-h, dashboard-credit. - Bits: dashboard-agents-h, dashboard-agents, dashboard-agents-ct, dashboard-agent-idle, dashboard-agents-active, dashboard-headchips, dashboard-v-split, dashboard-stack-row, dashboard-stack-more, dashboard-search, dashboard-export, dashboard-tt-wrap, dashboard-tt, dashboard-ledger, dashboard-ledger-foot. - Mobile chrome: dashboard-burger, dashboard-scrim, dashboard-tabbar, dashboard-tab-new, dashboard-tab-agent. DEVIATIONS - Replaced the gallery .screen-tab coordinate band with the real app .bar and added the editorzero logotype lockup to the sidebar top (reference omitted it on the dashboard; a standalone frame wants it). Used 100dvh alongside 100vh for mobile browser chrome. The .spaces base rule drops its bottom border for stacking, so dashboard-spaces re-adds it and recomputes per-child right borders at the 2-up/1-up breakpoints.

a11y --steel-2 as TEXT fails AA outright: 2.59 on --surface / 2.39 on --paper. Real text sites in this screen: .dashboard-agent-idle ('idle'), .stat .ix .ord glyphs (13px), inherited .tt .doc .pth document paths, .ord ordinals, and .fe .t audit timestamps (09:41, 9.5px). These are information, not decoration. · --ok green as TEXT fails AA-normal: 4.41 on --surface / 4.07 on --paper / 3.87 on the st-pub #e4f4eb. .dot--ok DOTS are fine (>3.0 UI), but .stat .d .up ('▲ 18') and the .status-tag.st-pub 'published' label render --ok as small (~9.5-10px) text and fail. Large/UI threshold passes; normal-text does not. · --agent raw cyan as a PERCEIVABLE mark fails 1.4.11 non-text contrast: 2.47 on --surface / 2.28 on --paper. Used as glyph color on the .stat .ix crosshair (color:var(--agent)) and as the .dot--agent fill; the agent-wash ring around the dot is even lower contrast, so the agent state indicator is hard to see. The screen itself uses --agent-ink correctly for the agents-header cross, then contradicts that on the stat icon. · --agent-ink usage is CORRECT and passes everywhere it is text (6.04-6.89): pending count '11', '3 AI' split, .dashboard-agents-active, .ev.ag ledger events, st-rev tag. This is the right discipline — the failures above are the spots that reached for --agent / --steel-2 / --ok-as-text instead of the *-ink token. · Meaningful glyphs not hidden from AT: .stat .ix .ord symbols (◫, ⊙) lack aria-hidden (their crosshair siblings have it), so screen readers announce garbage. The .ord counting numbers ('01'..'06','SP·01') are also exposed as plain text. · Custom interactive elements lack activation/role wiring: .link items ('View all →','Open audit log →','Manage →') use role=link tabindex=0 but show no Enter/Space handler; .sp space cards are tabindex=0 with NO role (announce as generic group). Prefer real <a>/<button>. · Live audit ledger ('AUDIT · LIVE', pulsing, '312 entries · 24h') has no aria-live=polite on .feed — dynamic entries won't be announced. · Search placeholder uses --steel on the --paper-filled search field = 4.21 → fails normal-text AA for placeholder copy. · Off-canvas drawer lacks a focus-management contract: aria-expanded/aria-controls present on the burger, but no focus trap, no aria-modal, and no Esc-to-close specified for the opened .side. · aria-current=page correctly set on BOTH sidebar and bottom-tab Overview links; decorative crosshairs/dots/spark bars/carets are properly aria-hidden. Focus-visible ring (--rule-2 solid --ultra, offset 2px, square) is strong and covers links, buttons, [tabindex], and the tab bar.
fixes Stop using --steel-2 for any text. Promote --steel-2 text sites to at least --steel (passes AA on --surface at 4.56) or --ink-2/--ink-3-on-surface for real content. Specifically: .dashboard-agent-idle, .stat .ix .ord, and (in the base sheet) .tt .doc .pth + .fe .t timestamps. Reserve --steel-2 strictly for hairline-adjacent decoration, never glyphs/labels. · Replace --ok-as-text with a darker functional ink. Introduce --ok-ink (e.g. ~#0a6e3f, ≥4.5 on --surface and on the st-pub wash) and apply it to .stat .d .up and .status-tag.st-pub; keep --ok only for the .dot--ok marks (which already clear the 3.0 UI bar). · Change the stat-card agent crosshair from color:var(--agent) to color:var(--agent-ink) so the agent signal is perceivable (6.4:1), matching what .dashboard-agents-h already does. Keep --agent only for fills that carry their own wash ring, and verify the dot edge — consider a 1px --agent-ink hairline on .dot--agent for the 1.4.11 floor. · Add aria-hidden="true" to the .stat .ix .ord symbol glyphs (◫, ⊙) and to purely-decorative .ord counters, OR swap the symbols for tokened SVGs with proper labels. Don't leave bare Unicode symbols announceable. · Convert .link pseudo-links and .sp cards to real <a href> / <button>. If they must stay as role=link/tabindex, add keydown handlers for Enter (and Space for buttons); a focusable element with no activation path is a WCAG 2.1.1 failure. · Add role="log" aria-live="polite" aria-relevant="additions" to the .feed in the Activity ledger so new audit entries are announced (and pair the visible 'LIVE' affordance with a real live region). · Darken the search placeholder: set .dashboard-search input::placeholder to --ink-3 or --steel-on-surface context, since --steel on the --paper field is 4.21 (sub-AA) for the placeholder string. · Specify drawer a11y: when .dashboard-shell.is-open, trap focus inside .side, set aria-modal semantics, return focus to the burger on close, and bind Esc to close. The CSS/markup is ready; the behavior contract is missing. · Base-sheet debt to retire (not introduced by this screen but consumed by it): .st-pub/.st-rev/.chg.st.acc hard-code #a7d9bf/#e4f4eb. Tokenize these (--ok-wash/--ok-edge) so token purity holds end-to-end and the green tags can be re-contrasted in one place. · Tidy the .cross size overrides: add a tokened size-modifier (e.g. .cross--sm with width/height) instead of repeating inline width/height/color on every crosshair instance; the inline overrides leave a stale flex-basis:16px and bypass the system. · Mid-band nav gap: the bottom tab bar only appears <=640px while the drawer covers <=1120px — fine, but the 'New'/'Agents' primary actions disappear in the 641–1120px band. Consider surfacing '+ New doc' in the sticky bar at that width (it's already there) and confirm Agents is reachable from the drawer.
verdict Strong, system-faithful Dashboard/Home — not the editor, so ADR 0032 inline-ins/del + gutter-accept does not apply (the screen correctly represents suggestions as an overview stat plus audit-ledger events, not a tracked-change surface). Token purity is effectively perfect within the screen's own CSS (no hard-coded hex; only scalar opacity inline), reduced-motion is handled comprehensively, and the mobile story (off-canvas drawer + bottom tab bar, dvh, safe-area, 56px targets) exceeds the brief. The blocking issues are all contrast/semantics, not structure: --steel-2 used as real text (2.4–2.6, fails everything), --ok used as small text (≈4.1–4.4, fails AA-normal), and raw --agent cyan used as a perceivable glyph/dot (≈2.3–2.5, fails 1.4.11) — even though the screen demonstrates the correct --agent-ink discipline elsewhere. Fix the token-as-text misuses, hide the meaningful Unicode glyphs, make the pseudo-links real controls, and add an aria-live ledger + drawer focus-trap, and this is shippable at WCAG 2.1 AA.

02 · Spaces overview

open ↗
DS 8mobile 8token 9a11y 8motion ✗

Composition: full app frame via `.win` (248px `.side` + `.main`). Sidebar reuses `.nav` with Spaces active (`a.on` ultra left-bar) and the live `Agents` nav so agents are present as peers in the chrome. Grid reuses the system `.spaces`/`.sp`/`.editors-stack`/`.bar-tip` atoms; all new classes are `spaces-` prefixed. Six cards as specced — Engineering, Product, Design, Company Wiki, Customer Docs (published), Sandbox — plus a 7th "New space" CTA card so the primary action lives in the grid too (header + mobile-FAB also carry it). Every member stack mixes humans (square `.av--u/u2/u3`) and agents (notched `.av--agent`), with a `+N` overflow chip; cards show doc count, member count (humans+agents), and a mono last-active with a live `.dot--agent` where an agent is currently working. Published/public space (Customer Docs) is made distinct three ways without leaving the token system: `--agent-wash` fill, a permanent left `--ok` accent bar (inset box-shadow, so it reads published even at rest, unlike the hover-only `.bar-tip`), an `.st-pub` "Published" status-tag, and a public-URL line (`docs.northwind.io` + Visit ↗) in agent-ink — signalling the open reader surface and that an agent is indexing it. Theming/tokens: zero hard-coded hex. Every colour, hairline, and the dashed "new" card hatch reference Meridian Zero custom properties (`--agent-wash`, `--ok`, `--ultra`, `--hair`, `--surface-2`, etc.), so a theme override of `:root` restyles the whole screen. Mobile/PWA: the shared sheet hides `.side` at ≤1120px, so I add a sticky bottom **tab bar** (`.spaces-mtab`: Home/Docs/Spaces/+FAB/Agents/You) with a center ink FAB carrying the crosshair mark for "New space", an active ultra top-bar, a cyan agents tab, and the user's square avatar. Grid steps 3→2→1 col with interior border fix-ups at each breakpoint; ≤640px stacks cards, hides the redundant desktop search + ghost export (action preserved via header btn + FAB), and keeps CTAs ≥36–44px tall. At ≤380px tab labels drop to icon-only. `prefers-reduced-motion` disables the tip-bar slide, card transitions, and the live pulse. A11y: card is an `<a>` with `:focus-visible` ultra outline; status/active text uses AA tokens (`--ok` on `--surface`/wash, `--agent-ink`, `--steel` at ≥9.5px mono on light). Deviation: `.spaces-grid` re-declares the `:nth-child` border logic because the base `.spaces` is hard-coded to a 3-up rhythm and I add a 7th card + 2-up/1-up breakpoints — same hairline language, just re-resolved per column count.

a11y --steel-2 used as readable glyphs/separators fails AA: .spaces-glyph, .spaces-sep, .spaces-mt-ic = 2.59:1 on white, 2.39:1 on paper. The bottom tab bar collapses labels to font-size:0 at <=380px, so the 2.6:1 icon becomes the ONLY visible label. · On the published card (background:var(--agent-wash)) .spaces-sep (--steel-2) drops to 2.27:1 and .spaces-stat/.spaces-active (--steel) sit at 4.00:1 — both under AA. · .spaces-more '+9' avatar: --steel on --surface-2 at 8.5px = 4.02:1, fails AA for sub-12px text. · .spaces-active / .spaces-meta labels (9.5-10px --steel) = 4.0-4.56:1: borderline on white, failing on the agent-wash public card. · Published tag reuses base .st-pub: --ok green text on #e4f4eb = 3.87:1 (fails AA normal text); the --ok crosshair glyph on --surface = 4.41:1 (under 4.5:1). · Icon-only tab bar (<=380px) and FAB: only .spaces-mt-fab has aria-label; the five nav links keep DOM text via font-size:0 (SR sees it) but the visual-only glyph carries a 2.6:1 contrast and no aria-current marks the active tab. · --agent / --agent-ink usage is CORRECT: every cyan text token uses --agent-ink (publine URL, Visit, active--pub) at 6.0-6.9:1 (pass); raw --agent appears only on dots/edges/left-bars (non-text). No violation here. · Decorative crosshair spans (.cross in screen-tab, crumb, FAB) and section glyphs lack aria-hidden, so SR users hear empty/garbage nodes.
fixes reduced-motion is INCOMPLETE: the @media (prefers-reduced-motion) block only kills .spaces-sp/.spaces-glyph/.spaces-newcross/.bar-tip transitions. It does NOT stop the base .live pulse (@keyframes pulse, infinite) on .dot--agent.live used in 3 places (sidebar archivist, Engineering card, public card). The block's own comment claims it 'kills the live pulse here' — it doesn't. Add: @media (prefers-reduced-motion:reduce){ .spaces-screen .live{ animation:none; } } (and the mtab .on::before is static, fine). · Stop semantically miscoding 'published/public' with the agent (cyan) signal. The system reserves cyan for AGENTS; public-ness is not an agent property, and the card stacks cyan (wash+edge) + green (--ok bar/cross/tag) = a third color on one tile. Recommend: drop --agent-wash/--agent-edge from .spaces-sp--public; signal 'published' with the --ok left bar + .st-pub tag alone on a normal --surface card, and keep cyan strictly for the actual agent-indexing presence row. This removes the conflated double-signal and the 2.27:1 separator-on-wash failure in one move. · Raise readable-glyph contrast: bump .spaces-glyph, .spaces-sep, .spaces-mt-ic from --steel-2 to --steel (4.5:1+) — or, if they must stay light, mark them aria-hidden and never let them be the sole label. Critically, the <=380px tab bar must keep a visible text label or use a >=4.5:1 icon; font-size:0 hides it from sighted low-vision users. · Add accessible names + state to the tab bar: aria-label on each of the 5 .spaces-mtab links (Home/Docs/Spaces/Agents/You), and aria-current="page" on the active (.on) tab instead of relying on the 2px ultra bar + color alone. · Fix sub-12px text contrast: .spaces-more (8.5px) and .spaces-active/.spaces-meta (9.5-10px) on --steel are under AA at those sizes. Either lift the color to --ink-2 (7.2:1) or raise size to >=12px. The '+N' overflow avatar text especially needs --ink-1/--ink-2. · The base .st-pub tag carries hard-coded hex (#a7d9bf / #e4f4eb) from the SSOT and is reused here — and at 3.87:1 it also fails AA. Tokenize it in the system (e.g. --ok-wash / --ok-edge) and darken the green text token used for tags so the published tag passes; the screen inherits the fix. · Honor the 44px touch target the CSS comment claims: .spaces-visit and .spaces-newcard-btn are min-height:36px; raise to 44px. Verify .spaces-toolbar .seg button (8px padding) and the Sort .filt control also reach 44px on phone. · Add aria-hidden="true" to the purely decorative .cross crosshair spans (screen-tab id, crumb, FAB) so they aren't announced; keep the FAB's aria-label on the link, not the glyph.
verdict Strong, disciplined Meridian Zero screen — clean token hygiene (no authored hard-coded hex anywhere), faithful chrome reuse (real 3-col .spaces grid with correct hairline overrides for the 7th card, notched agent avatars, .editors-stack, brand crosshair, .bar-tip hover, 0px radius), and a genuinely complete responsive story with a real bottom tab bar + FAB and 3-to-2-to-1 column collapse. Not the editor screen, so the ADR-0032 inline-ins/del-vs-card check does not apply. Two real problems keep it from shipping as-is: (1) reduced-motion is only PARTIALLY handled — the infinite .live agent-presence pulse runs in three places despite the block's comment claiming it's killed; (2) the published-space card semantically misuses the cyan AGENT signal for 'public' and stacks it with green, which both violates the one-accent/agents-second-signal rule and produces the worst contrast failure on the screen (steel-2 separators at 2.27:1 on the agent-wash). Plus a cluster of small-text/glyph AA failures (--steel-2 glyphs at 2.6:1, sub-12px --steel labels ~4.0:1, the inherited --ok .st-pub tag at 3.87:1) and missing aria-labels/aria-current on the icon-only tab bar. --agent-ink text usage, by contrast, is exemplary (all >=6:1). Fix the pulse, decouple published from the agent color, and lift the light-glyph contrast, and this is a 9.

03 · Documents list — Engineering space

open ↗
DS 9mobile 8token 8a11y 9motion ✓

PATTERN SOURCE: composed against the canonical mock's SCR.B (design-01-meridian-zero.html, lines 740-854) and the live-agent sidebar pattern (lines 615-620). Reuses .side/.top/.ws/.tree(.row/.ind/.ind2)/.nav-h, .bar/.crumb/.search, .page-h, .toolbar2/.seg/.filt, .tt(.doc/.ord/.nm/.pth/.who/.lbl/.when), .editors-stack, .status-tag(st-pub/st-draft/st-rev), .av--u/--u2/--u3/--agent, .dot--agent.live, .chip--ghost, .btn variants. TOKEN PURITY: zero hard-coded hex in the screen CSS — every colour references a token (--ultra/--ultra-ink/--ultra-wash/--ultra-edge for human+selection, --agent/--agent-ink/--agent-wash/--agent-edge for the agent/live signal, --steel/--ink-* neutrals, --warn-ink for the destructive Trash action, --hair* for rules). Spacing/sizes use --u-derived literals consistent with the sheet and --rule/--rule-2/--radius/--radius-chip metrics. A new theme is still a pure :root override; nothing here defeats it. The only literal is the #fff knockout glyph inside the cobalt/agent checkmark + new-button, matching the sheet's own .av/.btn--ultra convention (white-on-accent). HUMANS + AGENTS AS PEERS: human editors are square ultramarine .av--u/--u2/--u3; agents are notched cyan .av--agent throughout the editors-stack. The live row (ord 01) shows archivist editing now — pulsing .dot--agent.live in three places (sidebar "Agents · live", page sub-meta, and an inline .documents-liveflag on the title), a cyan ring on its avatar (.documents-avlive), an agent-wash row tint with an inset cyan edge bar, and "now" rendered in agent-ink. Agents appear as authors/editors in their own right (linter-bot owns a draft solo). BULK-SELECT: square cobalt checkboxes (.documents-check, appearance:none, token-built tick). A contextual .documents-bulkbar (cobalt wash + inset --ultra edge) carries Move/Set-status/Export/Trash + a select-all and Clear; selected rows get an --ultra-wash tint and inset cobalt edge via :has(:checked) so the selection state reads without JS. Header checkbox = select-all. ACCESSIBILITY: search is a real <input type=search> with aria-label; breadcrumb/treenav/tablists carry aria roles + aria-current; every checkbox + icon-button has an aria-label; decorative glyphs/dots are aria-hidden. Status colours use the sheet's AA-tuned st-* tokens; agent text uses --agent-ink (AA on light), human/selection text --ultra-ink; the destructive action uses --warn-ink (not the small green) for AA. Focus-visible ring on checkboxes. All motion (live pulse, drawer slide) is wrapped in prefers-reduced-motion:reduce. MOBILE / PWA: the shared sheet hides .side at <=1120 — I re-add a hamburger in the bar that opens .side as a CSS-only off-canvas drawer (:target, no JS). At <=640 the <table> repaints into stacked cards (thead visually hidden but kept for semantics; checkbox floats into a 44px left gutter; Updated/Size collapse onto a labelled meta line via ::before), filters scroll horizontally, and a fixed bottom tab bar (Docs/Spaces/New/Agents/More — Agents tab tinted cyan) provides primary nav. Touch targets are >=44px on all actions/pager/tabs; safe-area insets honoured; no horizontal page scroll. The frame fills the viewport edge-to-edge (100dvh) so it reads as the running app, not a centered demo card. NEW CLASSES (all documents- prefixed): -vp, -side(reuse), -burger, -searchfield, -sort/-sortdir, -bulkbar/-bulkall/-selcount/-bulkactions/-danger/-clearsel, -tablewrap/-tt/-cbcol/-check, -rowlive/-liveflag/-avlive/-whenlive, -livenote, -foot/-legend/-pager, -tabbar/-tab/-tab--new/-tabic/-tabic--agent. DEVIATIONS: (1) Added a Size column + leading checkbox column beyond the reference 5-col table, per the brief's richer spec; columns are Title, Status, Editors, Updated, Size. (2) Search is interactive rather than a static chip. (3) Board/Tree segmented control trimmed to List/Board (brief said list/board toggle). (4) Selection visuals rely on :has() (supported in all current evergreen + WebKit, fine for a PWA); a JS-driven class toggle would be the production fallback for any non-:has engine.

a11y --steel-2 on light = 2.4-2.6 contrast, FAILS WCAG AA. It carries real text here: .ord ordinals, .pth doc-paths, .ct collection counts, and the mobile td.when::before 'Updated ' label. Inherited from the SSOT but lands on legible copy, not just decoration. Promote path/count/Updated-label text to --steel (4.56 on white) or --ink-3; keep --steel-2 only for non-text rules/edges. · st-pub 'Published' tag uses --ok (#0d8a4f) at 9.5px: 3.87 on its own #e4f4eb tile, 4.41 on white — FAILS AA for normal text (passes large-text 3.0 only, but 9.5px is not large). Darken the st-pub foreground token (~#0a6e3f) or bump weight+size, since the green is the only thing distinguishing Published from the steel Draft tag. · Raw --agent cyan (#00b6c4) = 2.47 on white / 2.17 on agent-wash — sub-3.0. Acceptable here because every raw-cyan use is decorative and aria-hidden (.dot, .av--agent fill, --agent-edge borders, inset edge bars); all cyan TEXT correctly uses --agent-ink (6.0-6.9, passes AA). Keep this discipline — never let --agent carry text or a sole non-text state indicator. · --agent-ink and --ultra-ink text pairings all pass comfortably (agent-ink/agent-wash 6.04, agent-ink/surface 6.89, ultra-ink/ultra-wash 9.96). No action. · Live/selected state is conveyed by color + a pulsing dot + a text label ('archivist editing', 'editing now', 'now'), not color alone — good for color-blind users. The bulk 'selected' state is also color + checkbox + count text. Pass. · Custom checkbox checkmark is a pure CSS pseudo-element with no accessible affordance of its own, but the native <input type=checkbox> underneath carries per-row aria-label and :focus-visible ultra ring — accessible. White tick on --ultra = 6.67, visible. · Mobile table-to-card repaint hides thead with clip-rect (visually-hidden) rather than display:none, preserving th->td association for screen readers; td::before pseudo-labels add visible context. Good responsive a11y. Verify the ::before 'Updated '/'Size' labels are decorative-only (they restate visible data) so SR users don't hear duplicates. · Off-canvas drawer (.side via :target) has no visible close control and no scrim/overlay; opening it leaves no labelled way back and focus is not trapped or moved. Add a close button (aria-label) + a dismiss scrim, and move focus into the drawer on open. · Breadcrumb, search (role=search), view toggle (role=tablist + aria-selected), and aria-current=page on the active tree row + active tab are all present and correct.
fixes Token purity — remove the 3 hard-coded literals. .documents-vp .side box-shadow uses rgba(11,14,20,.06) (= --ink at 6%) with no token: add a --shadow-soft token to the system or replace with an existing surface treatment. The two #fff (checkbox tick border, .documents-tab--new plus glyph) match an existing SSOT pattern (white-on-fill in .av/.btn--ultra) but the brief mandates zero hard-coded hex — introduce a --on-accent:#fff token and reference it. · Bulk bar is display:flex unconditionally with no :has() gate, and ships with 3 rows pre-checked, so the list's RESTING state shows a permanent ultra-wash bar reading '3 selected'. Gate it: hide by default and reveal via .documents-tablewrap:has(.documents-check:checked) ~ ... or a parent .has-selection, mirroring the row-wash :has() you already use. Ship the default HTML with 0 checked rows. · --steel-2 text contrast: route .pth, .ct, and the mobile 'Updated '/size ::before labels to --steel (or darker). Keep --steel-2 for hairline edges and the .ord ordinal only if you accept it as a faint index marker — but the .ord on doc rows is identifying content, so prefer --steel there too. · st-pub green: define a darker published-foreground (~#0a6e3f, ~5.6 on white) so the 9.5px tag clears AA; the green is load-bearing (it's the only hue separating Published from Draft). · Off-canvas drawer: add (a) a fixed scrim behind .side when open, (b) a close button with aria-label inside .side, (c) focus management on open/close. :target alone gives no escape on touch and no SR affordance. Also note :target leaves the URL hashed — a click-outside/Esc JS handler is the production path. · .av--u3 is --ink-1 (graphite) in the SSOT but the space switcher overrides it inline to var(--ultra). This double-meaning (graphite on rows 05/07, ultramarine on the switcher) is a small drift — use .av--u for the switcher (it's already ultra) and drop the inline style, or keep .av--u3 strictly graphite. · reduced-motion block covers this screen's own motion (.live pulse, drawer slide). For completeness also neutralize the .btn transform/transition and .documents-sort hover-color transitions under prefers-reduced-motion if you treat micro-transitions as motion (optional — these are sub-150ms and arguably exempt). · Mobile new-doc affordance: .documents-tab--new inner glyph box is 30px; the tap target is the parent .documents-tab (56px min-height) so it meets 44px — confirm the whole tab is clickable, not just the 30px square, by ensuring the button fills the flex cell.
verdict Ship-worthy with fixes. This is the Documents-list screen (not the editor), so the ADR 0032 inline-ins/del-vs-card check is N/A — but the same philosophy holds: live agent editing is signalled INLINE in-row (cyan flag + pulsing dot + 'editing now' text) rather than as a detached element, which is correct. DS fidelity is excellent: faithful reuse of .tt/.side/.status-tag/.editors-stack/.toolbar2, square 0-radius structure, the two cold signals (human ultramarine, agent cyan) kept strictly separate, and a legend that spells the semantics out. Three things gate a clean pass: (1) the bulk bar is permanently visible and pre-checked — fix the resting state; (2) --steel-2 and the st-pub green fall below AA on real text; (3) the off-canvas drawer has no close/scrim/focus handling. Token purity is near-total — 3 literals, only the rgba shadow is meaningful drift. Reduced-motion is handled for this screen's motion.

04 · Document reading view

open ↗
DS 9mobile 4token 10a11y 8motion ✓

Composition: built on .win--reader (248 + 1fr + 230) using the canonical reading idioms verbatim from design-01 (the mock the CSS was extracted from): .read-meta strip, .read-h1 with one ultra .z (the period), .read-lede, .doc-body (h2 with hairline top + .ord, .callout ultra, .codeblock, em-dash .ul), and the right .toc with active item + version trail. Went denser than the mock: 4 H2 sections, a provenance .kv block in the rail, and an inline document-end footer carrying the brand crosshair. Humans + agents as peers: meta strip shows an overlapping author stack (two square ultramarine humans + one notched-cyan agent), an explicit "Agent contributor" cell (archivist · AI), the sidebar Contributors list mixes ultra + cyan dots, the version trail attributes v13 to the agent (cyan dot), and the end-footer credits the agent's last edit with a notched avatar. Agent signal stays cyan throughout; human stays ultramarine. Theming/token purity: zero hard-coded hex in screen CSS — every colour/border/spacing references a Meridian Zero token (--ultra/--agent/--ink-*/--hair*/--surface*/--steel*/--rule/--radius). Reading-progress, tab bar, off-canvas panel, footer all token-driven, so a theme override of :root restyles them for free. Mobile / PWA: shared sheet hides .side/.toc and stacks the grid at <=1120px. I added (1) a hamburger (.reading-menu-btn) that opens the sidebar as a pure-CSS off-canvas drawer via :target (#side would be the anchor target — wire id="side" on the aside at integration; transform-based, reduced-motion-safe); (2) a phone bottom tab bar (Doc / Contents / Versions / Edit) shown only <=640px with 56px targets; (3) TOC + versions resurface as a :target bottom sheet above the tab bar (Contents/Versions tabs link to #reading-toc / its anchor at integration). env(safe-area-inset-bottom) padding keeps the installed PWA clear of the iOS home indicator; sticky top bar + sticky progress hairline; body bottom-padding clears the fixed tab bar; no horizontal scroll. Phone body steps to 15px and drops the 66ch measure cap for comfortable column width. Accessibility: body/headings use --ink-1/--ink for AA; mono labels use --steel (not --steel-2) for the readable .read-meta values; --steel-2 reserved for non-essential ordinals/keys. Published status uses the .st-pub token pair (darker --ok-adjacent border/bg from the sheet, not raw --ok on white). All animation (drawer slide, progress fill) wrapped in prefers-reduced-motion: reduce. New classes (all "reading-" prefixed): reading-win, reading-bar, reading-bar-actions, reading-menu-btn, reading-progress, reading-eyebrow, reading-stack, reading-plusone, reading-foot(+-mark/-tx), reading-toc, reading-vtag, reading-vmore, reading-kv, reading-hide-sm, reading-tabbar, reading-tab(+-ic/-lbl). Deviations: the off-canvas drawer and bottom-sheet rely on :target anchors — I left the trigger markup (hamburger button, tab buttons with data-target) in place but the id targets (e.g. id="side", id on .reading-toc) should be set at integration so the CSS :target rules fire; layout/visuals are fully specified and degrade safely (drawer simply stays off-canvas, tab bar still navigates) without JS.

a11y AA-FAIL normal text: --steel-2 is 2.39:1 on --paper / 2.59:1 on --surface. Used at 9-10.5px for .reading-vtag, .reading-vmore, .read-meta .mi .k, and .ord section numbers (01-04). Below the 4.5:1 floor. · AA-FAIL normal text: .st-pub 'Published' uses --ok on its #e4f4eb wash = 3.87:1 at 9.5px uppercase (needs 4.5:1). The same green on --surface is 4.41 and on --paper 4.07 — also under floor for small text. · AA-FAIL non-text (3.0:1): raw --agent fill is 2.47:1 on --surface and 2.28:1 on --paper. Affects .dot--agent and any cyan presence dot/rail as a standalone meaningful indicator; the --agent-wash ring does not raise it. (Agent TEXT pairings are fine: --agent-ink is 6.0-6.9:1; .av--agent's baked #03363b-on-cyan is 5.3:1.) · --steel small text borderline: 4.21:1 on --paper (used for .reading-foot mono at 10.5px) — passes on --surface (4.56) but the foot sits on the white main column so it scrapes by; .reading-foot on a --paper context would fail. · No <main> landmark — the reader column is <div class="main">. Article content is not in a main region. · Two unlabeled <aside> landmarks (.side and .toc) both expose as 'complementary' with no accessible name; SR users can't distinguish collection-nav from document-outline. Contributors <nav> is also unlabeled (tab-bar <nav> correctly has aria-label="Primary"). · Inert mobile controls expose no state: hamburger has aria-label but toggles nothing; tab-bar <button data-target> items have no aria-controls/aria-expanded and open nothing. No Esc/backdrop/focus-management for the intended drawer + sheet. · Sub-44px touch targets at <=640: reading-menu-btn 36px, .btn min-height 38px, .reading-toc rows ~30px. Tab-bar 56px is fine.
fixes BLOCKER (mobile nav is inert): the :target CSS has nothing to match. Add id="reading-side" to <aside class="side"> and id="reading-toc" to <aside class="toc reading-toc">, then make the triggers real anchors: hamburger -> <a class="reading-menu-btn" href="#reading-side">, and the Contents/Versions tabs -> <a href="#reading-toc"> (drop the no-op data-target). Add a full-screen backdrop <a href="#"> behind the open drawer/sheet so a tap dismisses, and a close control inside. This satisfies the existing pure-CSS :target intent with no JS. · Replace --steel-2 with --steel (or --ink-3) for any real text: .reading-vtag, .reading-vmore, .read-meta .mi .k, and .ord when it conveys section numbering. Keep --steel-2 only for genuinely decorative hairline/edge use. Bump .reading-vtag/.read-meta .mi .k off 9px toward 10.5px to clear the small-text threshold. · Fix .st-pub: darken the published green token (e.g. an --ok-ink ~#0a6e3f) for the tag text, or render the label in --ink-1 with the green reserved for the dot/border, so the 9.5px uppercase text clears 4.5:1. · Never rely on raw --agent fill alone as a meaningful indicator: give --agent dots/rails a 1px --agent-ink hairline (or use --agent-ink for the meaningful mark) so the presence signal meets 3.0:1 non-text. Decorative-only cyan can stay as-is. · Add landmarks/names: wrap the reader column in <main>; add aria-label to each <aside> ('Collection navigation', 'Document outline') and to the contributors <nav> ('Contributors'). · Raise mobile touch targets to >=44px: reading-menu-btn 44x44, .reading-bar-actions .btn min-height:44px, .reading-toc a/.vrow min-height:44px. Add aria-controls + aria-expanded (kept in sync) to whatever opens the drawer/sheet once wired. · Optional system hardening: the shared meridian-zero.css ships no prefers-reduced-motion block at all — this screen correctly patches its own, but consider a global reduce block covering .live/@keyframes pulse, .btn, .caret-u blink, .agent-caret, .sp .bar-tip so other screens inherit it.
verdict Strong Meridian Zero composition with flawless token discipline and a correct reading-surface model. Token purity is perfect (zero hard-coded color anywhere; shadows and inline styles all use vars), and design-system fidelity is high: shared atoms reused verbatim (win--reader / reader / read-meta / toc / ver), human-square vs agent-notched avatars, ultra .z accent, mono kickers, hairlines, 0px radius, brand crosshair in the footer, agent-as-second-signal handled in agent-ink throughout. As the READING view (SCR.C) it correctly omits editor tracked-change affordances — no inline sugg-ins/sugg-del or detached sugg-card to mis-flag (ADR 0032 concern doesn't apply here). reducedMotion is properly handled for this screen's own animations (drawer slide, progress width, tab color all wrapped). The screen is held back by one functional blocker and a cluster of contrast issues: the mobile drawer and TOC/Versions bottom-sheet are styled but completely inert because the :target selectors have no matching ids and the triggers are href-less buttons — phones get a dead hamburger and dead tabs. On a11y, several small-text tokens fall under AA (--steel-2 at 2.4-2.6:1, st-pub green at 3.87:1) and raw --agent fill is sub-3.0:1 as a standalone indicator; plus missing <main>, unlabeled duplicate aside landmarks, and sub-44px touch targets. All fixes are mechanical and mostly pure-CSS/markup. Wire the :target ids/anchors and lift the flagged text tokens and this is ship-grade.

05 · Document editor

open ↗
DS 9mobile 8token 7a11y 8motion ✓

Verified by rendering the fragment + meridian-zero.css in headless Chromium at 320/360/390/414/640/768/1024/1440px — zero horizontal overflow at every width; desktop, tablet (collapsed-rail), phone, and phone-with-drawer+sheet states all inspected visually. STRUCTURE (matches the canonical design-01 editor mock, densified): - Full-bleed app frame: .editor-vp overrides .viewport (max-width:none, padding:2u) so the .win--editor 3-zone shell fills the viewport edge-to-edge and runs full height (100dvh). - Left .side: workspace switcher, collection .tree (indented children + version counts), live co-editors (human ultra dot / agent cyan live dot / idle). Centre .main: bar (crumb + "1 SUGGESTION" + Share) → .presence (human ultra .pchip + agent cyan .pchip "archivist · editing" + Synced/CRDT save status) → .fmtbar (offset shadow, groups + cyan "✦ ASK AGENT") → .edcanvas. Right .erail: .kv Properties + .chg tracked-changes ledger (pending cyan / live / done) + Accept-all + agent scope-bar. - Signature beats: .ed-h1 with ultra .z period; human .sel-u + .caret-u; agent .agent-caret with floating cyan .flag + .agent-typing highlight; open .slash menu (blocks + cyan "Ask agent" items). TRACKED SUGGESTION (ADR 0032 — inline marks are primary, card is reviewer): - Inline .sugg-del (strikethrough) + .sugg-ins (cyan underline) ARE the model. - Added a left-gutter quick control (.editor-gutter / .editor-gbtn--acc/--rej) aligned to the marked line, wired by aria-label to the same SG·01 suggestion as the margin .sugg-card, which carries the full diff + rationale + Accept/Reject. Hover/focus on the block links the inline insertion to its control via an extra ring. On <=1120px the gutter relocates from the margin to an inline labelled "ACCEPT / REJECT" row above the paragraph (no margin to live in once rails collapse). MOBILE / PWA: - <=1120px: sidebar becomes an off-canvas drawer (.editor-side--open) over a scrim, toggled by the .editor-drawer-btn (☰). Shared sheet already collapses the rails + inlines the sugg-card. - <=640px: desktop .fmtbar is replaced by a fixed bottom FORMAT bar (.editor-mbar) sitting above a bottom TAB bar (.editor-tabbar: Docs/Edit/Changes[cyan badge]/Agents). Suggestion review is a bottom SHEET (.editor-sheet, role=dialog, slide-up) showing the diff + rationale + full-width Accept/Reject — the "accept a suggestion on a phone" flow. Crumb truncates with ellipsis so the action cluster never overflows; the absolutely-positioned agent .flag is width-clamped + the canvas is overflow-x:clip so its decorative label can't widen the page. All touch targets >=44px (gutter buttons, sheet buttons, tab items, mbar buttons). env(safe-area-inset-bottom) padding on the fixed bottom bars for notched devices. THEMING / TOKEN PURITY: every color references a Meridian Zero token. The only literals are (a) #02363b for ink-on-cyan fills (Accept hovers, mobile AI button, tab badge) — the exact value the shared stylesheet itself uses on the cyan --agent fill (.agent-caret .flag, .sugg-card .sf button.acc), as there is no token for "ink on agent"; and (b) rgba(11,14,20,…) for the drawer scrim/shadow, which is --ink (#0b0e14) alpha-composited — the same pattern the shared sheet uses for .sel-u (rgba of --ultra). Spacing uses the --u scale (calc(var(--u)*N)) for the frame padding, bottom-bar offset, and tab heights. ACCESSIBILITY: text on light meets AA (agent text uses --agent-ink, not the lighter --agent; ok-green uses --ok). Slash menu has role=listbox/option + aria-selected; gutter is a role=group with per-action aria-labels; sheet is role=dialog aria-modal; drawer button has aria-expanded; both bottom navs/toolbars are labelled. ALL motion (added transitions + the shared sheet's .live/blink/pulse keyframes that surface here) is disabled under prefers-reduced-motion. NEW CLASSES (all "editor-" prefixed): editor-vp, editor-screen, editor-win, editor-main, editor-body, editor-canvas, editor-bar, editor-baractions, editor-suggcount, editor-presence, editor-fmtbar, editor-drawer-btn, editor-hide-sm, editor-suggblock, editor-gutter, editor-gbtn(+--acc/--rej), editor-suggcard, editor-emptyblock, editor-slash, editor-erail, editor-side(+--open), editor-scrim, editor-mbar, editor-mbtn(+--ai/--add), editor-sheet(+--open) and its -grab/-head/-title/-body/-qt/-why/-foot/-acc/-rej parts, editor-tabbar, editor-tab(+--on/--chg), editor-tab-ic, editor-tab-badge. DEVIATIONS: (1) Added the gutter quick-control the brief asked for that the canonical mock lacked (mock had only the card). (2) On phone both the inline gutter control and the inlined card show Accept/Reject — intentional: gutter = per-line quick action, card/sheet = detailed reviewer for the same suggestion. (3) JS is omitted (static composition); the --open / drawer-toggle / sheet-open classes are the documented hooks a behaviour layer would toggle.

a11y AA-FAIL (introduced): empty-block placeholder text 'Type / for blocks…' uses color:var(--steel-2) (#97a2b0 on white = 2.59:1) — functional instruction text, fails AA at any size. Use --ink-2/--steel for placeholder, or --steel-2 only on truly decorative glyphs. · AA-FAIL (introduced): right-rail crdt value 'converged' uses inline color:var(--ok) (#0d8a4f) at ~10.5px mono = 4.41:1 on --surface (4.07:1 on --paper) — fails AA normal. --ok is large-text/icon only on light; for small status text pair --ok with --dot--ok glyph or darken. · AA-FAIL (DS-inherited, still present): pervasive --steel-2 small text — .ord (SCR.D, SG·01, D·01), .ct ('you'/'idle'/'writing…'), .chg .mt timestamps, .slash .key, .kv values all sit at 2.27–2.59:1. Inherited from the system but renders here; the ADR-level fix is to retire --steel-2 as a text token. · SIZE: status-tag 'In review' forced to inline font-size:8.5px (below the DS 9.5px floor). Contrast is fine (agent-ink on agent-wash 6.04:1) but 8.5px mono uppercase is sub-legible; drop the inline override. · Touch: gutter accept/reject (.editor-gbtn) is 26px tall in the 641–1120px range (only bumped to 44px at <=640). Tablets are touch surfaces — raise to 44px across the whole collapsed range. · Icon-only controls without labels: .editor-mbtn B / I / bullet have no aria-label (only block-type/AI/add do); .fb format-bar buttons rely on title= only. SR users get no name. Add aria-label to every glyph button. · Bottom sheet has role=dialog aria-modal=true but no focus management (no trap, background not aria-hidden, no Esc) — modal semantics are asserted without behaviour. Drawer likewise: aria-expanded is hardcoded 'false' and never toggled; focus is not moved in. · Active bottom tab uses .editor-tab--on visually but no aria-current='page'; tabs are <a href='#'> placeholders — current location isn't announced.
fixes Tokenise the introduced literals: #02363b (gbtn--acc:hover, sheet-acc:hover, tab-badge fg) has no token — add a --agent-on / --on-agent foreground token (the DS already bakes this exact value into .av--agent/.flag) and reference it. Replace rgba(11,14,20,.06) drawer shadow and rgba(11,14,20,.42) scrim with values derived from --ink (e.g. color-mix(in srgb, var(--ink) 6%/42%, transparent)) so theming the ink recolours the scrim too. · Fix the two introduced contrast fails: change the empty-block placeholder from --steel-2 to --steel (or --ink-3 minimum) and the rail 'converged' value off bare --ok — keep the --ok colour on the dot/icon and render the word in --ink-1, or use a darker functional-text token. · Wire the mobile chrome: the hamburger (.editor-drawer-btn), scrim, sheet and tab bar are CSS-only — add the toggle JS (.editor-side--open / .editor-scrim un-hidden / .editor-sheet--open), move focus into drawer/sheet on open, trap it, close on Esc and scrim tap, and flip aria-expanded. As shipped the phone nav and suggestion sheet cannot open. · Raise .editor-gbtn to >=44px for the whole <=1120 touch range, not just <=640. · Add aria-label to every icon-only button (.editor-mbtn B/I/bullet, .fb format buttons) and aria-current='page' to the active .editor-tab--on. · Extend the prefers-reduced-motion block to also neutralise the DS-inherited micro-transitions that fire here: .editor-screen .btn { transition:none } and .editor-screen .eblock .handle { transition:none } (the handle opacity reveal). Signature motion is already covered; these two are the only leaks. · Drop the inline font-size:8.5px on the st-rev status-tag (let it inherit the DS 9.5px); replace the remaining inline style= colour overrides (the --ok, --steel-2, --ultra-ink, --agent-ink, --ultra fills) with utility classes so the screen carries no inline themeable values.
verdict Strong, system-faithful editor screen. Tracked suggestions are CORRECT per ADR 0032 — inline .sugg-del + .sugg-ins marks are the primary model, with a gutter accept/reject group AND a supplementary margin card (not the wrong detached-card-only pattern). Human-square / agent-notched avatars, agent-ink text discipline, dvh + safe-area + real mobile chrome (drawer, bottom format bar, suggestion bottom-sheet, tab bar), and a genuinely conscientious reduced-motion block that neutralises the DS keyframes it can't edit. Three things keep it from top marks: (1) the mobile chrome is structurally present but behaviourally inert (no toggle JS, no focus management) so the phone nav/sheet can't actually open; (2) token purity is broken by introduced literals — #02363b with no token and two rgba(11,14,20,…) ink duplicates for scrim/shadow; (3) two introduced AA fails (steel-2 placeholder text, --ok as small status text) on top of the system's own steel-2 text debt. All fixable without touching the locked DS. Net: ship-quality visual + structure, blocked on wiring the mobile interactions and tokenising/recolouring the four hard-coded values.

06 · Search + command palette

open ↗
DS 9mobile 8token 9a11y 8motion ✓

LAYOUT - Two layers as specced. Behind: a `.win--full` search-results page — top query bar (live mono input + ⌘K hint + an "Agent results" quick toggle), a 236px facets sidebar, and a results column. Front: a centered cmdk palette over an ink scrim. - Facets sidebar = Type / Space / Author / Updated, with active-filter chips at top. Author facet lists humans (square ultra avatars) AND agents (notched cyan avatars + "agent" chip) as peer principals; counts are tabular. - Result rows carry ranked ordinals, status tags (reusing `.status-tag`/`.st-*`), mono breadcrumb path, snippet with ULTRA `<mark>` highlights, and a byline showing the human/agent author plus per-result agent-edit chips and an overlapping `.editors-stack`. COMMAND PALETTE - Centered, offset hard shadow (`10px 10px 0 var(--surface-sunk)`), 1.5px ink border, mono throughout — matching the `.slash`/`.fmtbar` engineering-popover idiom already in the system. - Groups: Documents, Spaces, People & Agents, Actions (Create document ⌘N, Invite member/agent ⌘I, and "Ask an agent" ⌘↵ in cyan). The selected row is ink-inverse with an ultra left bar; its mark/sub/chips all invert. Key-chip hints (`.search-kchip`) on rows + a footer hint bar; the AI action's chip uses the agent token. - Live results filter on a partial query ("determ") with highlighted matches; an agent presence dot pulses on Curie. THEMING / TOKEN PURITY - No hard-coded hex except the `#fff` checkmark border on the ultra-filled checkbox (a fixed contrast mark on the accent, matching the system's own `color:#fff` on `.btn--ultra`/`.av`). Every other colour, border, and shadow references a Meridian Zero token. Spacing/sizing use px on the existing system's px scale (the SSOT itself uses literal px in components); structural radii inherit the global 0px. - Scrim uses `color-mix(in srgb, var(--ink) 46%, transparent)` so even the overlay dim derives from a token — a custom theme that overrides `--ink` recolours the scrim for free. A theme is still just a `:root` override. ACCESSIBILITY - AA text: bylines/sub-text use `--steel`/`--ink-2` (not `--steel-2`) for body-size copy; `--steel-2` is reserved for ≤10px mono incidentals. Inverse rows use `--paper`/`--ultra-edge` on `--ink`. Status green stays in the `--ok` tag tokens. - Checkboxes are real `<input>`s (visually hidden, custom `.search-cb`) with `:focus-visible` ultra outline; dialog has `role="dialog" aria-modal`, selected row `aria-selected`, search landmark on the query field. - All transitions + `.live` pulse wrapped in `prefers-reduced-motion: reduce`. MOBILE / PWA - ≤1120px: facets reflow to a 2-up top strip above results (hairlines dropped). ≤760px: palette becomes a full-screen sheet (top:0, 100% h/w, no shadow/border), query field 16px to avoid iOS zoom, on-screen keyboard-hint footer hidden, palette rows ≥44px; a 5-slot bottom tab bar appears (Home/Docs/Search/Agents/You — Search active, ultra indicator, Agents tab carries a cyan dot, You shows the user's ultra avatar). ≤420px drops the rank ordinal to keep snippets full-width. No horizontal scroll at any width. NEW CLASSES (all `search-` prefixed) - Page: search-bar, search-field(-x), search-input, search-clear, search-k, search-only-ai, search-body, search-facets, search-facet-head, search-reset, search-active, search-fgroup, search-fg-h, search-opt, search-cb, search-ol, search-on, search-agtag, search-dates, search-date, search-results, search-res-head, search-count, search-q, search-sort, search-sortbtn, search-list, search-row, search-rank, search-rc, search-rtop, search-title, search-path, search-snip, search-meta, search-by, search-dot, search-rtag, search-more, search-page. - Palette: search-scrim, search-palette, search-pal-input, search-pal-x, search-pal-field, search-pal-scope, search-kchip(--ai), search-pal-body, search-grp, search-grp-h, search-item(--ai), search-it-ic(--sp/--act/--ai), search-it-tx, search-it-nm, search-it-sub, search-it-av, search-it-pav, search-ai-q, search-pal-foot, search-fhint(--right). - Mobile nav: search-tabbar, search-tab, search-tab-ic, search-tab-x, search-tab-av, search-tab-l. DEVIATIONS - Reused `.status-tag`, `.chip*`, `.av*`, `.editors-stack`, `.dot*`, `.kicker`, `.ord`, `.cross`, `.btn*`, `.hr`, `.logo` directly; only genuinely new structure got `search-` classes. - The screen is wrapped in `.screen` + `.screen-tab` (the engineering-drawing frame the system uses for each screen) so it reads as part of the same spec sheet; overlay/scrim/tabbar are positioned `absolute` within that `.screen` (relative) rather than `position:fixed`, so the fragment composes cleanly inside the preview gallery without escaping its panel.

a11y FAIL: --steel-2 as data-bearing text — facet counts on paper 2.39:1, breadcrumb .search-path 2.59:1, both .search-input/.search-pal-field placeholders 2.59:1, .search-k hint 2.59:1, mobile inactive .search-tab-ic 2.59:1 (all below the 3:1 large/UI floor) · Non-text UI borders below 1.4.11 3:1: resting .search-cb checkbox, .search-date pill, .search-k chip all hair-strong-on-white = 2.01:1 (checked/selected states are fine) · dot--agent (#00b6c4) as a standalone status indicator is 2.47:1 on surface / 2.28:1 on paper — below 3:1; relies on adjacent text + low-contrast wash halo · --agent-ink usage is correct: every TEXT use (st-rev, chip--agent, kchip--ai, search-ai-q, fhint--right) passes 6.0:1+; --agent is used only for fills/dots/spines, never text · --ok st-pub published tag 3.87:1 at 9.5px — passes large/UI 3.0 but borderline; weakest status tag · .search-title is <a> with no href (not keyboard-focusable/activatable); .search-row click is on a bare <li>; .search-tab nav links have no href — mouse-only today · Palette advertises arrow-key nav (footer ↑↓) but has no role=listbox/option + aria-activedescendant; only aria-selected on .sel, so nav is not exposed to assistive tech · search-dot separators 2.59:1 (decorative, low stakes)
fixes Remove the only screen-level hard-coded hex: .search-opt input:checked + .search-cb::after uses border:solid #fff — switch to border-color:var(--paper) or add an --on-accent token · Promote data-bearing --steel-2 text to --steel (4.56:1) or darker: facet counts (.search-on), breadcrumb (.search-path), both placeholders, .search-k, mobile inactive .search-tab-ic · Raise resting interactive borders to 3:1 — .search-cb, .search-date, .search-k from hair-strong (2.01) to --steel-2 (3.0+) · Make dot--agent legible alone: always pair with a text/icon label for state, or thicken to a ringed indicator clearing 3:1 · Give .search-title an href + role/tabindex (or make .search-row a focusable <a>); make .search-tab real anchors so keyboard + AT can reach results and nav · Palette a11y: wrap items in role=listbox, each .search-item role=option, drive selection via aria-activedescendant on the input so the advertised arrow-key nav is announced · Reduced-motion: replace the brittle selector allowlist with a blanket *{animation-duration:.01ms!important;transition-duration:.01ms!important} inside the query so base-sheet transitions (.btn, .sp .bar-tip) can't leak through · Nudge st-pub ok-green to clear large-text 3.0 with margin (slightly darker wash or heavier weight at 9.5px)
verdict Strong, system-faithful search + command-palette screen — not the editor, so the ADR 0032 inline-suggestion check does not apply. Agent-as-second-cold-signal discipline is clean (cyan only on agent affordances; every agent TEXT use is --agent-ink and passes), the ink-inverse .sel palette row is exemplary, and mobile work is genuine (16px palette field, 44/56px touch targets, full-screen sheet, crosshair bottom-tab bar) beyond the base 1120px collapse. Token purity has exactly one screen-level leak (a #fff checkmark border). The blocking issues are accessibility: --steel-2 is used for data-bearing text (facet counts, breadcrumb paths, palette placeholder) at ~2.4-2.6:1, resting interactive borders sit at 2.01:1, dot--agent is sub-3:1 as a lone indicator, and result titles/nav are non-focusable <a>s with the palette's arrow-key model not exposed to AT. Fix the steel-2 text contrast, resting borders, focusability, and the single hex, and this ships.

07 · Admin · Members &amp; Teams

open ↗
DS 9mobile 8token 10a11y 11motion ✓

COMPOSITION: Built on the canonical mock's Admin/Members structure (design-01-meridian-zero.html, SCR.E). Reuses shared chrome (.screen/.win/.side/.main/.bar/.body/.page-h), the locked admin atoms (.adm-tabs, .mtbl, .person, .kind/.kind-h/.kind-a, .role-sel, .scope-bar/i.on/i.onu), and shared atoms (.av/.av--u/.av--u2/.av--u3/.av--agent, .chip, .dot/.dot--ok/.dot--agent.live, .btn variants, .kicker, .ord, .hr, .logo, .toolbar2 .seg). No token is hard-coded — every color/size in the screen CSS references a :root custom property, so a theme is a pure :root override. PRINCIPALS AS PEERS: Humans and agents sit in ONE .mtbl. Human = square ultramarine .av--u/u2; agent = NOTCHED cyan .av--agent. Kind tag is .kind-h (ultra) vs .kind-a (cyan). Agent rows carry a faint --agent-wash fill + a 2px inset --agent left-edge so the cyan "second signal" is legible at a glance without re-coloring text. Agent specifics that make first-class status concrete: API key id + creator in the email slot, rate limit (e.g. 600/min) in the scope label, a live "writing…" last-active with a pulsing cyan dot, and a Revoked row (grayed notched avatar, dead scope-bar, steel inset) proving per-row token revocation. Role selects on agent rows are cyan-tinted via .members-role--ag (composes on .role-sel). Scope cell pairs the locked .scope-bar pips (i.onu = ultra for humans, i.on = cyan for agents) with a mono human-readable scope string (read·author·edit·admin) so the capability tiers are explicit. TABS: Primary .adm-tabs is Members / Teams / Invites / Roles per spec (with count pills, new class .members-tc). A secondary .members-sub strip (reusing .toolbar2 .seg) gives All/Humans/Agents + Team/Role/Status filter chips. Below the table, a Teams section with .members-teamgrid cards shows overlapping member avatars (humans + agents) and a humans/agents tally per team. RESPONSIVE / PWA: Shared sheet hides .side and stacks .win at <=1120px — I expose a hamburger (.members-menu) in the bar and add a fixed bottom tab bar (.members-tabbar) for phone primary nav, with env(safe-area-inset-bottom) for notched devices and .body padding-bottom to clear it. At <=880px the two heaviest columns (Teams, Last-active) drop. At <=640px the whole .mtbl reflows: thead is visually hidden, each <tr> becomes a bordered card, and every <td> renders its label from data-label — no horizontal scroll, ≥44px touch rows, role-sel ≥32px. Teams grid goes 4→2→1 col with correct hairline-border resets at each breakpoint. The agent wash + inset edge and the revoked styling are re-applied in the card layout so the peer-principal signal survives on mobile. ACCESSIBILITY: Text uses AA-safe tokens — status greens use --ok, agent text uses --agent-ink, invited uses --warn-ink (not raw --steel-2 for meaningful text). role/search/tablist/aria-current/aria-selected/aria-label added. All motion (the shared .live pulse + hover transitions) is disabled under prefers-reduced-motion. NEW CLASSES (all members- prefixed): members-acts, members-prov, members-tc, members-sub, members-filt, members-chip, members-tblwrap, members-teams, members-team, members-scope, members-scopelbl, members-role--ag, members-role--ro, members-when--ag, members-st (+ --active/--ag/--inv/--rev), members-agentrow, members-revoked, members-av--rev, members-foot, members-legend, members-keyu, members-keya, members-pager, members-teamgrid, members-tcard (+ -h/-b), members-tdot, members-tname, members-tcount, members-tmembers, members-more, members-tmeta, members-menu, members-tabbar, members-tbi. DEVIATIONS: The locked .mtbl is a real <table> (no reflow); rather than fork it I added data-label attributes + a 640px card-reflow layer, which is purely additive (desktop table markup unchanged). Added a status column and a teams-as-pills column beyond the base mock to satisfy the spec's "teams" + "status" requirements; both degrade gracefully on the responsive ladder.

a11y FAIL non-text 3.0: --agent dots fall below 3:1 everywhere they sit. dot--agent = 2.47 on --surface and 2.17 on the --agent-wash agent row (the .dot--agent box-shadow ring is --agent-wash, i.e. the same colour as the row, so it adds no separation). Affects 'Live' status dot and the writing… presence dot. · FAIL non-text 3.0: scope-bar pips. Agent ON pip (--agent) = 2.17 on --agent-wash / 2.47 on --surface; OFF pip (--surface-sunk) = ~1.05-1.20. The on vs off state is essentially invisible to low-vision users; state is conveyed only via title= (not reliably announced) plus a 9px --steel mono label. · FAIL text 4.5: --steel-2 as body/label text. members-tc count pills = 2.28 on their --surface-2 background (2.59 on --surface); bottom-tabbar icons (.members-tbi) = 2.59 on --surface. Both carry information (counts, nav icons) and are well under 4.5. · BORDERLINE text 4.5: small --ok green. 'Active' status text (--ok, 9.5px, uppercase) = 4.41 on --surface and 3.86 on --agent-wash — under the 4.5 normal-text threshold at this size. The dot--ok itself passes UI 3.0 (4.41) on surface but the dot+label combo on agent-wash dips to 3.86. · --agent / --agent-ink usage: text uses (members-st--ag, members-when--ag, kind-a, role--ag) all correctly resolve to --agent-ink (6.0-6.9:1, PASS). The problem is the raw --agent hue used as a GRAPHICAL signal (dots, scope pips, inset left-bar at 2.17 on the wash row) — it never clears 3:1. The agent second-signal is currently carried by sub-3:1 graphics + a faint wash. · Agent row left-bar (inset 2px --agent on --agent-wash) = 2.17:1 — the primary 'this is an agent' visual cue is below non-text 3.0. · Hairline structure: --hair table/cell borders = 1.41 on surface (1.23 on agent-wash); --hair-strong = 2.01. Acceptable as decorative hairlines, but the data-grid row/column separators rely on them and fall under 3:1. · Tabs: role=tablist/tab + aria-selected present, but no aria-controls and no tabpanel association; arrow-key roving not implied. Screen-reader users get selection state but no panel linkage. · Interactive spans not focusable: .role-sel and .members-chip (and the .ws org switcher uses role=button but role-sel/chip do not) have click affordance/carets but are bare <span> with no role=button, tabindex, or key handler — unreachable by keyboard. · Bottom-tabbar items are <a href='#'> with state shown only by colour (--ink vs --steel) + a 2px top bar; no focus-visible styling defined and 8.5px labels are below comfortable legibility. · Status conveyed partly by colour alone: Active/Live/Invited/Revoked differ by dot colour + text — text labels exist (good), but the revoked/invited grey dots (steel-2 2.59, warn-ink passes) lean on hue.
fixes Agent dots/bars: stop relying on raw --agent at small sizes. Either (a) outline the dot — add a 1px --agent-ink ring (border or box-shadow) so the shape clears 3:1 regardless of fill, or (b) recolour the meaningful dots/left-bar to --agent-ink (6:1) and keep --agent only for large fills (avatars). The .dot--agent box-shadow ring must change from --agent-wash to a darker token (e.g. --agent-ink) to actually separate the dot from the agent-wash row. · Scope-bar: encode state non-chromatically. Make ON pips --agent-ink (or --ultra-ink for humans, which already passes at 6.67) and OFF pips a --hair-strong outline rather than a near-invisible --surface-sunk fill; raise pip height from 3px and add a real accessible name (aria-label listing granted tiers) instead of title= only. Mark the per-tier on/off with text or a filled/hollow shape so it survives greyscale. · members-tc count pills: swap text colour from --steel-2 to --steel (4.56 on surface) or --ink-2; since the pill bg is --surface-2, --steel-2 only gives 2.28 — use --ink-2 (≈6:1) to be safe at 9px. · Bottom-tabbar icons (.members-tbi): change inactive colour from --steel-2 (2.59) to --steel (4.56) or --ink-2; keep active --ultra (6.67 passes). · Small --ok 'Active' text: either bump size above the 14px/700 large-text boundary, or darken to a token ~#0a6b3d so it clears 4.5 on both --surface and the --agent-wash neighbours; or pair the colour with the existing dot (already done) and treat the label as large/bold. · Make .role-sel and .members-chip real buttons: role=button, tabindex=0, keydown Enter/Space, and a :focus-visible outline (2px --ultra). They are the primary mutation affordances (role change, filter) and must be keyboard-operable per invariant 4 (parity) and basic AA. · Tabs: add id on each panel and aria-controls on each role=tab; implement roving tabindex + arrow-key handling, or document that JS wires it. Without aria-controls the tablist is incomplete. · Add :focus-visible styling to .members-tabbar a, .nav a, and pager buttons (2px --ultra outline, offset) — currently focus state is undefined for the mobile primary nav. · Hamburger (.members-menu) and the org switcher .ws have aria-labels but no wired target/expanded state; add aria-expanded + aria-controls pointing at the drawer that the ≤1120px breakpoint should reveal (the shared sheet only hides .side — there is no replacement drawer markup, so the hamburger currently opens nothing). · Hairline data-grid: for the principal table, consider promoting the column/row separators that carry structure from --hair (1.41) to --hair-strong (2.01) or add a stronger header underline (already --ink on thead — good); purely-decorative hairlines can stay. · Optional fidelity nit: the legend swatches use ● / ◆ glyphs in --ultra/--agent at tiny size (members-tmeta) — same sub-3:1 issue; pair with the existing text labels (done) so it's informative-redundant, not sole carrier.
verdict Strong, highly faithful Meridian Zero admin screen — arguably the best expression of the 'agents as peer principals' thesis in the system (one unified human+agent ledger, notched cyan avatars, agent-wash row tint, kind chips, revocable scope tiers). Token purity is perfect: every themeable value in the screen-specific CSS and all inline styles resolve to var(--…), zero hard-coded hex. Reduced-motion is correctly handled (the only motion, the shared .live pulse, plus .btn/.members-tcard transitions, are disabled under prefers-reduced-motion). Mobile/PWA is genuinely good: real table→card reflow with data-label headers and 44px touch targets, a fixed bottom tab bar with safe-area inset and reserved body padding, hamburger exposed at the sidebar breakpoint, scroll-tabs and column-dropping mid-width. This is NOT the editor screen, so the ADR 0032 inline-ins/del + gutter-accept check is N/A (no tracked-suggestion markup present). The blocking issues are all accessibility, and they cluster on the agent signal: the --agent hue used as a small graphical cue (status dots, scope pips, the inset agent left-bar) never clears the 3:1 non-text threshold (≈2.2-2.5:1 on the agent-wash row, and the dot's box-shadow ring is the same agent-wash so it adds nothing), the on/off scope pips are near-indistinguishable for low-vision users, --steel-2 text on count pills and tabbar icons fails 4.5, and small --ok 'Active' text sits just under 4.5. None require a token change — fixes are: outline or darken (to --agent-ink) the meaningful agent graphics, encode scope state non-chromatically, move --steel-2 informational text to --steel/--ink-2, and make the styled-span controls (.role-sel/.members-chip) real keyboard-operable buttons with focus-visible. Ship after the agent-signal contrast pass and keyboard-focus wiring.

08 · Admin · Agents management

open ↗
DS 8mobile 8token 5a11y 9motion ✓

SCREEN: Admin · Agents management (SCR.F). Composes the Meridian Zero chrome (.viewport → .screen → .win with .side + .main → .bar/.page-h/.body) and reuses .mtbl, .adm-tabs, .scope-bar, .role-sel, .kind/.kind-a, .statgrid/.stat/.spark, .chg ledger, .kv, .chip, .av--agent/.av--u, .dot, .btn. New work is namespaced agents-*. DATA MODEL (ADR 0016): every agent row carries the principal spine — name + agent-id (mono `agt_…`), owner human (square ultra avatar), auth method (masked API key `ez_sk_…`/`ez_at_…` + inline rotate; @better-auth/api-key vs agent-auth delegated), scopes via .scope-bar (read→author→editor→admin), per-principal rate limit (rateLimitMax/rateLimitTimeWindow) shown as current/max + a usage meter, last-active, status (active/revoked), and a per-row Revoke. One row is REVOKED (migrator) to show the terminal state: hatched row, struck key, dead meter, disabled action — and the detail copy spells out the revocation cascade (key invalidated, sync+MCP sessions closed, future enqueues fail, in-flight jobs keep their snapshot, owner session unaffected) straight from the ADR. DETAIL PANEL: right rail for the selected agent (archivist, row highlighted ultra). Sections — Principal (kind/owner/mode/workspace/created), Credential (masked key box with Copy + Rotate, "secret never displayed after issue"), Rate limit (config rows + large live usage meter + Adjust), Allowed capabilities (cyan chips; denied scopes struck/ghosted), Recent activity (.chg audit ledger incl. a rate.throttle entry), and a prominent red Danger zone Revoke. PEER VISIBILITY: agents are the cyan signal throughout — notched .av--agent avatars, cyan scope bars/meters/spark bars, cyan capability chips, cyan detail header; humans appear as square ultramarine .av--u owner avatars in every row and in the detail Owner field, keeping the human/agent peer pairing legible (each agent is owned by / delegated to a named human). THEMING / TOKEN PURITY: all structural colour references tokens (paper/surface/ink/steel/hair/ultra*/agent*/ok/warn*). The only literal hexes are the destructive-danger reds for the Revoke zone + hover, and the small green/amber status-pill backgrounds copied from the shared sheet's own .st-pub/.st-warn pattern (the palette has no red token and reuses literal pill backgrounds for ok/warn); everything else themeable flows from :root, so a custom theme overriding the globals restyles the screen. Meter fills, status text, scope bars, spark, chips all derive from agent/ultra/ok/warn tokens. ACCESSIBILITY: status/role text uses AA-safe inks (--ok green pill on its own wash, --agent-ink/--ultra-ink for cyan/blue text, never the light --steel-2 for meaningful copy). Meters expose role="meter" + aria-valuenow/min/max + aria-label; rotate/revoke/copy buttons have aria-labels; selected row has aria-selected; burger has aria-expanded. All transitions/animations are wrapped in prefers-reduced-motion: reduce (including the live nav-dot pulse). MOBILE / PWA: shared sheet collapses .side and the win to one column at ≤1120; I also collapse the table↔detail split to one column there and reveal a ☰ burger in the bar (the in-page Agents nav lives in .side which is hidden small). At ≤640 the .mtbl reflows from a wide grid into stacked cards (thead hidden; each cell labelled via ::before content:attr(data-l) — data-l is set on every td in the markup, e.g. "Owner", "Auth", "Rate · req/min"), tabs scroll horizontally, and a fixed bottom tab bar (Members/Spaces/Agents/Audit/Me) appears with ≥56px targets and env(safe-area-inset-bottom) for notched devices; viewport bottom padding (92px) keeps content clear. ≤380 drops stats to one column. No horizontal page scroll at any width (minmax(0,1fr) + min-width:0 on the table wrapper guard overflow). NEW CLASSES: agents-masthead/-mh-l/-mh-div/-mh-sub/-mh-coord, -ws-id, -navdot(+--rev), -crumb-x, -burger, -stats/-v-agent/-statdot(+--warn)/-sp-ag/-sp-tip/-d-rev, -tabs/-tab-add, -split, -tblwrap, -mtbl, -th-rate, -row(+--sel/--rev), -nm-rev/-av-rev, -owner/-owner-av/-owner-nm, -key/-key-val(+--dead)/-key-btn/-key-meta(+--rev), -role(+--agent/--dead)/-scope(+--dead), -rate(+--dead)/-rate-top/-rate-cur/-rate-max/-meter(+--lg)/-meter-fill(+--ag/--hot), -when-live/-when-rev, -status(+--active/--rev)/-status-dot/-status-x, -revoke(+--dead), -tbl-foot/-tbl-legend, -detail/-dh/-dh-av/-dh-id/-dh-nm/-dh-sub/-dh-status, -sec/-sec-h, -kv-owner/-kv-av, -keybox/-keybox-val/-keybox-acts/-keybox-btn(+--rot)/-key-fine, -ratecfg/-ratecfg-row/-ratecfg-k/-ratecfg-v/-rate-live/-rate-lbl/-rate-num/-cfg-edit(+--ag), -caps/-cap(+--off), -ledger/-st-warn/-ledger-all, -danger/-danger-h/-danger-x/-danger-t/-danger-d/-danger-btn, -credit-l/-credit-logo/-credit-mark/-credit-cross/-credit-ring/-credit-word, -tabbar/-tabbar-i/-tabbar-ic/-tabbar-av. DEVIATIONS: (1) Destructive red literals for the Revoke danger zone/hover + the green/amber status-pill background fills (the latter mirror the shared sheet's own .st-pub/.st-rev literal pattern) — recommend adding --danger/--danger-ink/--danger-wash tokens to :root so the Revoke zone becomes fully token-pure. (2) Added an agent-posture .statgrid strip (not in the brief) to make the screen dense and surface rate-limit-hit / revocation telemetry an admin needs at a glance — pure reuse of the dashboard .stat component.

a11y --steel-2 on light = 2.59:1 (FAIL AA 4.5): used for .agents-owner-nm (10.5px mono owner NAMES), .agents-key-meta (8.5px), .agents-key-val--dead, and the mobile per-cell data-l labels. On the selected ultra-wash row it drops to 2.17:1. This is the headline a11y defect. · --ok green (#0d8a4f) on the active-status pill bg #e4f4eb = 3.87:1 (FAIL AA 4.5 for the small 'Active' label). Inherited from the SSOT .st-pub/.st.acc pattern, but still failing. · --steel (#6b7785) on --paper = 4.21:1 (FAIL 4.5): .agents-tbl-legend (9px) and tbl-foot text are small, not large-text exempt. · --agent / --agent-ink usage is CLEAN: agent-ink as text scores 5.8-6.9:1 on agent-wash/surface/ultra-wash (passes AA). The raw --agent (#00b6c4) is used only as fill/rule/dot, never as text-on-light, which is correct. · agents-meter role=meter has aria-valuenow/min/max/label (good), but the scope-bar (4 i bars) and the spark bars convey state purely by color/fill with no text or aria equivalent. · Status is encoded by color+icon (dot--ok / ⊘) AND a text label ('Active'/'Revoked') - good, not color-only. · agents-burger sets aria-expanded but toggles nothing (no disclosed menu / no target id), so the control is a dead end for AT and keyboard users at <=1120. · Rows are clickable (cursor:pointer, aria-selected) but are <tr> with no role=button/tabindex - selection is mouse-only, not keyboard-reachable. · Danger-zone warm reds pass contrast (5.5-7.5:1) so they are not an a11y flag - they are a brand-fidelity flag (see fixes).
fixes Token purity / brand: the danger zone invents a WARM red palette (#b0341f, #8c2a18, #7a3a2e, #fbeeec, #d98c7e) plus revoke-hover #c0392b/#fdecea. Meridian Zero is explicitly cold ('no warmth in any channel', ONE cold accent). Either (a) add cold destructive tokens to the SSOT (--danger cold-crimson + --danger-ink AA + --danger-wash) and reference them, or (b) express destructive intent with ink/steel weight + ultra + the ⊘ mark instead of crimson. Do NOT mint per-screen warm hexes. · a11y AA (highest priority): stop using --steel-2 (2.59:1) for any real text. Promote owner names (.agents-owner-nm), .agents-key-meta, .agents-key-val--dead, and mobile data-l labels to --steel (still 4.2 - bump to --ink-2 #4d5867 = 7.4:1 to clear AA cleanly). · a11y AA: the 'Active' status label fails at 3.87:1 on #e4f4eb. Darken the status-active text to a token that hits 4.5 on that wash (e.g. --ink over the green bg, or a darker green token) - and fix it at the SSOT level since .st-pub shares the value. · a11y AA: .agents-tbl-legend / tbl-foot at --steel on --paper = 4.21:1; either bump to --ink-2 or raise size past the large-text threshold. · Keyboard: make table rows selectable via keyboard - add role=button + tabindex=0 + Enter/Space handler (or wrap the identity cell in a real <button>), since aria-selected is set but only mouse triggers it. · Wire the burger: it sets aria-expanded but opens nothing. Add the disclosed in-page nav (the .side content) as a target with matching id, or remove the control. The <=1120 breakpoint hides .side via the shared sheet, so the burger is currently the only nav path and it is non-functional. · Touch targets: inline ↻ rotate (22px) and the Revoke buttons stay small in mobile stacked cards. Bump to >=44px min-height on <=640 so they meet touch-target guidance. · Mobile search: .agents-search is display:none on phone with no replacement. Surface search via the tab bar or a header icon so the capability is reachable on mobile (parity invariant - every capability on every surface). · reduced-motion: coverage is effectively complete (bare .live reset kills the inherited SSOT pulse; meter width transition reset). For completeness also reset the inherited .btn transition (.btn--ultra/--ghost/--sm color/background fades) in the prefers-reduced-motion block. · Minor token hygiene: #fff appears raw on the danger button text and elsewhere; the SSOT itself uses raw #fff (.btn--ultra), so add a --on-accent / white token at the system level rather than per-screen.
verdict Confident, system-fluent admin screen that reuses the Meridian Zero vocabulary well (masthead band, ultra .on sidebar bar, .mtbl, .adm-tabs, .kv, .chg ledger, notched .av--agent, cyan as a consistent second cold signal, 0px radius, mono kickers, tabular meters). Mobile is genuinely thought-through: real bottom tab bar with safe-area inset, table->stacked-cards with data-l labels, horizontal-scroll tabs. Three things hold it back. (1) Brand: the danger zone breaks the cold-only rule with an invented warm-crimson palette - the single biggest fidelity defect. (2) tokenPurity: ~11 raw hexes; the 5 danger reds are fresh regressions, the green/warn/white tints are inherited SSOT debt but still un-tokenised, so 'all themeable values are tokens' is false. (3) a11y: --steel-2 at 2.59:1 carries owner names and key metadata (fail), the 'Active' pill green is 3.87:1 (fail), and the burger advertises aria-expanded while opening nothing on the very breakpoint where it is the only nav. --agent/--agent-ink usage, in contrast, is clean and AA-safe throughout, and reduced-motion is properly handled (the bare .live reset neutralizes the inherited pulse). Not the editor screen, so the inline-ins/del vs detached-card (ADR 0032) check does not apply. Fix the cold-token destructive palette and the steel-2/status-green contrast and this is a ship-quality admin surface.

09 · Audit log

open ↗
DS 9mobile 8token 7a11y 11motion ✓

STRUCTURE — Composes the canonical app chrome verbatim from design-01 (the mock the CSS was extracted from): `.screen` > `.screen-tab` (coordinate label SCR.F) + `.win` (248px sidebar + 1fr main). Reuses the admin `.side` nav with "Audit log" marked `.on`, `.bar` (breadcrumb + `.search` + export), `.page-h` with the `.z` ultra accent, and the `.credit` strip. No shared tokens/classes redefined — only `audit-`-prefixed additions, plus light reuse of `.seg` (from `.toolbar2`), `.chip`, `.kind`/`kind-h`/`kind-a`, `.av`/`av--u`/`av--agent`, `.btn`, `.cross`, `.dot`. LEDGER — A dense `audit-tbl` (its own table, modeled on `.mtbl` but tuned for ledger density) with the requested columns: # (seq, mono, steel-2), Timestamp UTC (mono, ms precision), Principal (human = square ultra `.av av--u/--u2/--u3`; agent = notched cyan `.av--agent`; plus a third SYSTEM principal `audit-av--sys` + `audit-kind-s` badge for scheduled/system mutations), Action (capability id in a mono ultra-wash pill — `doc.update`, `block.insert`, `member.invite`, `agent.token.revoke`, `doc.delete`, `doc.restore`, `agent.ratelimit.hit`, `workspace.snapshot`), Target (typed: kind kicker + name + mono path/id), Result (`✓ OK` / `⊘ DENIED` / `⤓ SOFT-DEL` / `⚠ THROTTLED` chips with optional mono sub-note), Trace-id (mono). Each `<tbody>` is one day group led by an `audit-day` separator band (weekday · ISO date · per-day count + agent share), giving the "engineering ledger grouped by day" feel. Sticky `thead`. The invariant ("1 mutation = 1 entry", append-only, hash-chained) is reinforced in the screen-tab meta, the page subline, the `audit-invariant` banner (SHA-256 · MERKLE), the sidebar `audit-integ` chain-verified panel (entries / gaps:0 / head seq), and the footer note (append-only · tamper-evident · 7y). PEER PRINCIPALS — Humans and agents appear interleaved throughout as co-equal actors. Agents (archivist, linter-bot, summariser) carry the notched cyan avatar + `kind-a` Agent badge and produce real agent-specific events (`doc.suggest`, a scope-denied `doc.read`, a rate-limit throttle), so agent-as-first-class-principal is legible in the audit trail, not just decoration. The principal filter has explicit Human/Agent/System facets (cyan notched dot vs ultra square dot in the seg). FILTERS / EXPORT — Filter rail (`audit-filters`) covers all requested axes: principal kind (segmented), action (`doc.*`), scope (space/doc), result, and a date range (`2026-05-30 → 2026-05-31`), with a reset. An `audit-meta` readout echoes active filters as chips + a live match count. Export is offered three ways (top bar CSV/JSON, page-header "Export ledger" primary, footer CSV/JSON) since export is called out as a first-class action. THEMING / TOKEN PURITY — Every color references a Meridian Zero token. The only literal hex values are the three already blessed by the shared sheet for the success/OK family (`#e4f4eb`, `#a7d9bf`) and a warn border (`#e6c98a`) derived to sit between `--warn-wash` and `--warn-ink` — matching the sheet's own pattern where `.st-pub`/`.chg .st.acc` hard-code the same OK greens (no OK-edge/OK-wash tokens exist). Everything else (ink ramp, steel, hairlines, ultra, agent, paper/surface ramp, warn-ink/wash) is a `var()`. A new theme = overriding `:root`; this screen inherits it automatically. ACCESSIBILITY — Load-bearing text uses AA-safe tokens: `--ink`/`--ink-1`/`--ink-2` for names/targets/timestamps, `--ultra-ink`/`--agent-ink`/`--ok`/`--warn-ink` (all documented AA-on-light) for accent/status text. `--steel-2` is confined to non-essential decoration (ordinals, target-kind kickers, separators), never sole-carrier copy. Result is conveyed by glyph + word + color (not color alone). Mobile touch targets are ≥44px (segmented filters, selects, footer/export buttons, 56px tab bar). A `prefers-reduced-motion` block defensively disables any inherited transition/animation incl. the shared `.live` pulse. MOBILE / PWA — Three breakpoints past the sheet's built-in 1120px sidebar collapse: ≤1120px tightens filter wrap + table padding; ≤900px hides the seq + trace columns (still present in CSV/JSON export) to protect the principal→action→target→result spine with no horizontal scroll; ≤640px reflows the table into stacked record cards (timestamp line, principal, action pill, typed target, result, with seq pinned top-right and trace inlined with a "trace" label), full-width stacked filter controls, and adds a fixed bottom tab bar (`audit-tabbar`, Home/Docs/Spaces/Audit/You with Audit active) — the off-canvas `.side` is hidden by the shared sheet, so the tab bar restores primary nav on phones. Body gets bottom padding so the fixed bar never occludes the last rows / export buttons. No horizontal scroll at any width. ≤420px trims the screen-tab meta labels so the engineering header never overflows. NEW CLASSES (all `audit-` prefixed): audit-integ(+-h,-row), audit-export, audit-invariant, audit-filters, audit-fgroup(+--date), audit-flbl, audit-segdot(+--u,--a), audit-fsel(+--date), audit-arrow, audit-reset, audit-meta, audit-chips, audit-count, audit-tbl, audit-seq, audit-ts, audit-res, audit-trace, audit-day(+-d,-line,-c), audit-who, audit-av--sys, audit-wn, audit-kk, audit-kind-s, audit-act, audit-tgt, audit-tk, audit-tn, audit-tp, audit-r(+--ok,--deny,--warn), audit-rnote, audit-foot, audit-cursor(+-pos,-nav), audit-foot-r, audit-foot-note, audit-tabbar, audit-tab(+--on,-ic). DEVIATIONS — (1) Introduced a SYSTEM principal (alongside human/agent) for scheduled mutations (snapshots) — audit completeness implies non-user actors must also be attributable; styled neutrally so it never competes with the two cold human/agent signals. (2) Reused `.seg` (defined under `.toolbar2`) for the principal switch rather than inventing a parallel control, to stay on-vocabulary. (3) Mobile column-hiding relies on cell ordering; the action `<td>` is the 4th child (targeted via `:nth-child(4)` for its mobile margin) since it has no extra class in markup.

a11y FAIL 2.59:1 - --steel-2 on --surface is used as readable TEXT in three places: .audit-tbl td.audit-seq (seq# 10.5px), .audit-tk (target-kind label 8.5px), and .audit-fsel .car. Needs 4.5:1. --steel-2 (#97a2b0) is a decorative/border tone, not a text tone; on row-hover (--paper bg) it drops further to 2.39:1. · FAIL 4.41:1 - .audit-integ-h 'CHAIN VERIFIED' uses color:var(--ok) (#0d8a4f) at 9px on --surface. Small green misses 4.5:1. Same --ok-on-white pattern recurs on the gaps '0' value (inline style color:var(--ok), 10.5px). · FAIL 3.87:1 - .audit-r--ok '✓ OK' chip: --ok text on the HARD-CODED green-wash #e4f4eb. Below 4.5:1 for the 9.5px uppercase label. (The deny/warn chips pass: deny 17.0:1, warn 5.1:1.) · FAIL 4.21:1 - several --steel-on-paper text spots miss 4.5:1 by a hair: thead th (9px) sits on --paper; .audit-count and .audit-tp also render --steel on the paper row-hover background. --steel on --surface is 4.56 (just passes), but the moment the row hover paints --paper behind it, body-row --steel text dips under. · BORDERLINE 6.04:1 - .kind-a Agent badge (--agent-ink on --agent-wash) PASSES comfortably; --agent-ink as text is fine. The risk is the raw --agent fill (#00b6c4): .audit-segdot--a and .dot--agent render --agent on --surface at only 2.47:1 - below the 3:1 non-text/graphical-object minimum (WCAG 1.4.11). These dots are the sole carrier of the human/agent distinction in the principal filter, so the meaning fails contrast. · Non-text 1.4.11: --hair borders are 1.41:1 and --hair-strong 2.01:1 on white - both under 3:1. The ledger leans on these hairlines as the primary structural affordance (row separators, table border). Decorative grid is exempt, but the seg-control and fsel borders that define interactive control boundaries should use --hair-strong AND a >=3:1 cue (or pair border with the --ink active state, which they do for .on). · No focus-visible styling anywhere: the .seg buttons, .audit-fsel pseudo-selects, .audit-reset, .audit-tab links, and pagination .btn have no :focus-visible ring. Keyboard users get no visible focus on the entire filter rail and tab bar. · Semantics: .audit-fsel (Action/Scope/Range/Result selectors) are <span> with a ▾ caret - not <button>/<select>, no role, not focusable, no aria-haspopup. .audit-reset is a real <button> (good) but the four dropdowns are inoperable by keyboard/AT. The seg principal switch is <button>s with no aria-pressed on the active .on item. · Color-only status encoding: result chips carry a glyph (✓/⊘/⊕/⚠) AND color (good, dual-encoded), but the principal segdots and the saved-view dots (.dot--agent/.dot--ultra/.dot) distinguish meaning by hue alone - add a shape or text label (notched square already exists for agents via .av--agent clip-path; reuse it on the segdot, which it does - but at 2.47:1 the notch is the only reliable signal). · Sticky thead (position:sticky;top:0) inside a long scrolled ledger is good, but the day-group uses multiple <tbody> elements each with its own sticky th from the single <thead>; verify the header doesn't double-paint over the .audit-day band - the band has no sticky offset so a header can occlude the first row of a group on scroll. · table lacks <caption> / aria-label; screen-reader users get no table name. colspan=7 day-separator rows are fine structurally but announce as empty-ish rows.
fixes Stop using --steel-2 as text. In .audit-tbl td.audit-seq and .audit-tk, switch color to --steel (4.56:1 on white). Better: introduce these as --ink-3 (#79859a -> ~3.6:1, still short) is NOT enough; use --steel and bump the seq weight, or darken to --ink-2 for the seq column which is meaningful data, not chrome. · Fix the green-on-green chip: change .audit-r--ok to color:var(--ink-1) or a darker green token, OR keep --ok text but darken the wash. Cleanest: replace the hard-coded #e4f4eb/#a7d9bf with token-derived values and verify >=4.5:1 - e.g. background:var(--surface); border-color:var(--ok); color:var(--ok) gives --ok-on-white 4.41 (still short) so use a dedicated --ok-ink (~#0a6e3f) token. RAISE THIS: the shared sheet's .st-pub has the identical 3.87:1 defect - fix the token at source, not per-screen. · TOKEN PURITY - remove the three hard-coded hexes in this screen: .audit-r--ok{ border-color:#a7d9bf; background:#e4f4eb } and .audit-r--warn{ border-color:#e6c98a }. There are no --ok-wash/--ok-edge/--warn-edge tokens, so either (a) add --ok-wash, --ok-edge, --warn-edge to :root in the shared sheet and reference them, or (b) derive via color-mix(in srgb, var(--ok) 12%, var(--surface)). The screen claims 'Tokens only' in its header comment but ships 3 literals - the comment is currently false. · Make the four .audit-fsel dropdowns real controls: <button type=button aria-haspopup=listbox aria-expanded=false> (or native <select>). They are the primary filter affordance and are entirely keyboard/AT-inoperable as <span>. · Add :focus-visible{ outline:var(--rule-2) solid var(--ultra); outline-offset:2px } to .seg button, .audit-fsel, .audit-reset, .audit-tab, and .btn within this screen (or globally in the shared sheet - preferable). Currently zero visible focus across the whole filter rail + bottom tab bar. · Raise the agent/ultra dot contrast for 1.4.11: the principal segdots carry meaning at 2.47:1 (agent) - wrap each in a 1px --hair-strong outline or rely on the notched-square shape at a larger size, and add visible text ('Human'/'Agent' already present as button text - so the dot is supplementary; acceptable IF the text stays, but mark the dot decorative with aria-hidden). The standalone saved-view .dot rows have only the dot+label text - text carries meaning, so those pass. · Add aria-pressed to the .seg principal buttons (true on .on, false on others) and aria-current=page to .audit-tab--on / .nav a.on so AT conveys active filter + active route. · Give the table an accessible name: <table aria-label="Audit ledger"> or a visually-hidden <caption>. Add scope=col to the <th>s. · Sticky-header occlusion: give .audit-day a scroll-margin or set thead th z-index above the band (currently th z-index:2; the band has none) and confirm on a real scroll that the first row of each day group isn't covered. Consider top: with the th height as offset. · Mobile (<=640px) is genuinely strong - the table->card reflow, 44px touch targets on seg/fsel/footer btns, and the fixed bottom tab bar with safe spacing (body padding-bottom:84px) are all correct. Two gaps: (1) the fixed .audit-tabbar needs padding-bottom:env(safe-area-inset-bottom) for iOS notch/home-bar; (2) the sticky thead is display:none on phone (good) but verify the absolute-positioned td.audit-seq (top:13px;right:13px) doesn't collide with long .audit-rnote text in the same card. · PWA/touch nit: .audit-fsel--date packs a full datetime range '2026-05-30 00:00 -> 2026-05-31 12:00' into one 11px nowrap span; on a 360px phone even at full-width it will truncate. Allow it to wrap or split into two stacked tappable date fields under <=420px.
verdict Strong, system-faithful audit-ledger screen - arguably the best-reasoned responsive reflow in the set (table->stacked-card with real 44px touch targets and a proper fixed bottom tab bar, not just a collapsed grid). Design fidelity is high: append-only/hash-chained framing, capability-id actions in --ultra chips, dual-encoded result chips (glyph + color), notched-cyan agent avatars, mono/tabular numerals throughout. Reduced-motion is handled defensively even though the screen ships no animation of its own. NOT the editor screen, so ADR 0032 (inline ins/del + gutter accept) does not apply - and pleasingly, doc.suggest correctly appears as ONE ledger row, honouring invariant 3 (1 mutation = 1 entry). Three things hold it back from top marks: (1) token purity - it advertises 'Tokens only' in its header but hard-codes three hexes (#e4f4eb / #a7d9bf / #e6c98a) for the OK/warn chips, inheriting the shared sheet's .st-pub defect; (2) a11y contrast - --steel-2 is used as readable TEXT in the seq# and target-kind columns at 2.59:1, small --ok green misses 4.5:1 in two spots (incl. the green-on-green OK chip at 3.87:1), and the raw --agent dot is 2.47:1 (under the 3:1 non-text floor); (3) the four filter dropdowns are <span>s - no focus, no keyboard, no role - and there is no :focus-visible anywhere. Fix the green/steel-2 contrast at the TOKEN source (it recurs across screens), promote the dropdowns to real controls, and add focus rings; everything else is polish.

10 · Version history + track-changes review (ADR 0032)

open ↗
DS 9mobile 6token 9a11y 9motion ✓

VERIFIED by rendering: built a self-contained preview (locked meridian-zero.css + Google Fonts + this fragment/CSS) and screenshotted in headless Chrome at 1320@2x desktop and 360/390/640 mobile. A DOM probe (documentElement.scrollWidth vs clientWidth) confirmed OVERFLOW=no at 360/390/640 — no document-level horizontal scroll at any mobile width. (Screenshots can show inner `pre` content full-width because --hide-scrollbars suppresses the scroll affordance; the base sheet's `.codeblock pre{overflow:auto}` scrolls it in a real browser, and the page itself does not widen.) LAYOUT (ADR 0032 anatomy): reuses the locked `.win--editor` 3-col frame (248 / 1fr / 268). LEFT = version timeline built on `.side` — a continuous vertical rail with tick `.history-node`s; v14 = filled-ultra CURRENT node, v13 = selected (ringed node + ultra left-bar) carrying its +/− stat and the ultra "Restore this version" button, plus a restore-point and older snapshots. CENTER = `.main` diff of v13→v14: a stat ledger (+102/−18 cyan-vs-steel meter, blocks-touched) above a stack of `.history-block` rows (gutter line-no + ~MOD/+ADD/−DEL badge + per-block author), using the locked `.sugg-ins`/`.sugg-del` marks inline in prose AND inside a real `.codeblock`. RIGHT = `.erail` suggestion queue: a restore-confirm popover (from→to→writes v15, acked checkbox, Confirm/Cancel) then full review cards for one agent + one human pending suggestion (Accept/Reject), a Resolved ledger of compact `.chg` rows (accepted/rejected), and Accept-all/Reject-all. HUMANS + AGENTS AS PEERS: square ultramarine `.av--u/-u2/-u3` for people (Nadia, Tomas, Jun), notched-cyan `.av--agent` for AI (archivist, linter-bot) — carried consistently across timeline authors, diff block-authors, and queue cards. Change rails follow the same code: ultra for human edits/additions, cyan for agent edits/suggestions. HUMAN vs AGENT chips on each snapshot. MOBILE/PWA: at <=1120 the shared sheet hides .side/.erail; I override to re-show them as a single stacked column and add a sticky bottom TAB BAR (`.history-mobnav`: Versions / Diff / Queue·2 with an ultra active-bar and a cyan count badge) — `data-pane` hooks are present for JS pane-switching; CSS-only fallback stacks all three panes with dividers so it's fully usable without script. At <=640 the engineering coordinate band (`.screen-tab .meta`) and the bar crumb collapse, the diff-mode tabs go full-width, gutters narrow, and all controls get min-height:44px. THEMING/TOKENS: every themeable value references a Meridian Zero token; spacing/rules use --rule/--rule-2 and token colors throughout. The only literal hexes are #fff and #02363b as foreground-on-saturated-fill (white on ultra, dark-teal ink on cyan) — these have no token and exactly match the locked stylesheet's own usage (.btn--ultra, .sugg-card .acc, .agent-caret .flag), so a custom theme that overrides the :root tokens reskins everything here. (The "#001" in the member-label text is content, not a color.) ACCESSIBILITY: AA-safe inks chosen deliberately — --agent-ink/--ultra-ink for text on cyan/ultra washes, --steel (not --steel-2) for body-weight meta, dark-on-fill for buttons. ARIA: timeline is role=listbox with role=option (selected marked aria-selected), diff-mode is a tablist, restore popover is role=dialog, decorative avatars are aria-hidden. ALL motion (.history-* transitions, .btn, and the inherited .live pulse/caret) is disabled under prefers-reduced-motion. NEW CLASSES (all `history-` prefixed): -win/-side/-main/-body/-erail (frame tweaks); -tlhead/-timeline/-snap(.is-head/.is-selected/.is-restore)/-rail/-node/-snbody/-snhead/-vtag/-snmeta/-author/-when/-sum/-snstat/-touch/-add/-rem/-restorebtn/-back (timeline); -diffmode/-diffbar/-dstat/-dk/-dv/-dmeter/-mlabel/-mtrack/-madd/-mrem/-diff/-block(.is-ctx/.is-changed/.is-added/.is-removed)/-bgut/-bln/-bbadge(-bb-mod/-bb-add/-bb-rem)/-bbody/-bauthor (diff); -restorecard/-rcline/-restoremain/-confirm/-cfh/-cfbody/-cfack/-cfbox/-cffoot/-qcard(.is-agent/.is-human)/-qhead/-qwho/-qmeta/-qquote/-qwhy/-qact/-acc(/-acc--u)/-rej/-resolved/-rlabel/-st-rej/-bulk (queue/restore); -mobnav/-mi/-mbadge (mobile nav). DEVIATIONS: none from the design language. The restore-confirm popover is shown in its open state (not toggled) so the confirm-flow is visible in a static mock. Source files written for reference: /Users/numman/Repos/editorzero/.design/history-screen.fragment.html and /Users/numman/Repos/editorzero/.design/history-screen.css (the canonical output is in this tool's html/css fields).

a11y AA FAIL (screen-introduced): --steel-2 on light at 9-10px fails 4.5:1 in four places — .history-touch (2.59 on --surface), .history-qmeta (2.59 on --surface), .history-dk (2.39 on --paper diffbar label), .history-bln line-numbers (2.39 on --paper gutter). steel-2 is a hairline/decorative token; it must not carry small text. Promote these to --steel (4.56) or --ink-2. · AA BORDERLINE-FAIL (base-inherited via reused .chg .st.acc 'accepted'): --ok #0d8a4f on --surface = 4.41:1 at 8.5px uppercase — under 4.5:1 for small text. Same green on the .st-pub-style wash is 3.87. The small green status pill is the exact failure the brief flags; darken --ok or enlarge/embolden the pill. · AA marginal: --steel on --paper (gutter context) = 4.21:1 — .history-when timestamps sitting over the paper-toned gutter dip just under 4.5 (they pass at 4.56 on pure --surface). Verify which surface they actually render on; on --paper they fail. · Opacity compounds a marginal color: .history-block.is-removed .history-bbody{opacity:0.86} multiplies the already-low --steel sugg-del/author text down to ~3.29:1 effective on --paper. Don't dim text that's already near the floor — drop the opacity on text, or apply it only to non-text chrome. · --agent / --agent-ink usage is SOUND: the bright --agent #00b6c4 fill is only ever paired with dark ink (#02363b accept button = 5.33, agent-ink on agent-wash = 6.04) — never light text on raw cyan. agent-ink as text on light = 6.36-6.89. No agent contrast failures. · Listbox semantics broken: role='listbox' has role='option' children that are NOT focusable (no tabindex), there's no aria-activedescendant, and only one option has aria-selected — the others need aria-selected='false'. Two options also wrap interactive <button>s (restore), which is invalid inside role='option'. · Tablist incomplete: .history-diffmode buttons have role='tab' with no role='tablist' container and no aria-selected on the active tab — active state is the visual .on class only. Same for the mobile nav: .on is purely visual, buttons lack aria-selected/aria-controls. · No :focus-visible styles defined anywhere in the screen. Custom buttons with border:0 (diff-mode tabs, .history-acc/.history-rej, mobnav) will show only the UA default outline, often invisible against the dark/cyan fills — keyboard focus is effectively lost. Add explicit focus-visible rings (e.g. 2px --ultra outline + offset). · Decorative-only icons are correctly aria-hidden (mobnav glyphs, ↔ arrow, checkbox box) and action buttons have real text labels ('✓ Accept'), so icon labelling is fine — the gap is focus/selection state, not naming.
fixes Fix the four --steel-2 small-text failures: change color:var(--steel-2) -> var(--steel) on .history-touch, .history-qmeta, .history-dk, and .history-bln. steel-2 is the hairline/disabled tier — reserve it for borders and 3px scope ticks, never 9-10px copy. · Make the mobile bottom tab bar actually switch panes. It currently renders all three panes stacked with a tab bar that filters nothing. Cheapest correct fix: give each pane an id (#timeline/#diff/#queue), turn the mobnav buttons into anchor links with scroll-margin-top, so taps scroll-jump. Stronger fix: a state class on .history-win (or :has() on a hidden radio set) that maps the selected tab to display:flex on one pane and display:none on the other two at <=1120px, and add aria-controls + aria-selected to the buttons. · Darken --ok for small status text or stop using it small. The 'accepted' pill (.chg .st.acc) at 8.5px is 4.41:1 — below AA. Either bump --ok toward ~#0a7344 (>=4.5 on white and ~4.1+ on the green wash), or render the pill at >=14px/bold so 3.0:1 large-text applies. This is a base-sheet token, so the fix benefits every screen. · Stop dimming already-marginal text: remove opacity:0.86 from .history-block.is-removed .history-bbody (it pushes --steel to ~3.29:1). If the removed block needs a 'muted' read, convey it with the existing strikethrough + the DEL badge + the --paper background, not an alpha multiplier on the text layer. · Add a visible :focus-visible treatment for all custom controls (diff-mode tabs, accept/reject, restore, mobnav, snapshot options). e.g. `:focus-visible{ outline:var(--rule-2) solid var(--ultra); outline-offset:2px; }` — border:0 buttons currently have no perceivable keyboard focus. · Repair the listbox: make each .history-snap focusable (tabindex), set aria-selected on every option (true on selected, false elsewhere), add aria-activedescendant to the listbox, and move the inline Restore <button>s out of the role='option' subtree (e.g. expose restore as a row action revealed on select, not a nested button inside the option). · Complete the tab semantics: wrap .history-diffmode in role='tablist', add aria-selected='true' to the active tab and 'false' to the rest; mirror aria-selected + aria-controls onto the mobnav buttons so the visual .on state is exposed to AT. · Optional token-purity polish (base-sheet debt, not screen drift): introduce --on-ultra and --on-agent tokens for the #fff / #02363b ink-on-saturated-fill literals so .history-acc / .history-acc--u / .history-cfh stop hard-coding glyph colors. Low priority — the screen only mirrors the base sheet here.
verdict Strong, ADR-0032-correct version-history/diff/review screen. Tracked suggestions render the right way: INLINE .sugg-ins/.sugg-del inside line-numbered diff blocks WITH a gutter accept/reject queue on the right (per-card Accept/Reject + Accept-all) — not a detached-card-only design. Restore is correctly modeled as forward-appending (writes v15, nothing lost), matching the ADR's 'restore appends, never rewinds.' Cyan is used precisely as the tracked-change signal and ultramarine as the human/structural accent; agent avatars notched; change-kind rails stay cold; token purity is near-total (the only literals are ink-on-saturated-fill colors the base sheet itself leaves untokenized). Reduced motion is handled defensively. Two things hold it back from top marks: (1) a cluster of small-text contrast failures — four screen-introduced --steel-2 misuses (2.39-2.59:1) plus the base-inherited small --ok green pill (4.41:1) and an opacity multiplier that drags removed-block --steel to ~3.29:1; and (2) the mobile bottom tab bar is non-functional — it carries data-pane + a visual active state but no CSS/JS maps a selected tab to showing one pane and hiding the others, so all three panes stack and scroll together while implying tab behavior they don't deliver. Both are mechanical fixes; none are structural. Ship after the steel-2/--ok contrast pass, the focus-visible rings, and wiring (or honestly downgrading) the mobile tabs.

11 · Org settings

open ↗
DS 9mobile 7token 10a11y 7motion ✗

Composition: Reuses the canonical chrome (.screen > .screen-tab > .win = .side + .main > .bar + .body) exactly as design-01, with the .panel/.ph engineering-header pattern for every settings section so it reads like the rest of the app. Reused atoms: .kv rows (instance info, integration details), .status-tag (st-pub/st-rev for cert + sync status), .role-sel + .scope-bar (per-key agent scope tiers), .kind/.av (human square / agent notched), .chip variants, .mtbl (API keys + domains tables), .dot--ok/--agent. Left settings nav is the standard .nav with .on ultra left-bar; all nine requested entries present (General, Members, Spaces, Integrations, API & Agents, Domains & TLS, Backup & Export, Theme, Danger Zone). Humans + agents as peers: agents are first-class principals everywhere — provisioner/backup-bot in the live sidebar list, notched cyan .av--agent rows in the API-keys table with cyan-bordered .role-sel + scope bars, "pushed by backup-bot" / "run by backup-bot" cyan attribution in Integrations and Backup, and an agent-tinted toggle (.settings-toggle--agent) for "Allow agent API tokens". The human (Nadia, ultra square) holds the admin/CI key and the footer identity. Region motif: .settings-coord renders LAT/LON as oversized ultra-ink tabular numerals with mono axis labels (52.3676 LAT · 4.9041 LON, AMS1), overlaid with the crosshair brand device (.cross + .cross-ring) as the "origin" mark — tying the engineering-drawing language to the self-hosted instance block alongside version/build/db/uptime/license .kv rows. Theming / token purity: zero hard-coded hex. Every colour, border, padding and size references a Meridian Zero token. The custom switch, inputs, region block, integration cards, theme picker and Danger Zone are all token-driven, so a :root override restyles them for free. The Theme section makes this literal — swatches are painted from var(--paper/--ink/--ultra/--agent) and the hint states a theme is a :root token override, with an "Author theme" affordance. New classes (all settings- prefixed): settings-nav/navord/navdanger, settings-savestate, settings-section, settings-fieldset/field(+--toggle)/subfield/flabel/fname/fhint/fctl, settings-input(+--mono)/inputwrap/iprefix, settings-toggle(+--agent)/tknob, settings-instance/coord/coordval/cnum/cax/csep/coordloc/crosshair/instgrid, settings-keyhead/keytbl/key/keymono/keymeta/revoke(+--neutral)/keyfoot(+-l/-a), settings-integrations/int(+--off)/int-h/int-ic/int-id/int-nm/int-sub/int-body/int-empty, settings-domtbl/dom/domadd/tlsnote, settings-backup/bkstats/bkstat/bkv(+--agent)/bku/bkd/bkactions/bkbtns, settings-themes/theme(+--new)/theme-plus/swatches/themenm/themetag/themehint, settings-danger(+-ph/-tag)/dangerset/dangerrow(+--final)/dangerinfo/dangername(+--del)/dangerbtn/confirm/delconfirm/delinput/deletebtn, plus mobile nav primitives settings-mobilenav (+mn-danger) and settings-tabbar (+tbic/tbl/tb-danger). Accessibility: AA-safe token choices — body/hint copy uses --ink/--ink-1/--ink-2 (not --steel-2) for legibility; status greens use the --ok-on-wash pairing baked into .st-pub; danger affordances use --warn-ink (#8a5a00) on light, which clears AA. Toggles are real role="switch" buttons with aria-checked + aria-label and a visible :focus-visible ring; theme tiles use aria-pressed; the delete button is disabled until the slug is typed (confirm gating). Touch targets step to >=44px on phones (inputs, role-sel, all action buttons, 54px tab-bar items). Mobile / PWA: the shared sheet hides .side at <=1120px, so I layer two nav fallbacks — a horizontal mono section-switcher (.settings-mobilenav) at the tablet breakpoint, then a fixed bottom tab bar (.settings-tabbar, the PWA-style primary nav with safe-area-inset padding) at <=640px. Every grid (fields, instance, integrations, key/backup stats, themes, danger rows) stacks to one column; .body gets bottom padding so content clears the fixed bar; no horizontal scroll (tables sit inside panels; the only scroller is the opt-in switcher with hidden scrollbars). All transitions/animations this screen introduces are disabled under prefers-reduced-motion. Deviations: none structural. New classes only extend the system (square toggle, labelled field rows, region/coord block, integration + theme cards) in the established cold-Swiss idiom — hairline rules, 0px radius, mono labels, tabular numerals, ordinals. The Danger Zone uses --warn-ink as a deliberate functional accent (not a new colour) to stay cold while signalling irreversibility, consistent with the system's functional token set.

a11y --steel-2 (#97a2b0) as readable text fails AA (~2.6:1 on --surface): .settings-keymeta (key creation provenance, 9.5px), .settings-navord, and inline color:var(--steel-2) on '— not set —', 'disabled', domain '—', expires/'in 71d'. This is genuine informational text, not decoration — bump to --steel or --ink-2. · --steel (#6b7785) ~4.0:1 used as NORMAL-size text below 18px: .settings-keyhead (9.5px), .settings-int-sub (9.5px), .settings-tlsnote / .settings-themehint (10px). Fails AA 4.5:1 at those sizes; use --ink-2 for prose-bearing notes. · Small --ok (#0d8a4f) ~4.0:1 as text fails AA at the sizes used: 'postgres · 17.4' and 'converged' (.v.mono ~11px) and .settings-bkd '2.4 GB · verified' (10px). st-pub tag text on its green wash is ~3.6:1. Reserve --ok for the dot/swatch or pair with a darker ink for text. · role-sel is a non-interactive <span>/<div> styled as a dropdown (Default space, all Scope selectors, workspace .car switcher) with no role/tabindex/aria — not keyboard-focusable or operable. Make it a <button> with aria-haspopup, or add role=button + tabindex=0 + key handling. · Standalone glyph affordances are not all aria-hidden: ⌕ search icon, ▾ carets, +/↯/⤓ button icons, ⊹ note bullets. Region crosshair and theme + are correctly aria-hidden — apply the same to the rest so SRs don't read decorative symbols. · --agent / --agent-ink usage is CORRECT: --agent (#00b6c4, ~2.0:1) is only ever fill/border/dot/knob/swatch, never text; all agent TEXT uses --agent-ink (#02646d, ~6.0:1, passes AA). No change needed — credit retained. · scope-bar conveys scope tier by fill alone with only a title= on the wrapper (not reliably exposed). Add an aria-label or visually-hidden text for the tier.
fixes Tame the .live pulse under reduced motion. The screen introduces <span class='dot dot--agent live'> (sidebar agent) and the 'live' dot in the API chip; .live runs the shared @keyframes pulse infinitely and NEITHER the shared sheet nor this screen kills it under prefers-reduced-motion. Add to the screen's reduced-motion block: .live{ animation:none !important; } (and consider .btn{ transition:none !important } since the screen relies on the shared button transitions which it does not currently re-disable). · Make the wide tables responsive at <=640px. .settings-keytbl and .settings-domtbl (.mtbl) keep their full multi-column layout on phones with no overflow guard or card-collapse — the 6-column key table overflows a 360px viewport. Wrap each in an element with overflow-x:auto (and -webkit-overflow-scrolling:touch), or restructure rows to stacked label/value cards inside the <=640 query like the field rows already do. · Promote role-sel and the workspace/default-space switchers to real buttons (<button class='role-sel' aria-haspopup='listbox'>…) so they're tab-focusable and Enter/Space-operable; add :focus-visible matching the existing toggle outline. · Raise small-text contrast: swap color:var(--steel-2) -> var(--steel) (or --ink-2) for .settings-keymeta and the inline 'not set/disabled/—' values; swap color:var(--steel) -> var(--ink-2) for .settings-keyhead, .settings-int-sub, .settings-tlsnote, .settings-themehint; and stop using bare --ok for <12px text (pair with --ink-1 or use the dot only). · aria-hide decorative glyphs: add aria-hidden='true' to the ⌕ search icon, every ▾ .car, the +/↯/⤓ icon spans in buttons, and the ⊹ note bullets, matching the already-correct crosshair and theme-plus. · Add a visually-hidden label to .scope-bar (e.g. <span class='sr-only'>Scope: read, author, edit, admin</span>) so the tier isn't fill-only. · NOT the editor screen — this is SCR.F Admin/Org settings, so the ADR-0032 inline-ins/del + gutter-accept check does not apply; no tracked-suggestion UI is present and none is expected here.
verdict Strong, highly token-pure Meridian Zero settings screen (no hard-coded hex anywhere in the screen's own HTML or CSS; all color/spacing flows through :root vars). Design-system fidelity is excellent: crosshair origin device, mono kickers/ordinals, tabular numerals, 0px radius, square toggles, correct human=square-ultra / agent=notched-cyan dual encoding, and a disciplined agent signal (cyan only as fill/edge, --agent-ink for all agent text — AA-safe). Mobile work is above average: sidebar collapse plus an added horizontal section switcher AND a fixed bottom tab bar with safe-area inset and generous touch targets. Two real defects keep it from top marks: (1) prefers-reduced-motion is only half-handled — its own transitions are killed but the .live infinite pulse it introduces is not, so reducedMotionHandled=false; and (2) the wide key/domain tables have no <=640 overflow or card-collapse and will blow out on phones. Plus AA contrast failures on small --steel-2/--steel/--ok text and non-focusable role-sel pseudo-dropdowns. None are structural — all are mechanical fixes. Not the editor screen, so the ADR-0032 tracked-suggestion rule is N/A.

12 · Login / Onboarding

open ↗
DS 9mobile 7token 8a11y 9motion ✓

THREE STATES, one engineering set. Rendered as a full-viewport paper field (faint 32px grid via grid-line token) with a sticky top coordinate strip (brand + live instance readout: node nw-01 · v0.1.0 · ok-dot) and a footer credit strip. The three states sit side-by-side in a bordered .login-set, each a .login-col with its own coordinate header (ord + id + status chip): (1) First-run wizard — progress meter + 4-step rail (done/on/todo), org+admin+instance fields, the .ez.internal affix; (2) Returning sign-in — email+password with SHOW affix, primary submit, OR divider, two SSO buttons (SAML + OIDC); (3) Invite accept — ultramarine .login-invite banner ("Northwind Eng … as Editor"), a 3-cell grant grid (Role/Spaces/Expires), invited-by line, locked email + name + set-password, and a NEW-PEERS strip. The crosshair brand device repeats: each card opens with a framed .markwrap (cross + cross-ring) carrying ultramarine corner registration ticks. VALIDATION (dev-browser/Playwright): captured full-page at 1366, 1280, 900, 390. Zero horizontal overflow at every width. At <=1080 the set collapses to one column (verified gridTemplateColumns→1fr); at <=640 .login-row2 and the grant grid stack. Confirmed --ultra and --paper resolve at runtime. THEMING / TOKEN PURITY: graded clean — a scan of the screen CSS found NO hardcoded hex/rgb; every color is a var(--token). Swapping :root re-themes this screen wholesale (the grid field, mark ticks, step rail, invite wash, agent notes all follow their tokens). Spacing/sizing use literal px tuned to the 8px system but reference --rule/--radius for structure. Focus rings use --ultra; the inset box-shadow uses var(--rule) for width. MOBILE / PWA: off-canvas not needed — there is no app nav at the entry screen; instead the stage stacks into a single scrollable column with the sticky brand strip retained for orientation. Touch targets meet/exceed 44px on phones (measured: submit 44, back 44, input 46, SSO 46, reveal-affix 46×52). Inputs go to 16px font at <=640 to suppress iOS focus-zoom. Uses 100dvh so the field fills mobile viewports under dynamic browser chrome. ACCESSIBILITY: body/label text uses --steel (~4.7:1 on white) or darker (--ink-1/--ink-2); --steel-2 is reserved for decorative mono micro-labels/coordinates only. Status/role text uses the AA-safe --ultra-ink / --agent-ink / --ok ink tokens. All inputs have <label for>; affix toggles are real <button> with aria-label; the readonly invite email has aria-readonly; decorative dots/avatars are aria-hidden; hint text wired via aria-describedby. Every animation (input/ssobtn/back/submit transitions, the .live pulse, blink) is disabled under prefers-reduced-motion. HUMANS + AGENTS AS PEERS: present in all three states. Human = square ultramarine .av--u (NA monogram); agent = notched cyan .av--agent (AI/AR). Each state carries the required agent footnote in the cyan .login-agentnote band ("Agents authenticate via token/key — Authorization: Bearer ez_… — not this form"), the invite's NEW-PEERS strip lists a human admin and the 'archivist' agent side-by-side, and the global footer repeats the agent-auth statement with a cyan dot. NEW CLASSES (all login- prefixed): login-field, login-topstrip, login-inst, login-stage(-h), login-set, login-col, login-ch, login-card, login-brand (+ markwrap), login-form, login-fl, login-lbl, login-input, login-affix, login-hint, login-row2, login-steps, login-step, login-prog, login-or, login-sso, login-ssobtn, login-actions, login-submit, login-nav, login-foot-line, login-peers, login-peer, login-invite, login-grant, login-by, login-agentnote, login-footer, login-toggle (toggle styles included for the wizard's instance-settings step; markup for that step is summarized into the rail here to keep all three states visible at once). Reused system atoms: .logo/.cross/.cross-ring, .kicker(--ultra), .ord, .chip(--ultra/--agent/--ghost), .dot(--ok/--agent/.live), .av(--u/--agent), .btn(--primary/--ultra), .hr, .mono. No app-chrome classes (.win/.side/.bar) are used since this is the pre-auth entry surface. DEVIATIONS: the spec's "stepped wizard" is shown mid-flow (step 2/4) rather than as a multi-screen sequence, so the full wizard mechanics (progress meter + step rail + per-step body) read at a glance alongside the other two states. The instance-settings toggle component is styled (login-toggle) and reduced-motion-guarded but its body is represented by step 3 in the rail rather than expanded, to keep all three states co-visible in one frame.

a11y FAIL AA (text): --steel-2 is 2.27-2.59:1 on every background it's used on and carries real text/data here — input ::placeholder (2.59, holds example values like 'you@northwind.eng'/'Theo Mensah'), .opt labels ('MIN 12 CHARS'/'MIN 12'), .login-ssobtn .ar arrows, peers count '8 HUMANS · 4 AGENTS', and the inline style=color:var(--steel-2) separator dot. All <18px → strict 4.5 floor. · FAIL AA (text): --steel mono at small sizes — 4.21:1 on --paper, 4.0:1 on --agent-wash, 4.56:1 on --surface. Affects .login-foot-line, .login-hint, .login-lbl, .kicker, .sub, topstrip .coord, login-prog .lab, login-step .ds (all 9-11px on paper → fail). · PASS (non-text): --ok green is 4.07:1 on paper / 4.41:1 on surface — below 4.5 for text, but only used as the 6px aria-hidden .dot--ok, which is decorative and clears the 3.0 non-text bar. Do NOT promote --ok to a text role on this palette. · PASS: --agent/--agent-ink usage is correct — agent-ink on agent-wash = 6.04:1 (agentnote body, chip--agent, code), notched av--agent monogram uses #03363b on --agent = 5.32:1. Agent-as-second-cold-signal is well-formed and AA-clean. · Non-text borders below SC 1.4.11 (3.0): hair-strong 2.01:1, agent-edge 1.46:1, ultra-edge 1.69:1 on white. Consistent with the system's hairline convention and input focus uses --ultra (6.67:1), but the agentnote/invite/callout wash panels rely entirely on a sub-1.5 edge — only the wash fill distinguishes them, marginal for low-vision. · SHOW reveal-password buttons: text label 'SHOW' is good, but aria-label is static 'Reveal password' — must toggle to 'Hide password' and carry aria-pressed when state flips, else SR users get no state feedback. · No skip-link and no landmark <nav>; topstrip and footer are plain <header>/<footer> with link soup. .login-set is a 3-column grid of independent forms with no visible focus-order cue — keyboard users tab through 3 stacked auth forms with no 'which state am I in' signal beyond the .login-ch ordinal. · Decorative glyphs '⊹', '◑', '◑', '✓', '←', '→' sit inside visible labels/buttons without aria-hidden — some (✓ in done step, → in submit) get announced as stray characters. Mark purely-ornamental ones aria-hidden. · Required-field marking relies on '*' that is aria-hidden plus no programmatic required attr — add required (or aria-required) to the starred inputs so SR users learn the constraint.
fixes Retire --steel-2 as a TEXT token. Re-map every text use to --steel (still fails small — see next) or better --ink-3 (#79859a). For placeholders specifically, set .login-input::placeholder to --ink-3 (3.6:1, still short) — the real fix is a dedicated --placeholder/--steel-text token at >=4.5 on --surface; e.g. darken to ~#727d8c. Keep --steel-2 only for hairline-tier non-text (edges, the .ar arrow IF made aria-hidden decorative). · Darken the small-mono floor: --steel at 9-11px is 4.21 on paper. Either (a) introduce --steel-text >=4.5:1 on --paper (#f4f6f8) for .login-lbl/.login-hint/.login-foot-line/.kicker/.sub/.coord/.login-prog .lab/.login-step .ds, or (b) bump those specific sizes to >=18px-equivalent (not viable for mono labels). Recommend (a) — one new token, swap the color refs. · Make password reveal stateful: toggle aria-label between 'Reveal password'/'Hide password', add aria-pressed, and swap button text SHOW/HIDE in the same handler (currently text and label are both static). · Add a skip-to-content link before .login-topstrip, wrap the footer link list and (if kept) the SSO group context in semantic landmarks, and give .login-stage role/labelledby tied to the h1. The brief's 'add a mobile nav' is largely N/A for an unauthenticated login screen (no app surfaces yet) — instead add a skip-link + ensure the sticky topstrip doesn't trap focus; that is the equivalent mobile/AT affordance here. State this N/A explicitly so it isn't scored as a miss. · aria-hidden the ornamental glyphs (⊹ kicker tick, ✓ done-step check is meaningful — give it aria-label='complete' instead; ←/→ in buttons → aria-hidden; SSO ◑/cross glyphs → aria-hidden). The cross marks with inline style=color:var(--ultra) are decorative → aria-hidden. · Add required (or aria-required='true') to every input whose label shows the '*' (org, slug, admin name/email/password, invite display-name/password). Pair the visible '*' with an sr-only 'required'. · Token-purity cleanup (maintainability, not contrast): all 14 inline style= color/size declarations reference var() correctly — no hard-coded hex — but inline styling bypasses the class system and invites drift. Lift them into login- classes (e.g. .login-foot-line a already exists; the 'Forgot?' link, the topstrip cross sizing, the OIDC .gl override, peers count color should become modifier classes). · Delete dead CSS: the @media(max-width:640px) block styles .login-toggle .tg / .tg i / .tg.on i but there is no .login-toggle in the HTML — orphan rules, remove. · Editor-screen check: N/A — this is the Login/Onboarding screen, no tracked-suggestion surface present, so ADR 0032 inline ins/del + gutter-accept rule does not apply here.
verdict Strong, highly system-faithful screen — ships after the contrast fixes. Meridian Zero fidelity is excellent: 0px structural radius, hairline rules, mono labels/kickers, the crosshair origin mark reused correctly, human=square-ultra vs agent=notched-cyan avatars, and the repeated 'agents authenticate via token, not this form' trust statement is exactly the AI-native peer framing the system wants. The agent (cyan) signal is AA-clean throughout (agent-ink on agent-wash 6.04:1). Token purity is high — zero hard-coded hex; the only impurity is ~14 inline var()-based styles that should be classed. reduced-motion is genuinely handled (transitions off + animation:none on all descendants, which correctly neutralizes the shared .live pulse on the peer status dot). BLOCKERS are two contrast failures, both inherited from how the palette's lightest greys are used as TEXT: (1) --steel-2 at 2.3-2.6:1 carries real content here — most importantly input placeholders holding example values — and (2) --steel small mono at 4.0-4.2:1 on paper/agent-wash falls just under 4.5 for the 9-11px labels that blanket this screen. Neither is a structural redesign — introduce one --steel-text token >=4.5:1 on --paper and re-map placeholder + small-label color refs. Then tighten the reveal-button state semantics, add required attrs + a skip-link, aria-hidden the ornamental glyphs, and delete the orphan .login-toggle rules. mobileUX is good (single-column stack at 1080, 16px inputs to defeat iOS zoom, 44-46px targets); the brief's 'add a mobile nav' is correctly N/A for an unauthenticated entry screen — a skip-link is the right equivalent. Not the editor screen, so the ADR 0032 inline-suggestion rule does not apply.

13 · Mobile + PWA Showcase

open ↗
DS 9mobile 9token 8a11y 8motion ✗

SCREEN = a gallery of 7 phone frames (a-g). Each frame is a token-built device bezel (.mobile-pwa-device, aspect-ratio 375/812, graphite --ink body, offset --surface-sunk shadow) wrapping a real .mobile-pwa-screen flex column: faux OS status bar -> app/read bar -> scrollable body -> docked bottom chrome. The frames are self-contained "mini-viewports", so every inner layout is already genuinely mobile. FRAMES: (a) installed home — app bar, 2-up .stat grid, Continue panel + activity .feed, and a 5-item BOTTOM TAB BAR (Home/Docs/Search/Activity/Account) with an ultra active indicator + cyan agent-count badge; (b) documents list — stacked .mobile-pwa-doc rows reusing .status-tag + .editors-stack, a 4-up segmented filter, and an ultra FAB; (c) reading view — read bar, big .z headline, mono meta with human+agent avatars, callout/code/list reusing reader tokens; (d) EDITOR — top presence (.pchip u/ag), live .caret-u + agent-typing + .agent-caret flag, inline .sugg-ins/.sugg-del, a tap-to-review BOTTOM SHEET (grab handle, agent header, add/rm diff, rationale, 48px Accept[cyan]/Reject), and a docked touch FORMAT BAR with an "Ask" agent action; (e) OFFLINE — warn-wash banner "Offline · 3 edits saved locally", a per-edit sync queue (human=ultra rail, agent=cyan rail), then the reconnected "Synced · merged via CRDT" --ok bar; (f) INSTALL sheet over a dimmed app — app icon = crosshair zero mark, feature list, "Add to Home Screen"; (g) SPLASH — graphite canvas, visible grid field, large ultra crosshair zero mark, wordmark with cyan "zero", indeterminate ultra loader. MOBILE/PWA APPROACH: The page is the showcase; real responsiveness is the gallery reflow. Desktop = auto-fill grid of ~375px frames; <=900px shrinks the cell; <=640px collapses to one centered phone per row (max-width 360px so the bezel stays phone-shaped, never edge-to-edge ugly), header/credit stack, no horizontal scroll. Inside frames, primary nav is the bottom tab bar (a) and docked format bar / bottom sheets (d) — the PWA pattern. Touch targets: tab items min-height 52px, format-bar buttons 48x>=44px, sheet Accept/Reject 48px, FAB 52px, icon buttons 38px boxes inside generous bars. Status bar shows an installed standalone shell (no browser chrome); offline frame flips the status bar to graphite with a cyan offline glyph. THEMING/TOKEN PURITY: No hardcoded hex except where the SSOT itself defines literal avatar/status values — I reuse the system's own .st-pub greens (#e4f4eb/#a7d9bf) verbatim for the synced bar so it matches the published status tag exactly, and #fff only inside ultra/agent fills mirroring .btn--ultra/.av conventions. Everything else (graphite bezel, grid lines, washes, rails, accents) is a var() token; spacing/rules also use --u/--rule/--rule-2/--radius/--radius-chip. A custom theme = overriding :root, and these frames recolor automatically. Splash grid is drawn from --ink-1 line gradients; all glyphs (tab icons, crosshair marks, search/doc icons) are CSS borders — zero raster assets. ACCESSIBILITY: Text uses AA-safe tokens — agent text via --agent-ink, ultra via --ultra-ink, offline via --warn-ink on --warn-wash, synced via --ok on its light green; --steel-2 reserved for >=10px mono captions/decorative meta only. Sheet has role="dialog" + aria-label, status regions role="status", tab bar nav[aria-label], aria-current on active tab, decorative bezel/notch/glyphs aria-hidden, icon buttons aria-label'd. Only two animations (status .live pulse from the base sheet, splash loader) and both are wrapped in prefers-reduced-motion: reduce. Humans (square --ultra .av--u) and agents (notched --agent .av--agent) appear as peers in EVERY content frame — co-editor stacks (a,b), bylines (c), presence + live caret/suggestion (d), and dual-colored sync rails (e). NEW CLASSES: all prefixed mobile-pwa- (page/head/intro/title/lede/legend; gallery/frame/cap; device/notch/screen; status[+--off]; appbar[+--title]/iconbtn/titleblock/greet-h/count; scroll variants; stat2/panel/row/livelbl; tabbar/tab/tab-ic/tab-l/badge + ic-docs/ic-search/ic-act drawn glyphs; seg/doc/doc-* /fab; readbar/read-h1/read-h2/read-p/readmeta/lede2/callout/read-ul; ed-h1/ed-p/agentline/presence-m/save; sheet/grab/sheet-* ; fmtbar/fb-ai; offbanner/off* /q/q-* /synced* ; install/install-* /dim* ; splash/splash-*). DEVIATIONS: reused the existing .seg, .stat, .panel/.feed, .callout, .status-tag, .editors-stack, .pchip, .caret-u, .agent-typing, .agent-caret, .sugg-ins/.sugg-del, .chip--ghost, .btn--ultra/--ghost, .logo/.cross/.cross-ring, .dot atoms rather than re-declaring them — the bottom sheet mirrors the desktop .sugg-card review pattern repositioned as a sheet, and the bottom tab bar / format bar are the mobile equivalents of the desktop .nav / .fmtbar.

a11y CRITICAL --steel-2 on --paper = 2.39:1 (on --surface 2.59:1): fails AA normal AND large/UI. Pervasive in .mobile-pwa-count, .mobile-pwa-doc-mt, .mobile-pwa-row-pth, .mobile-pwa-q-mt, inactive .mobile-pwa-tab-ic. --steel-2 is a hairline/decorative tone, not a text tone — it is being used as readable metadata text. · --ok on synced green #e4f4eb = 3.87:1: .mobile-pwa-synced-s (9.5px mono) fails AA normal; .mobile-pwa-synced-t (13px bold) is borderline and not reliably large-text. Same --ok-on-#e4f4eb sits in .status-tag.st-pub ('Live'/'Published') at 9.5px — fails AA normal there too. · --agent-ink on solid --agent = 2.79:1: .mobile-pwa-badge (activity-tab count) and the SSOT .acc accept button (.mobile-pwa-sheet-btn.acc). The SSOT itself dodges this by using #03363b/#02363b ink on solid agent for .av--agent and .flag — the badge/acc should adopt the same darker ink, not --agent-ink. · --ultra on --ink = 2.90:1: splash crosshair mark + .mobile-pwa-splash-load bar on dark splash. Decorative (aria-hidden) so UI-contrast is advisory, but adjacent wordmark .z uses --agent (7.81:1, fine). · --steel on --paper = 4.21:1: just under AA normal for --steel body text on the --paper canvas. --steel passes on --surface (4.56) but not on --paper — check steel-on-paper contexts. · Touch-target shortfall: .mobile-pwa-iconbtn is 38x38px (min-width 38) — below the 44px AA / footer-stated '>=44px touch' contract. Comment claims '44px via padding box' but no padding expands it. Tabs 52px, FAB 52px, sheet btns 48px, fmtbar fb 48px all pass; only the icon buttons miss. · Interactive rows/tabs are bare <a> with no href: .mobile-pwa-row, .mobile-pwa-doc, .mobile-pwa-tab are not keyboard-focusable/operable. aria-current on the active tab is correct, but these need <button>/href or role+tabindex+key handling. (The .seg and sheet/format controls ARE real <button> — good.) · Human/agent distinction is shape+color only: legend and avatars rely on square-ultra vs notched-cyan; add sr-only 'Human'/'Agent' text. In the sync queue the .mobile-pwa-q-rail .u vs .ag is a hue-only 3px rail (the .mobile-pwa-q-mt 'you'/'agent' mono text does carry it — keep that).
fixes Stop using --steel-2 as text. Promote metadata text (.mobile-pwa-count, .mobile-pwa-doc-mt, .mobile-pwa-row-pth, .mobile-pwa-q-mt, .mobile-pwa-doc-side meta) to --steel on --surface (4.56:1) or --ink-2 (#4d5867, ~7:1) where it sits on --paper. Reserve --steel-2 for rules/disabled glyphs. · Fix inactive tab icons: .mobile-pwa-tab-ic color --steel-2 (2.59:1) -> --steel (4.56:1) for UI-component contrast; active stays --ultra. · Synced/published green: --ok on #e4f4eb is 3.87:1. Add --ok-ink (~#0a6b3e, >=4.5 on #e4f4eb) plus --ok-wash/--ok-edge to the SSOT (only --ok exists today, which is why .st-pub and .syncedbar hard-code #a7d9bf/#e4f4eb), and use --ok-ink for .mobile-pwa-synced-t/-s and the .st-pub label; or bump those captions to >=14px bold. · Badge + accept on solid cyan: set .mobile-pwa-badge and .mobile-pwa-sheet-btn.acc text to the SSOT solid-agent ink #03363b (tokenize as --agent-ink-on-solid) instead of --agent-ink, matching .av--agent / .agent-caret .flag. Raises 2.79:1 to ~8:1. · Reduced-motion: extend the existing @media (prefers-reduced-motion: reduce) block (currently only .mobile-pwa-splash-load i) to also set animation:none on .live — the home 'Continue' .dot--agent.live still pulses for reduced-motion users — and neutralize the SSOT .caret-u blink / .agent-caret presence motion within the screen's scope. · Icon buttons to >=44px: bump .mobile-pwa-iconbtn to 44x44 (or keep a 38px visual box with a ::before hit-area / real padding reaching 44px). The footer asserts '>=44px touch' — 38px breaks the screen's own contract. · Make tappable rows real controls: convert .mobile-pwa-row, .mobile-pwa-doc, .mobile-pwa-tab to <button>/<a href> or add role+tabindex=0+key handling; keep aria-current on the active tab. · Tokenize the 3 remaining literals at SSOT level, not per-screen: #fff -> an --on-accent token (white-on-ultra/agent recurs), and route .mobile-pwa-syncedbar through the proposed --ok-wash/--ok-edge so #a7d9bf/#e4f4eb leave feature CSS. Move the inline style="color:var(--agent-ink)" on the '42' stat into a .stat--agent modifier for parity with .stat--ultra. · Add a non-color human/agent signal: give the legend rows sr-only 'Human principal'/'Agent principal' text and ensure the notched-vs-square avatar shape (not just hue) carries the distinction anywhere it's the sole signal.
verdict Strong, highly disciplined Meridian Zero mobile/PWA gallery — 7 phone frames (installed home + bottom tab bar, docs list w/ FAB, reading, editor, offline->sync, install sheet, splash) that genuinely EXTEND the system to a phone rather than shrink the desktop chrome. DS fidelity is high: crosshair mark, mono kickers, .ord ordinals, square-human/notched-agent avatars, 0px structural radius, hairline rules, tabular numerals, and the offline-as-warn / synced-as-ok / agent-as-cyan semantics all read correctly; the bezel/notch/status-bar conceit is consistent across every frame. Mobile UX is the standout: a real bottom tab bar (not a hamburger afterthought) with active top-marker + aria-current, 52px tabs/FAB, 48px sheet+format buttons, a tap-to-review bottom sheet, an offline banner with a local-edit queue, and a CRDT-merge synced state; responsive rules correctly drop to one phone per row and stack the header <=640px. EDITOR / ADR 0032 CHECK PASSES: screen D shows TRUE inline tracked changes (sugg-del 'just tools' + sugg-ins 'first-class peer principals' inside the live paragraph) plus a live agent caret AND a review surface — the bottom sheet is the correct mobile analog of the gutter .sugg-card (an addition, not a replacement), so this is the right pattern, not the wrong detached-card-only failure mode. Token purity is near-total: only #fff and the published-green pair #a7d9bf/#e4f4eb are hard-coded, and all three are values the SSOT itself hard-codes because no --on-accent / --ok-wash / --ok-edge tokens exist — no NEW off-palette color is introduced; the gap is in the token set, not the screen. The real blockers are accessibility: (1) --steel-2 used as readable metadata text throughout at 2.39-2.59:1, failing AA outright; (2) --ok on synced/published green at 3.87:1 fails AA-normal for the small mono captions; (3) --agent-ink on solid --agent (badge + accept) at 2.79:1 when the SSOT's own #03363b solid-ink fix was right there; (4) reduced-motion covers only the splash loader, leaving the .live home-panel pulse animating; (5) 38px icon buttons break the page's own '>=44px touch' contract; (6) tap targets are bare <a> with no href/role so they aren't keyboard-operable. Fix the steel-2-as-text habit, add --ok-* and a solid-agent-ink token to the SSOT, widen reduced-motion to .live, and make rows/tabs real controls — then this is a ship-quality, parity-honest mobile surface.

14 · Theming & custom themes

open ↗
DS 9mobile 8token 7a11y 8motion ✓

SCREEN: Settings / Appearance / Themes, rendered as the full app frame edge-to-edge (.viewport > .screen > .win 248+1fr) so it reads as a real product surface. Reuses shared chrome verbatim: .side/.nav (Settings + Appearance groups, "Themes" active), .bar/.crumb/.search, .page-h with .z ultra accent, .panel/.ph, .callout, .codeblock, .credit, and .chip/.dot/.av/.btn atoms. THESIS SHOWN, NOT TOLD — "a theme = a :root override, no rebuild." Demonstrated structurally: both the 4 curated thumbnails AND the live-preview pane are the SAME markup, each re-skinned purely by overriding token custom properties on a wrapper class (.theming-tk-graphite / -warm / -hicon / -afterdark). Children read --ink/--paper/--ultra/--agent etc., so they recolour automatically — the exact product mechanism. A thesis callout + the export panel also state it and show a paste-able :root[data-theme] block. (1) CURATED CARDS: Meridian Zero (DEFAULT, active — ultra outline + ACTIVE tag), Graphite Dark, Warm Paper, High Contrast (WCAG AAA chip). Each = a mini-app thumbnail (sidebar+main+human/agent rows) under its own token set, plus a real 5-swatch palette strip and an Apply action. (2) CREATE-THEME EDITOR: left panel = editable token rows grouped into the 6 requested buckets (Neutrals / Accent / Agent / Functional / Type / Metrics); each row = swatch + --token + semantic role + value field. The actively-edited --ultra row gets an ultra outline + a human .caret-u in its hex field (live editing). Type rows use font-name swatches; Metric rows use size/bar swatches incl. --radius 0. Right column = live preview pane (a full sample doc screen scoped to .theming-tk-afterdark "Northwind After-Dark"), a contrast-guard band (auto-nudge to keep AA), Save / Apply now / Export CSS / Revert actions, and the export+paste panel. (3) THEME = CSS CUSTOM PROPS: codeblock shows the exported :root[data-theme="after-dark"] override; footer note "paste any :root{} block… same tokens drive Web UI, PDF, embeds" + Import-from-CSS. HUMANS + AGENTS AS PEERS appear in every preview surface: sidebar live agent (notched cyan dot), presence chips for human (square ultra av) + agent (notched cyan av, "typing…"), and a tracked agent suggestion (.ins/.del cyan) in the live preview. The Agent token group is first-class beside Accent. TOKEN PURITY: no hard-coded hex in screen CSS EXCEPT inside the alternate-theme override blocks (.theming-tk-*) and the curated swatch strips — unavoidable and correct, since a theme's literal job is to DEFINE token values. All structural/default styling references vars only. Two small #fff uses are on saturated fills (ultra btn text, ok guard glyph) matching the shared sheet's own .btn--ultra/.av pattern. Contrast: text uses AA-safe tokens (ultra-ink, agent-ink, ink-1, ok); steel-2 only on decorative marks; the guard band reinforces AA as a product constraint. MOBILE / PWA: shared sheet hides .side at <=1120, so I add a fixed bottom TAB BAR (>=56px rows, env(safe-area-inset-bottom), ultra active marker) for primary nav. At <=1120 cards go 2-up and the editor stacks with the PREVIEW moved above the token list (order:-1) so the result stays visible while scrolling tokens. <=760 the preview sample app stacks (sidebar -> horizontal strip). <=640 single-column cards, token rows drop the role column to swatch+name+value at 44px min height, actions become full-width stacked buttons, the screen goes edge-to-edge (side borders dropped), duplicate header Import button hidden. No horizontal scroll at any width. NEW CLASSES: all prefixed theming- (vp, win, applied/-v, thesis, sech/-ed, cards, card/-ft/-meta/-nm/-sw, thumb, mini*/-mark/-side/-main/-bar/-h/-row/-av, tk-meridian/-graphite/-warm/-hicon/-afterdark, defchip/a11ychip/active-tag/applybtn/importbtn, editor, tokens/-tcount/-tokscroll, grp/-h/--last, kag, trow/--on/--font/--metric, sw/--edit/--font/--mono/--metric/--radius, tname/trole/hex/--edit, previewcol, preview, livetag, stage, samp*/-side/-logo/-mark/-nav/-navh/-dot/-main/-bar/-crumb/-btn/-body/-kick/-h1/-p/-presence/-pchip/-av/-typing/-sugg/-ins/-del/-chips/-tag, guard/-ic/-tx/-tag, actions/-l/-r, code/-copy, export/-ft/-note, tabbar, tab/-ic). Reused shared atoms recontextualised: .caret-u (human caret reused in the edited hex field), .codeblock token spans (.cm/.kw/.st), .dot--agent.live. ANIMATION: all motion (shared .live pulse, .caret-u blink, agent dot) disabled under @media (prefers-reduced-motion: reduce); card/row transitions also killed. DEVIATIONS: kept the .screen/.screen-tab wrapper (consistent with the canonical mock's per-screen framing + engineering-drawing coordinate label) rather than a bare .win; on <=640 its right-hand meta hides and side borders drop so it fills the phone edge-to-edge. Brand crosshair marks in the mini/sample previews are drawn with token-coloured gradients (not the shared .cross pseudo-elements) so they survive being placed inside scoped-token wrappers.

a11y PASS (light chrome body/labels): --steel #6b7785 on --surface = 4.56:1 (AA normal); on --paper = 4.21:1 (clears 3:1 UI/large, just under 4.5 for body but only used on mono kickers/sub-labels at 9.5-11px which read as UI text). --ultra-ink and --agent-ink pairings all clear AA comfortably (9.9:1, 6.9:1). · FAIL — --steel-2 #97a2b0 is below AA everywhere it carries meaning: on --surface = 2.59:1, on --paper = 2.39:1. It is used as TEXT in .theming-applied-v .ord (the 'v0.1.0' version), .theming-tcount is --steel (ok) but .ord ordinals (01/02/03/04/07 group counters) and .theming-tab-ic mobile icons (2.59:1) all rely on --steel-2. Decorative ordinals are arguable, but the mobile tab-bar ICONS at 2.59:1 are a real touch-target legibility fail. · PASS but MISLEADING — small --ok green: --ok #0d8a4f on --surface = 4.41:1 and on --paper = 4.07:1. Both clear 3:1 (AA for >=18.66px bold / UI) but MISS 4.5:1 for normal text. .theming-guard-tag (9px), .theming-samp-tag.pub (8.5px) and .theming-guard-tx green accents are sub-18px non-bold, so technically AA-normal FAIL at ~4.1-4.4:1. White check glyph on --ok guard-ic = 4.41:1 (icon, passes 3:1). · PASS — --agent/--agent-ink usage is correct and AA-safe in BOTH modes. Light: --agent-ink #02646d on --agent-wash = 6.04:1. Dark preview (scoped #7deaf2 on #0a3a40) = 8.82:1, on surface = 12.29:1. Agent never appears as a low-contrast fill-on-fill. Notched-square agent avatar semantics preserved in mini-thumbs and sample (clip-path notch). · MISMATCH between guard-band copy and actual ratios: the band claims 'Body 8.1:1 · agent 5.4:1 · accent 4.9:1'. Real computed values for .theming-tk-afterdark are body 14.6:1, agent 8.8:1, accent (ultra-ink) 9.05:1. The numbers are quoted as precise engineering facts (the whole brand is 'engineering-drawing precision') but are wrong/under-reported. If a designer copies these as truth they mislead. Note: raw --ultra #3b5bff on surface = 3.4:1, so if 'accent 4.9:1' meant the saturated accent-on-surface it's actually a FAIL for accent-as-text — only --ultra-ink passes. · Dark-preview saturated --ultra #3b5bff as TEXT/icon-on-surface = 3.4:1 (fails AA-normal, passes 3:1 UI). The sample uses --ultra-ink #a9b8ff for text (9:1, fine) and reserves raw --ultra for fills (samp-btn bg with #fff text = 5.09:1, ok), so no actual violation in markup — but the inset 2px box-shadow accent on .theming-samp-nav.on relies on raw --ultra as a 2px rule (decorative, fine). · Mobile bottom tab-bar: idle label --steel on --surface = 4.56:1 (pass) but the ICON glyph uses --steel-2 = 2.59:1 (fail). Active tab --ultra-ink = 11.9:1 (excellent). Only the active item has a non-color affordance (2px top bar); idle vs active is otherwise color-only — borderline 1.4.1 Use of Color for the selected-tab state. · ARIA: theme thumbnails use aria-label correctly; mobile <nav aria-label='Primary'> is good. But the .theming-trow rows are <label> elements with no associated <input> — they look interactive (cursor:pointer, hover) yet expose no control to AT; the 'edited' row (--ultra hex with caret) has no role/aria-live announcing the live value. Color swatches (.theming-sw) convey palette by color alone with no text alt inside the row beyond the hex string (which is fine as the text equivalent).
fixes Token purity (drop score-limiter): replace the remaining DIRECT hard-coded hex used as property values — .theming-samp-btn{color:#fff} and .theming-guard-ic{color:#fff} should be a token (add a --on-accent / use the existing pattern; the shared sheet itself uses #fff for .btn--ultra text, so introduce --ultra-on:#fff once and reference it). The 15 literals in .theming-sw-graphite/.theming-sw-warm/.theming-sw-hicon i are the swatch palettes — those are legitimately raw values BUT they duplicate the same hexes already declared in the matching .theming-tk-* override blocks. Drive the swatches from the tokens instead: scope each swatch row with the theme class and set background:var(--paper)/var(--ink)/var(--ultra)/var(--agent)/var(--hair-strong) so the palette can never drift from the actual theme. This makes the screen literally token-pure and self-demonstrating. · Fix the guard-band numbers OR mark them illustrative. Either recompute to the real ratios (body 14.6:1, agent 8.8:1, accent 9.0:1 for ultra-ink) or, better, compute them at runtime. Quoting wrong precise figures in an 'engineering precision' brand undercuts trust. At minimum change 'accent 4.9:1' since raw --ultra-on-surface is 3.4:1 and would be a real fail if accent were used as body text. · --steel-2 contrast: stop using --steel-2 for any text that must be read. Mobile .theming-tab-ic should use --steel (4.56:1) not --steel-2 (2.59:1); .theming-applied-v .ord (version string) should be --steel or --ink-2. Keep --steel-2 only for truly decorative ord counters, and even there bump to --steel for the 8-11px mono labels. · Small --ok green text: .theming-guard-tag (9px), .theming-samp-tag.pub (8.5px) sit at ~4.1-4.4:1 — under AA-normal. Either enlarge to >=14px bold (then 3:1 suffices) or darken the success token for small text. Simplest: these are UI status chips with a border in the same color, so the border carries the signal; acceptable under AA if treated as UI components, but the inline green in .theming-guard-tx body sentence ('Two tokens auto-nudged') should use --ink-1, not green. · Make .theming-trow real controls: each token row is a <label> with no <input>. Add an associated input[type=color]/text (or role=button + tabindex=0 + keyboard handler) so the editor is operable by keyboard and exposes the editable value to AT; wrap the live hex in aria-live='polite' so 'renders as you type' is announced. Currently the entire theming editor is mouse-and-color-only. · 1.4.1 Use of Color on selected states: the mobile tab idle/active and the .theming-samp-nav.on differ only by color + a thin bar. The desktop nav uses the 2px left bar (ok). Ensure the active mobile tab's 2px top bar is the non-color cue (it is) — keep it; just verify the bar uses --ultra (3:1+ against surface) not --ultra-wash. · Touch targets: .theming-trow gets min-height:44px at <=640 (good). But .theming-copy / .theming-export-note .btn and .theming-applybtn inside cards are btn--sm (~28px tall) and never grow on mobile — bump card Apply buttons and the COPY affordance to >=44px at <=640. · Minor: .theming-tk-hicon (High Contrast / WCAG AAA) sets --hair:#000 and --hair-strong:#000 — every hairline becomes a solid 1px black rule, which is correct for AAA but means .theming-mini-row em (background:--surface-sunk #e6e6e6) bars nearly vanish on white; verify the mini-preview still reads. Cosmetic only.
verdict Strong, on-system theming screen that cleverly dogfoods the core thesis — 'a theme is just a scoped :root override' — by literally re-skinning live mini-apps via .theming-tk-* token blocks. DS fidelity is high: 0px radius, hairlines, mono kickers, notched-cyan agent avatars, crosshair mark, tabular hexes all correct, and the agent/ultra dual-signal is preserved in both light chrome and the dark preview. Reduced-motion is properly handled (the shared .live pulse, .caret-u blink, and card/row transitions are all wrapped in prefers-reduced-motion via .theming-vp scoping). Mobile is genuinely considered: bottom tab bar with safe-area inset, 44px token rows, role-column dropped, stacked actions. NOT the editor screen, so ADR 0032 gutter-accept is not required — and notably the tracked suggestion that DOES appear (in the live preview sample) is correctly rendered as INLINE ins/del (.theming-samp-ins/.theming-samp-del with the agent underline + strikethrough), not a detached card, which is the right pattern. Three things hold it back from top marks: (1) token purity is claimed ('every colour references a var') but 15 swatch hexes plus two #fff text values are hard-coded and duplicate the theme blocks — they should be token-driven so they can't drift; (2) the contrast guard-band quotes precise ratios (8.1/5.4/4.9) that are simply wrong (real values 14.6/8.8/9.0), which is a credibility problem for a precision-branded product; (3) genuine AA gaps on --steel-2 as text (2.59:1, worst on the mobile tab icons) and small --ok green chips (~4.1:1). The token editor is also visually-only — <label>s with no inputs, no keyboard path, no aria-live on the 'renders as you type' value. Fixable without restructure; the architecture and design language are right.