Skip to content

fix(design-system): resolve the full-frontend design review findings - #2210

Merged
BigSimmo merged 11 commits into
mainfrom
claude/frontend-design-6sl1ft
Aug 21, 2026
Merged

fix(design-system): resolve the full-frontend design review findings#2210
BigSimmo merged 11 commits into
mainfrom
claude/frontend-design-6sl1ft

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Summary

Applies the smallest correct fix for each finding from a read-only design review of the whole frontend (240 production components, 75 routes, 834 files under the design-system contract), and closes the gate gaps that let them accumulate. Every gate was already green before this PR — the findings sat in the surfaces those gates structurally cannot parse.

Live defects

  • --shadow-overlay was declared nowhere in the repository and referenced with no fallback by the sidebar Appearance menu (ClinicalSidebar.tsx:485). An unresolved var() with no fallback is invalid at computed-value time, so box-shadow fell back to none and the popover rendered flat. Declared, aliased to the elevated tier to match the other production popovers.
  • --radius-pill was also undeclared, working only because all 14 call sites independently wrote the same , 9999px fallback. Declared.
  • Print factsheet warning banner had drifted to the wrong theme's colour. The "not for clinical use" banner paired the light --danger-bg (#fef3f2) with the dark theme's --danger-solid (#b42318). Restored to the light value (#a3190f), lifting measured contrast from 6.05:1 to 7.15:1. The literals stay literals deliberately — the print stylesheet forces a white ground but not light token values, so tokenising would print the dark colour for a reader in dark mode — and a comment now records that.

Accessibility

  • 12 ward-management tap targets at exactly the 44px the repo forbids by name raised to var(--spacing-tap). They were missed by the earlier 44→48 sweep because they are hand-rolled CSS-module heights rather than Tailwind utilities. .bedStates span is left at 44px — it is display-only, not a target.
  • .roleSelect removed the only focus indication.outline: 0 with no :focus-visible replacement anywhere meant a keyboard user tabbing to the role selector saw no change at all. The visible shell now owns the ring, scoped to the wrapper because the phone layout sets the select to opacity: 0.
  • Selection state silently defeated the focus ring.:where(...):focus-visible contributes zero specificity, so an unconditional [aria-pressed="true"] outline at (0,2,0) always won on the same property — focus was indistinguishable from selection on the routing screen. Both rules are now :not(:focus-visible).
  • ward-management-network.module.css was the only one of four ward stylesheets with no forced-colors block, on the screen whose routing cues most need to survive High Contrast Mode. Added.
  • Five sub-floor controls in patient-safety-plan.tsx raised to min-h-tap, including a phone-only tab switcher.
  • Two decorative icons in ui-primitives.tsx given aria-hidden, matching the codebase's own 2,273-instance convention.

Answer surface

  • AnswerCard now requires a support prop with centrally-owned wording. deriveTrust returns "medium" both for an ordinary answer and for the case where a high-risk clinical claim rests on evidence whose authority was never reviewed — and weakEvidence covers only "unsupported"/"low". That second case therefore reached the reader as { kind: "ready" }, visually identical to a fully verified answer. The distinction already existed in compactEvidenceSummary but lived in a conditionally-rendered side card, so it could vanish. Making the prop required is what stops it being hideable. Wording is unchanged from the existing copy; the label is text, never colour alone.

Token layer

  • 36 shared token roles disagreed between globals.css and ckb-v2-tokens.css.layout.tsx:118 mounts ckb-v2 unconditionally on <html>, and .ckb-v2.ckb-v2 (0,2,0) outranks :root (0,1,0), so the v2 value always wins and the globals.css value is dead — editing it has no visible effect, silently. The four highest-consequence non-colour roles (--text-hero, --text-hero--line-height, --leading-prose, --ease-standard, the last two differing by curve family) are synced to the winning values and pinned by a new cross-file test. Visually inert, since v2 was already what rendered.

Gate gaps closed

  • New rawMarginLiterals ratchet. Padding, radius, gap and line-height each had one; margin never did, leaving 31 literals counted by nothing.
  • New test: every fallback-less var(--x) must resolve to a declaration, ignoring conditional-theme blocks so a token declared only under forced-colors cannot satisfy it. This catches the --shadow-overlay class of bug at its source.
  • Baseline regenerated: tolerated debt 363 → 339 with zero regressions, and the 50 units of recoverable slack are gone (a file that had paid debt down could previously regress back to its recorded ceiling).
  • GATES.md: two rows qualified that claimed broader enforcement than the rules have. require-z-index-ladder was marked unqualified implemented-blocking but only sees z-[N] literals in JS/TS — sidebar-live-shell.module.css:144 carries an off-ladder z-index: var(--z-sidebar-flyout, 50) it cannot see. no-hardcoded-hex matches only bg-/text-/border- bracket-hex.
  • 8 genuinely dead CSS classes removed. Five that the review initially called dead are retained: two are asserted by tests/helpers/style-contracts.ts and three are named in docs/process-hardening.md. Three others turned out to be grouped with live selectors and were pruned by name rather than deleted.

Verification

  • npm run verify:pr-localexit 0, all 19 selected gates completed, none failed: check:runtime, check:installed-lock-parity, format:changed, sitemap:check, docs:check-index, docs:check-inventory, docs:check-scripts, docs:check-links, check:branch-review-ledger, check:outstanding-issues, check:ledger-write-discipline, lint, typecheck, test, build, eval:rag:offline, eval:rag:adversarial:offline, check:medication-interactions, check:medication-lexicon-report. Unit suite Tests 7599 passed | 4 skipped (7603), zero errors. Build generated 1871 static pages. Adversarial fixture contract passed (24 synthetic cases, 8 categories, 6 canaries).
  • npm run verify:cheap was used as the iteration gate. Design-system contract passed (834 production files; ... sub-floor interactive min-heights 33; ...); Scale ratchets: raw padding literals 52; raw radius literals 20; raw gap literals 25; raw margin literals 31; raw line-height literals 3.
  • UI verification not run: Playwright browser-revision drift (#255) in this environment — check:playwright-browser-revision reports chromium 1234 expected, 1194 installed. Per AGENTS.md, a mismatched Chromium path must not be forced; browser proof is delegated to CI Production UI. This PR changes globals.css, ward-management CSS modules, tap-target heights and a forced-colors block, so Production UI is the gate that matters here and should be green before merge.
  • npm run verify:release not run — not a release/handoff confidence claim.
  • npm run check:production-readiness not run: no ingestion, privacy, environment, Supabase, source-governance or deployment behaviour changed. The clinical-output change is presentational (an additional required label on an existing card).
  • Provider-backed gates (eval:retrieval:quality, eval:rag, eval:quality) not run and not applicable: no retrieval, ranking, selection, chunking or scoring behaviour changed. The offline RAG fixture gates ran and passed as part of verify:pr-local.

New guards were each proven to fail before being trusted: reverting --leading-prose made the cross-layer test fail with the intended message, and removing the --shadow-overlay declaration made the resolution test name ClinicalSidebar.tsx:485 specifically.

Risk and rollout

  • Risk: Low-to-moderate, and concentrated in CSS. The token sync is visually inert because the v2 layer already won at runtime. The tap-target and focus changes alter ward-management layout heights by 4px per affected control and add a focus ring where there was none. The one behavioural change is the new always-rendered support label on AnswerCard, which adds a short line of text to every answer. The dead-CSS removal is the residual risk worth a reviewer's eye: three rules were grouped with live selectors and were pruned by name, so the live siblings (.medication-results-inset, .smart-search-prompt-row, .smart-search-rotating-text, [data-therapy-scroll-sm]) are asserted present but were not visually diffed.
  • Rollback: git revert of the single commit restores every surface. No migration, no data change, no config change. The regenerated scripts/design-system-contract-baseline.json and .design-sync/config.json revert with it.
  • Provider or production effects: None. No provider-backed command was run at any point in this work.
  • RAG impact: no retrieval behaviour change — no file under src/lib/rag/, no retrieval RPC, no ranking or selection surface, no golden fixture, and no eval-harness file is touched. classifyPullRequestFiles reports ragRanking: false for this diff. src/lib/answer-render-policy.ts was read during the review but is unmodified.

Clinical Governance Preflight

  • Source-backed claims still require linked source verification before clinical use
  • No patient-identifiable document workflow was introduced or expanded without explicit governance approval
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy)
  • Service-role keys and private document access remain server-only
  • Demo/synthetic content remains clearly separated from real clinical sources
  • Source metadata, review status, and outdated/unknown-source behavior remain conservative
  • Deployment classification/TGA SaMD impact was checked when clinical decision-support behavior changed

On the last item specifically: the answer-surface change makes an existing, already-computed trust distinction visible rather than introducing a new clinical determination. It adds caution-relevant information (an answer resting on unreviewed-authority evidence for a high-risk claim no longer reads as fully verified) and removes none, so it moves conservatively. The unconditional support label option was chosen deliberately over routing medium into the amber weakEvidence banner: deriveTrust also returns "medium" as its generic non-high-confidence fallback, so treating all "medium" as a caution would have alarmed on most answers and degraded the banners that do carry specific meaning.

Notes

  • The print-sheet contrast figures were measured, not estimated: #b42318 on #fef3f2 is 6.05:1 and #a3190f on #fef3f2 is 7.15:1 (both pass AA; only the corrected pair passes AAA).
  • Two counts reported during the review were corrected downward while fixing: raw margin literals are 31 by the gate's own stricter definition rather than the 43 a looser grep suggested, and the "13 dead CSS classes" became 8 once test-helper and documentation references were checked.
  • Three findings are deliberately not fixed here because they are architectural decisions rather than repairs, and should not arrive as an incidental diff: the primitive-layer split (157 files import ui-primitives.tsx against 12 that import the registered Button); the private --ward-*/--net-*/--co-* token system (~90 unregistered names, 307 spacing references); and the two overlapping type scales. Each needs a decision recorded, not a sweep.
  • One unrelated pre-existing test issue surfaced and was left alone: tests/guard-push.test.ts assumes the gh CLI is installed — inFlightCiGuard fails open when it is absent, so the test fails on any machine without gh. Proven environmental by re-running with a stub gh on PATH (41/41 pass). Not this PR's to fix.

Generated by Claude Code

Applies the smallest correct fix for each finding from the 2026-08-20
read-only design review, and closes the gate gaps that let them accumulate.
Live defects:
- Declare `--shadow-overlay` (aliased to the elevated tier, matching the other
production popovers). It was referenced with no fallback by the sidebar
Appearance menu and declared nowhere, so `box-shadow` was invalid at
computed-value time and the popover rendered flat.
- Declare `--radius-pill`. 14 call sites worked only because each independently
wrote the same `, 9999px` fallback.
- Print factsheet: the "not for clinical use" banner paired the light
`--danger-bg` with the DARK theme's `--danger-solid` (#b42318). Restored to
the light value (#a3190f), lifting measured contrast 6.05:1 -> 7.15:1. The
literals stay literals on purpose - print forces a white ground but not light
token values - and a comment now records why.
Accessibility:
- ward-management: 12 tap targets at the forbidden 44px raised to
`var(--spacing-tap)`; `.bedStates span` left alone as display-only.
- ward-management `.roleSelect`: `outline: 0` removed the only focus
indication with no replacement. The visible shell now owns the ring, scoped
to the wrapper because the phone layout sets the select to `opacity: 0`.
- Selection outlines yielded to nothing: `:where(...):focus-visible` has zero
specificity, so an unconditional `[aria-pressed="true"]` outline always beat
the focus ring. Both are now `:not(:focus-visible)`.
- ward-management-network was the only one of four ward stylesheets with no
forced-colors block; added.
- patient-safety-plan: five sub-floor controls raised to `min-h-tap`.
- Two decorative icons in ui-primitives given `aria-hidden`.
Answer surface:
- `AnswerCard` now requires a `support` prop with centrally-owned wording.
`deriveTrust` returns "medium" both for ordinary answers and for a HIGH-RISK
claim resting on unreviewed-authority evidence, and `weakEvidence` covers
only "unsupported"/"low" - so that second case reached the reader as
`ready`, visually identical to a verified answer. The distinction existed in
`compactEvidenceSummary` but sat in a conditionally-rendered side card.
Token layer:
- `ckb-v2` is mounted unconditionally on <html> and outranks `:root`, so for
any shared role the globals.css value is dead and editing it does nothing.
Synced the four highest-consequence non-colour roles to the winning values
and pinned them with a cross-file test.
Gate gaps closed:
- New `rawMarginLiterals` ratchet. Padding, radius, gap and line-height each
had one; margin never did, leaving 31 literals counted by nothing.
- New test: every fallback-less `var(--x)` must resolve to a declaration,
ignoring conditional-theme blocks (this catches the `--shadow-overlay` class
of bug at its source).
- Baseline regenerated: tolerated debt 363 -> 339 with zero regressions, and
the 50 units of recoverable slack are now gone.
- GATES.md: qualified two rows that claimed broader enforcement than the rules
actually have.
- Removed 8 genuinely dead CSS classes; 5 more that the review called dead are
retained - two are asserted by tests/helpers/style-contracts.ts and three are
named in docs/process-hardening.md. Three others were grouped with LIVE
selectors and were pruned by name rather than deleted.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uzqrokJW55EN9vbZhFyXz
@coderabbitai

coderabbitaiBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your current included review allowance is based on your included PR review attempts over the past 7 days.

Next review available in:43 minutes

Limit details: You’ve used the included review currently available. Your 87 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e8af50a9-3ac7-4995-9825-a642aab3ae26

📥 Commits

Reviewing files that changed from the base of the PR and between 5d2d2f0 and 3dde98d.

📒 Files selected for processing (29)
  • .design-sync/config.json
  • .design-sync/previews/AnswerCard.tsx
  • docs/branch-review-records/017879a1e01ebb393ee9cfcacfe95f6f72f36926ac3b954e40cce1cc53c02b27.record.md
  • docs/branch-review-records/e59c5e7a53f6377bb610ffaeec065030de7aaccb89378c8c0d6318d233cfe41e.record.md
  • docs/design-system/COMPONENTS.md
  • docs/design-system/GATES.md
  • docs/design-system/TOKENS.md
  • scripts/check-design-system-contract.mjs
  • scripts/ci-change-scope.mjs
  • scripts/design-system-contract-baseline.json
  • scripts/design-system-contract-utils.mjs
  • src/app/ckb-v2-tokens.css
  • src/app/globals.css
  • src/components/caring-contacts/mockups/caring-contact-shell-frame.tsx
  • src/components/caring-contacts/mockups/product-pages.tsx
  • src/components/clinical-dashboard/answer-result-surface.tsx
  • src/components/clinical-dashboard/settings-dialog.tsx
  • src/components/factsheets/factsheet-detail-page.tsx
  • src/components/mode-nav/mode-nav.tsx
  • src/components/patient-safety-plan.tsx
  • src/components/ui-primitives.tsx
  • src/components/ui/answer-card.tsx
  • src/components/ward-management/ward-management-modes.module.css
  • src/components/ward-management/ward-management-network.module.css
  • src/components/ward-management/ward-management.module.css
  • tests/design-system-contract-utils.test.ts
  • tests/design-token-contract.test.ts
  • tests/ui-smoke.spec.ts
  • tests/ui-v2-answer-safety.dom.test.tsx

Comment @coderabbitai help to get the list of available commands.

@supabase

supabaseBot commented Aug 21, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

…anch
Immutable record, travelling with its owning product PR rather than a
ledger-only branch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uzqrokJW55EN9vbZhFyXz
…iation
Two real defects, and three findings that needed a decision recorded rather
than a sweep.
Defects:
- caring-contact-shell-frame: the 250ms deferred focus hop was never cancelled,
so on a fast unmount it fired against a torn-down tree and threw
`document is not defined`. Held in a ref and cleared on unmount. This is the
unhandled error that surfaced once during the full suite and would not
reproduce in isolation.
- guard-push `inFlightCiGuard` fails open when `gh` is absent, and that check
ran BEFORE the injected `prViewer`/`runFetcher` were consulted - so the
blocked-message test asserted nothing on any machine without the GitHub CLI,
and failed there. `ghAvailable` is now injectable alongside the other two,
defaulting to the real probe. The full suite now passes with no `gh` on PATH
(7599 passed, exit 0), which it did not before.
Decisions recorded (these three were deliberately not swept):
- TOKENS.md gains §9 for the `--ward-*`/`--net-*`/`--co-*` family: 89 names
across four stylesheets, 307 spacing references, 0 to the real semantic
roles. §8 forbids a token without a usage rule, so leaving the family
undocumented made that rule unenforceable rather than satisfied. Recorded as
a scoped exception with the retirement path, because mapping a 1px-granular
clinical grid onto `--gap-*`/`--pad-*` reflows the bed board and is the
owner's visual call.
- ckb-v2-tokens.css records how its 6-step type scale maps onto the `@theme`
steps and Tailwind's defaults, including that `--text-sm` is 13px here
against Tailwind's 14px. Deliberately NOT resolved by aliasing: pointing this
file at `@theme` would invert the documented source-of-truth order. The
`-lh`/`-tr` companions are noted as declared-but-unadopted (0 references) so
their presence stops reading as evidence that leading is handled.
- COMPONENTS.md §0.4 gains the per-primitive breakdown behind the existing
aggregate: `Button` 12 importers against ui-primitives' 157, 112 production
files still holding a raw `<button>`, and `Sheet` at 26 as the one genuinely
adopted primitive. The split is not uniform and the reason is recorded -
`Sheet` owns focus trap, portal and stacking, which a className cannot fake.
That is the actual PR 12 question, stated rather than pre-empted.
Also documents `support` as AnswerCard's third required prop in §9.13 and the
behaviour list, so the binding contract matches the code.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uzqrokJW55EN9vbZhFyXz
`advisory_ui_changed` stayed false when a component inside
`src/components/caring-contacts/mockups/` changed, so the `@mockup` journeys -
the only browser coverage those components have, since every production
Playwright project excludes them by tag - ran nowhere.
Two rules already existed and neither reaches this layout: one matches a
TOP-LEVEL `*-mockups/` directory, the other a `*-mockups.tsx` FILE at any
depth. A plain `mockups/` segment one level down, holding files with ordinary
names, falls between them. That is 12 components today.
This is precisely the failure the existing rule's own comment describes -
"a mockup component edited on its own ... losing the only lane that runs its
`@mockup` journey" - one directory level lower than it reaches.
Adds a third pattern rather than widening either existing one, so their
behaviour is untouched. Pinned in `selfTest` from both directions: a nested
mockup file turns the lane on, and an ordinary component in the same parent
directory leaves it off, so the pattern cannot quietly grow to cover real
component directories.
Verified against this PR's own file list: exactly one flag flips
(advisory_ui_changed false -> true) and the other fifteen are unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uzqrokJW55EN9vbZhFyXz
Supersedes the earlier record, which named an ancestor SHA and predated the
loose-end fixes and the nested-mockup CI scope routing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uzqrokJW55EN9vbZhFyXz
@BigSimmo
BigSimmo marked this pull request as ready for review August 21, 2026 09:19
@BigSimmo
BigSimmo enabled auto-merge August 21, 2026 09:22

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:83507aeed3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadscripts/design-system-contract-utils.mjs Outdated
Resolves a conflict in the guard-push pair, where PR #2209 landed the same fix
independently: `ghAvailable` injected into `inFlightCiGuard` so the fail-open
`gh --version` probe stops short-circuiting the injected fetchers.
Took main's version of both files wholesale rather than hand-merging two
spellings of one change. It is a strict superset of the local one: it also
injects the probe into `selfTest`'s `mockBlockedGuard`, and adds a
fails-open-when-gh-is-unavailable case whose fetchers throw if consulted.
Nothing local was lost in substance.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uzqrokJW55EN9vbZhFyXz
Addresses the Codex P2 on the margin ratchet added earlier in this PR. The
metric only ever saw the positive class utility, so three other spellings of
the same defect cleared `check:design-system-contract` untouched:
- `-mt-[22px]` negative utility — the regex had no optional `-` prefix
- `[margin-top:22px]` arbitrary property — routes through
`recordRawScaleLiteralProperty`,
which had no margin branch
- `margin-top: 22px` stylesheet — same missing branch
Confirmed by probe before and after: all four spellings are now counted, and
`margin: 0` / `margin: var(--gap-stack)` correctly remain uncounted.
Wiring the detector was not enough on its own. `check-design-system-contract`
records class-side and CSS-side debt through two separate `recordDebt` calls,
and only the class-side one had been added — so the stylesheet half was
detected and then silently dropped. Both are wired now, which is what turned
the count from 31 to 74: 43 literal CSS margins that existed all along and no
gate could see, 35 of them in the ward-management modules whose private
spacing vocabulary TOKENS.md §9 now documents.
Baseline regenerated at 382. No other metric moved.
Pinned in `tests/design-system-contract-utils.test.ts` across all four
spellings plus the zero and token exemptions, so a future narrowing of any one
of them fails rather than quietly reducing coverage.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uzqrokJW55EN9vbZhFyXz
@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

CI triage

CI failed on this PR. Automated classification of the 2 failed job(s):

  • Lighthouse budgetnot baselined: this job did NOT run on the main comparison below (path-scoped skip), so that run says nothing about it either way. Treat the comparison as absent, not green, and inspect the failing step.
  • PR requiredneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.

Compared with main CI run #12781 (success). That run's conclusion is an aggregate and did not exercise Lighthouse budget.

Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger.

BigSimmoand others added 3 commits August 21, 2026 18:28
…scroll geometry
The full-frontend design review remediation made `support` a required prop on
AnswerCard, always rendering a short evidence-support label above the answer
prose. Two ui-smoke.spec.ts phone geometry tests had calibrated thresholds
from before that label existed, so the real added content height (a few px)
tripped their strict scroll-geometry budgets in Production UI CI:
- "phone short answer stays top-aligned with no phantom scroll into black":
maxScrollTop 12 vs a permitted <= 8. The test already measures
universal-also-matches as real content contributing to permitted overflow;
the new answer-card-support label is measured the same way and added in.
- "phone answer result keeps the edge dock and shared chrome synchronized on
a short runway": postCollapseMaxOffset 74 vs an expected < 72. The support
label's measured height is now added to that ceiling (and to the
maxOffset upper bound) instead of leaving a stale pre-label constant.
Both fixes measure the label's real rendered height rather than fudging a
magic number, matching the existing pattern for other real content in the
same tests.
@BigSimmo
BigSimmo merged commit ca7b187 into mainAug 21, 2026
26 checks passed
@BigSimmo
BigSimmo deleted the claude/frontend-design-6sl1ft branch August 21, 2026 11:07
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@BigSimmo@claude