feat(design-system): give the brand a written identity and a per-ground mark - #2462
feat(design-system): give the brand a written identity and a per-ground mark#2462BigSimmo wants to merge 1 commit into
Conversation
…nd mark Three related things the design system did not have: one home for the product's written identity, a colour role for the logo, and a phone drawer header built for a phone. **Brand copy had four homes.** The page metadata, the web manifest, the OG card and the install prompt each carried a hand-typed sentence, and two of them disagreed about whether PsychSift is a "RAG knowledge base" or a "knowledge base". Nobody decided to say two things; the second sentence was written later by someone who could not see the first. `src/lib/brand.ts` now owns the name, the catchphrase and the descriptive lines, and `tests/brand-copy.test.ts` fails if any of them is retyped as a literal outside that module. The catchphrase is "From question to source." It promises a path, not a verdict — which is the only kind of claim this product may make, given it is a clinical reference prototype and not validated decision support. A test enforces that boundary in words: the line may not contain trust/accuracy/safety claims. The wording is not new, either; `guide-content.ts` already taught the "evidence-first workflow from question to source". "RAG" also leaves the user-facing description. It is accurate internally and meaningless on an install sheet. **The logo had no colour role of its own.** It read `--clinical-accent` directly, so a future accent retune for selection/evidence/send would have silently repainted the brand, and a surface needing the mark to hold its ground had nowhere to go but a pressed-state token. Adds `--brand-mark`, `--brand-mark-emphasis` and `--brand-mark-contrast` as aliases onto the accent ramp — one declaration each, since `.dark` and the forced-colors block both land on `<html>` — plus a `tone` prop on `<BrandMark>`. Every production chrome surface now asks for `emphasis`. The mark is two counter-turning strokes whose lower one is the thinner read, so at chrome sizes (28-40px) on a near-white band the resting accent let the bottom of the S dissolve into the ground while the dot-and-bowl cluster stayed solid: the mark went top-heavy. Emphasis is a full ramp step, so it restores an even read without touching the geometry. Mockups keep the resting tone. **The phone drawer header spent ~160px saying what the drawer is.** A third of the first screenful above the notch on a 390px phone, to a user who had just tapped the menu button and could see it — and the description wrapped to two lines because its column is squeezed between the mark and a 48px close control. It now reads as a brand lockup: mark, wordmark, one strapline that cannot wrap, and a close control that keeps its full 48px tap target while giving up the boxed chrome that made it the loudest thing in the header. The functional sentence moves to `sr-only`, where it is still the accessible description — a screen-reader user wants to know what the dialog contains, not what the product stands for, so the two audiences get different sentences instead of one compromise serving neither. The desktop sidebar takes the same lockup. These are overrides on the shared Sheet, not edits to it: every other dialog uses that header, and the case for a compact brand header is specific to a navigation drawer already showing its own contents. Verification - Full unit suite: 11721 passed | 4 skipped, 929 files. 5 pre-existing failures in clinical-hazard-controls, privacy-readiness-contract, rag-plan-package-parity and caring-contacts-contact-time-adjustment — all reproduced on a clean stashed tree (6 there; one caring-contacts case is flaky), none in this diff. - Design-system contract passed; every ratchet at or under baseline. The hardcoded-CSS-duration count reads 25 against a baseline of 26 on a clean tree too, so it is pre-existing slack, not this change masking a finding. - check:type-scale, check:icon-scale clean. Lint clean at --max-warnings 0 on the changed files. Typecheck exit 0, unscoped. Whole-tree format committed. Not done here, and recorded rather than guessed: the app renders the mark's display geometry at every chrome size, where docs/brand/psychsift-logo.md describes a small-size optical cut (a widened stroke gap and a point slid out of its cradle) for exactly that band. That is the root cause of the top-heavy read that the emphasis tone compensates for, and fixing it properly means new brand geometry — an artwork decision, not a styling one. RAG impact: no retrieval behaviour change — this diff touches no file under src/lib/rag/** and none of the protected ranking surfaces (clinical-search, retrieval-selection, released-search-order, ranking-config, answer-ranking, answer-verification), adds no comparator key, and leaves the golden fixture and eval harness untouched. Verified by listing the diff's paths against that set. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YRGeyyiZNrXnFJjVVnykgp
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_99d3b6ba-0ddc-4b4c-a0f0-253f7ebd5d59) |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
CI triageCI failed on this PR. Automated classification of the 3 failed job(s):
Compared with main CI run #14502 (failure). That run's conclusion is an aggregate and did not exercise Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger. |
Re-run result: required checks green, and a correction
Correcting myself on the other one. In my previous comment I described the What does not change is whose failure it is. The import trace stands: the route under test reaches 181 modules and none of this PR's nine changed files, and Two things follow, and I am doing neither here:
Summary of the whole run on Worth noting for the PR body's own verification section: the six unit failures I recorded from my local run did not reproduce in CI — That is my one re-run spent, and CI has settled. Merging is the owner's call. Generated by Claude Code |
Summary
src/lib/brand.tsnow owns the name, the catchphrase and the descriptive lines, andtests/brand-copy.test.tsfails if any of them is retyped as a literal outside that module.guide-content.tsalready taught the "evidence-first workflow from question to source". "RAG" also leaves the user-facing description; it is accurate internally and meaningless on an install sheet.--clinical-accentdirectly, so a future accent retune for selection/evidence/send would have silently repainted the brand, and a surface needing the mark to hold its ground had nowhere to go but a pressed-state token. Adds--brand-mark,--brand-mark-emphasisand--brand-mark-contrastas aliases onto the accent ramp — one declaration each, since.darkand the forced-colors block both land on<html>— plus atoneprop on<BrandMark>.emphasistone. The mark is two counter-turning strokes whose lower one is the thinner read, so at chrome sizes (28–40px) on a near-white band the resting accent let the bottom of the S dissolve into the ground while the dot-and-bowl cluster at the top stayed solid: the mark went top-heavy. Emphasis is a full ramp step, not a nudge, so it restores an even read without touching the geometry. Design-scratch mockups keep the resting tone.sr-only, where it is still the accessible description. A screen-reader user arriving in the dialog wants to know what the dialog contains, not what the product stands for. The two audiences get different sentences rather than one compromise serving neither.These are overrides on the shared
Sheet, not edits to it: every other dialog in the app uses that header, and the case for a compact brand header is specific to a navigation drawer that is already showing its own contents.Verification
npm run verify:pr-local— completedcheck:runtime,check:installed-lock-parity,format:changed,lint,typecheck;testthen failed on six pre-existing failures (see below), sobuildand the trailing domain checks were not reached by the wrapper and were run directly instead.npm run test—11721 passed | 4 skippedacross 929 files. Six failures are pre-existing and not in this diff, inclinical-hazard-controls,privacy-readiness-contract,rag-plan-package-parityandcaring-contacts-contact-time-adjustment. Reproduced on a clean stashed tree, which failed the same four files (six cases there; onecaring-contactscase is flaky between runs). None of the four touches brand copy, tokens,BrandMark,Sheetor the sidebar.npm run build— succeeded on a cleared.next.Client bundle secret surface check passed.npm run check:bundle-budgeton that fresh build — production, routes and mockups all within tolerance (route/237.1 KiB gzip against a 278.5 KiB baseline). ThebaselineSource ... does not resolve to a local Git commitwarning is a shallow-clone ancestry limitation and pre-exists this branch.npm run check:design-system-contract— passed, every ratchet at or under baseline; sub-floor interactive min-heights2, matching baseline. Also rancheck:design-system-adoption(55 components, 84 roots) andcheck:design-sync-contract.npm run check:type-scale,npm run check:icon-scale— both clean under--strict.npm run lint— clean at--max-warnings 0.npm run typecheck— exit 0, unscoped.npm run format— whole-tree, committed with the work rather than after it.UI verification not run:
npm run verify:uineeds a running dev server and a Chromium journey pass, which this container has provisioning in the background and which I did not confirm ready; the Chromium journeys in CI are the gate of record for this diff. The affected surfaces have offline DOM coverage that did run (sheet.dom,sheet-focus.dom,sheet-focus-stress.dom,sidebar-production.dom,mobile-sheet-safe-area-contract,pwa-lifecycle.dom— 70 passed across the sheet/sidebar set).One measurement worth stating plainly: the header's height reduction is reasoned from the token values and the removed wrapping line, not from a screenshot on a device. The two-line description is gone by construction (
truncateon a single strapline), but the exact pixel saving is an estimate until a phone journey confirms it.Risk and rollout
toneprop defaults to the previous behaviour, so reverting the call sites alone would also restore the old appearance without touching the token layer.src/lib/rag/**and none of the protected ranking surfaces (clinical-search, retrieval-selection, released-search-order, ranking-config, answer-ranking, answer-verification), adds no comparator key, and leaves the golden fixture and the eval harness untouched. Verified by listing the diff's fourteen paths against that set.Clinical Governance Preflight
Clinical KB Database(sjrfecxgysukkwxsowpy)Notes against those items, in full rather than as ticks alone.
This change introduces no retrieval path, no source-backed claim, no clinical content and no new data. It changes brand wording, a colour role, and the layout of one navigation drawer header. No Supabase target, migration, credential or document-access path is touched, and nothing in the diff runs server-side beyond static metadata generation.
The clinically material part is the catchphrase, and it was constrained deliberately. A brand line sits above every surface and is read as the product's own claim about itself, so on a clinical tool it is a governance artefact rather than decoration. "From question to source" describes the mechanism — take a clinical question, land the reader on the passage in the original document — and asserts nothing about whether the guidance found is correct, current or sufficient. That restraint is the point: the entire citation architecture exists so a clinician can check those things for themselves, and a line like "the answers you can trust" would assert exactly what the architecture is built to let them verify.
tests/brand-copy.test.tsencodes the boundary so a future edit has to argue with a failing test rather than slip past review.The one item touching a clinical-facing page is
privacy-quiet-signal-page.tsx, and the change there is the brand mark's tone attribute only — no privacy copy, no retention statement, no obligation band, and no change to what the page discloses.Failure behaviour is unchanged and remains conservative. Nothing in this diff sits on a degradation path: the tokens are aliases that resolve to the existing accent in every theme including forced-colors, and the drawer header renders identically whether or not the brand module resolves, because the strings are build-time constants rather than fetched content.
Notes
Recorded rather than guessed, and deliberately not fixed here: the app renders the mark's display geometry at every chrome size.
docs/brand/psychsift-logo.mdandsrc/lib/brand-mark.tsdescribe a small-size optical cut for exactly that 20–32px band — a widened stroke gap (BRAND_STROKE_PATH_SMALL) and a point slid out of its cradle (BRAND_POINT_SMALL) so the dot separates from the S instead of fusing into it. Nothing in the app uses either; only the favicon and the raster icon routes do. That fusion is the actual root cause of the top-heavy read, and theemphasistone compensates for it rather than fixing it.Fixing it properly means deriving a bare-glyph placement transform for the small paths, which is new brand geometry. That is an artwork decision for the owner, not a styling one an implementation PR should take unilaterally —
brand-mark.tssays in terms not to redraw the construction by hand — so it is written down here instead.Also unaddressed, and visible in the same screenshots: the phone chrome band on the privacy route paints
--surface-glassat 95%, which reads whiter than the tinted page beneath it and leaves a seam the mark appears to float on. Changing it means moving a phone chrome ground, which isdocs/search-chrome-behaviour.mdterritory and wantsverify:phone-chromeevidence of its own. It is a separate change, not a line to slip into this one.Generated by Claude Code
Note
Low Risk
Display-only branding, CSS token aliases, and sidebar/drawer layout—with broad but low-impact visual change to mark color on chrome surfaces; no auth, data, or retrieval paths.
Overview
Introduces
src/lib/brand.tsas the single source for product name, catchphrase ("From question to source."), metadata description (drops user-facing "RAG"), install tagline, menu a11y copy, and OG alt text. Metadata, manifest, OG image, PWA install UI, and the Clinical Guide sidebar now import those constants instead of hard-coded strings;tests/brand-copy.test.tsfails if owned lines are retyped elsewhere and checks catchphrase length and clinical-claims boundaries.Adds
--brand-mark,--brand-mark-emphasis, and--brand-mark-contrastinglobals.css(aliases on the clinical accent ramp) so logo ink can diverge from UI accent tuning.BrandMarkgains atoneprop (resting|emphasis|contrast); production chrome call sites switch toemphasisfor clearer small marks on light bands.Clinical Guide navigation gets a tighter brand lockup: expanded sidebar and phone drawer show wordmark plus a truncating strapline; the drawer's functional description moves to
sr-onlywhileSheetheader spacing/close styling is overridden locally (not in the shared dialog component).Reviewed by Cursor Bugbot for commit de9d97b. Configure here.