diff --git a/.agents/plugins/api_marketplace.json b/.agents/plugins/api_marketplace.json
index bd87e4200..e3b190dd4 100644
--- a/.agents/plugins/api_marketplace.json
+++ b/.agents/plugins/api_marketplace.json
@@ -1,7 +1,7 @@
{
"name": "clinical-kb-api-local",
"interface": {
- "displayName": "Clinical KB local"
+ "displayName": "PsychSift local"
},
"plugins": [
{
diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json
index f164c3d06..af6b5e799 100644
--- a/.agents/plugins/marketplace.json
+++ b/.agents/plugins/marketplace.json
@@ -1,7 +1,7 @@
{
"name": "clinical-kb-local",
"interface": {
- "displayName": "Clinical KB local"
+ "displayName": "PsychSift local"
},
"plugins": [
{
diff --git a/.agents/skills/database-skills.md b/.agents/skills/database-skills.md
index 8301eb670..0e8abb3fc 100644
--- a/.agents/skills/database-skills.md
+++ b/.agents/skills/database-skills.md
@@ -1,6 +1,6 @@
# Database skills catalog
Run `npm run skills` to render the current categories from `catalog.json` and explanations from each canonical skill's frontmatter.
-Run `npm run check:skills` to prove that every canonical skill and compatibility alias has valid local metadata and that all Claude, Cursor, and Clinical KB plugin skills satisfy shared safety policies.
+Run `npm run check:skills` to prove that every canonical skill and compatibility alias has valid local metadata and that all Claude, Cursor, and PsychSift plugin skills satisfy shared safety policies.
The `skills` skill uses this generated view, explains each unique skill in the chat, and recommends the smallest useful set for the current request. Compatibility aliases remain callable but are not counted or displayed as separate skills.
diff --git a/.github/workflows/live-domain-monitor.yml b/.github/workflows/live-domain-monitor.yml
index e5d7c3f0c..4611e5f8c 100644
--- a/.github/workflows/live-domain-monitor.yml
+++ b/.github/workflows/live-domain-monitor.yml
@@ -37,8 +37,8 @@ jobs:
body="$(curl -sSL --fail --max-time 30 --retry 2 --retry-delay 10 --retry-all-errors "$LIVE_DOMAIN_URL/")"
# The dashboard hydrates client-side (ssr:false), so assert on the
# server-rendered document title, not client-rendered brand text.
- echo "$body" | grep -q "
Clinical KB" || {
- echo "::error::Root responded but does not serve the Clinical KB document"
+ echo "$body" | grep -q "PsychSift" || {
+ echo "::error::Root responded but does not serve the PsychSift document"
echo "First 300 bytes of response for diagnosis:"
echo "$body" | head -c 300
exit 1
diff --git a/docs/brand/preview.html b/docs/brand/preview.html
index 171775954..e2df335b8 100644
--- a/docs/brand/preview.html
+++ b/docs/brand/preview.html
@@ -526,7 +526,7 @@
@@ -554,7 +554,7 @@
The set
@@ -564,7 +564,7 @@
The set
@@ -574,7 +574,7 @@
The set
@@ -584,7 +584,7 @@
The set
@@ -594,7 +594,7 @@
The set
@@ -605,13 +605,13 @@
The set
@@ -637,6 +637,12 @@
How it is built
ends of each stroke the two edges simply run into each other, and that crossing is the point — a sharp cusp, not a
rounded cap.
+
+ The round point is placed by the same rule as the cut, not by eye. Its centre is exactly the centre of the throat
+ arc — the circle whose arc forms the concave face that cups it — so the crescent of white between the two is a
+ constant 7.2646 units all the way round, with no variation at all. Anywhere else in that bay the crescent tapers.
+ One measured width of negative space, twice: down the middle, and around the point.
+
- The 4.2-unit gap between the two strokes is the first thing to close up. The second row is a separate cut for
- small sizes: each facing edge moves 1.5 units away from the other, widening the gap to 7.2. Only those two lines
- move, so the outer silhouette is the one in the primary file.
+ Two gaps close up first: the 4.2-unit cut between the strokes, and the 7.26-unit crescent around the point. The
+ second row is the small-size variant, which opens both. Each facing edge of the cut moves 1.5 units away from the
+ other, widening it to 7.2; only those two lines move, so the outer silhouette is the one in the primary file. The
+ point slides 10 units out of its cradle, opening the crescent to 11.55 and widening the ink box, so this variant
+ also carries its own centring. The three travel as a set. Below about 20 px the point fuses into the S whatever is
+ done — that is the size, not the placement.
Primary markpsychsift-mark.svg
Down to 16 px
Down to 16 px
Down to 16 px
Down to 16 px
Down to 16 px
Down to 16 px
Down to 16 px
Down to 16 px
Down to 16 px
Down to 16 px
Down to 16 px
Down to 16 px
Down to 16 px
Lockups
psychsift-lockup-horizontal.svg
psychsift-lockup-horizontal-tagline.svg
psychsift-lockup-horizontal-reverse.svg
psychsift-lockup-stacked.svg
@@ -936,7 +951,15 @@
Lockups
05
Colours
+ the symbol carries the colour
+
+ In the application the mark has no tile at all: the S is drawn in the accent colour, standing directly on the
+ page, so on a white ground it reads as a mark rather than an app-store tile dropped into the chrome. The tile
+ survives only where the format cannot be transparent and something has to be painted — the .ico, the Apple touch
+ icon and the Android icons — and there it is the surface colour, not a brand colour. The navy tile below is the
+ brand sheet's own, for use away from the app.
+
@@ -950,12 +973,22 @@
Colours
Deep Navy
#0D1B2A
-
The tile; and the S on light grounds
+
The brand-sheet tile, and the S on light grounds
White
#FFFFFF
-
The S and the point, on navy
+
The S on navy; and the ground of every app icon
+
+
+
Accent Blue
+
#1D6FB8
+
The S in the application, light theme — the accent token
+
+
+
Accent Blue, dark
+
#74BDF0
+
The S in the application, dark theme
Brand Blue
@@ -1046,7 +1079,7 @@
Clear space and misuse
>
Clear space and misuse
@@ -1119,7 +1152,7 @@
Clear space and misuse
@@ -1131,7 +1164,7 @@
Clear space and misuse
@@ -1143,7 +1176,7 @@
Clear space and misuse
@@ -1248,14 +1281,19 @@
The files
09
Still open
- two for the owner; one now settled
+ one for the owner; two now settled
01
- Two taglines. The brand sheet gives "CLARITY. EVIDENCE. BETTER CARE." in its header and "Clinical
- clarity. Evidence. Better care." in its footer. The lockup uses the first. One of them should be retired.
+ The strapline — chosen, on trial. The application now sets "From question to source" under the
+ wordmark: it names the exact job the app does, and it promises a route to evidence rather than an answer,
+ which is the honest claim for a reference tool that is not validated decision support. It replaces
+ "Source-backed clinical search". The brand sheet's own two taglines — "CLARITY. EVIDENCE. BETTER CARE." in its
+ header and "Clinical clarity. Evidence. Better care." in its footer — are still both in the sheet, and the
+ tagline lockup still carries the first. Once the strapline is confirmed, one line should serve everywhere and
+ the other two retired.
diff --git a/docs/brand/psychsift-logo.md b/docs/brand/psychsift-logo.md
index 8f0726b83..1b280ae97 100644
--- a/docs/brand/psychsift-logo.md
+++ b/docs/brand/psychsift-logo.md
@@ -157,24 +157,43 @@ approximately — true is what fixes the cut's position; see **The middle line**
### The point
-A circle of radius **10.4586** centred at **(60.4716, 17.3581)**.
-
-Measured against the cut, its centre sits **43.95 units along** the cut from the cut's midpoint and
-**14.90 units off** it, on the lower stroke's side. Its nearest approach to the S is 13.65 units —
-a little over three times the width of the cut, which is what keeps it reading as a separate
-particle rather than part of the letter.
+A circle of radius **10.4586** centred at **(44.8724, 20.0286)** — which is exactly the centre of
+the throat arc.
+
+That is the whole of the placement rule. Because the point shares its centre with the arc that cups
+it, the crescent of white between them is a **constant 7.2646 units** all the way round — 17.7232
+less the point's own 10.4586 — with zero variation. It is the same idea as the straight cut between
+the two strokes: negative space of one measured width, not a gap that happens to look about right.
+Move the point off that centre and the crescent immediately starts to taper. Its clearance to the
+lower stroke is 8.18 units.
+
+**The small-size point** sits 10 units further out, at **(54.8724, 20.0286)**, opening the crescent
+from 7.26 to 11.55. It travels with the widened cut as a set — the wider ink box it produces also
+needs its own centring transform, and mixing one variant's point with the other's placement puts
+the glyph off-centre in the tile. Below about 20 px the crescent is under two pixels and the point
+fuses into the S whatever is done; that is the size, not the placement.
+
+Two earlier positions are worth recording, because both were wrong in instructive ways. It sat at
+(60.4716, 17.3581) until 2026-08-28, well clear of the S to the upper right. The nearest point on
+the entire S was the upper stroke's sharp tip, aimed straight at the circle from 13.65 units — 2.2
+px at a 16 px icon, which antialiasing closes. A sharp point aimed at a circle reads as contact
+even when the numbers say otherwise. Dropping it 7 units to (60.4716, 24.3581) fixed the contact
+reading and opened the approach to 18.46 units, but left it floating: too far out, and unrelated to
+any curve in the mark. Cradling it in the throat resolves both, and gives the mark a hint of the
+**P** in PsychSift alongside the S.
An earlier draft of these files had it at (58.9234, 16.5279) with radius 10.2165. That was a
measurement error, not a decision: 1.8 units in and 2.3% small, which crowded the S's shoulder and
made the point look like a stray rather than a counterweight.
-With the point included, the glyph spans 0 to 70.93 horizontally and 0 to 100.38 vertically.
+With the point included, the glyph spans 0 to 55.33 horizontally and 0 to 100.38 vertically.
+The small-size variant, whose point sits further out, spans 0 to 65.33 by the same 0 to 100.38.
### The tile
A square with a corner radius of **3/16 of its side** (18.75%). The glyph is scaled to **80% of the
tile height** and its ink bounding box — S and point together — is centred in the tile. At 512 px
-that leaves 112 px clear on the left and right and 51 px top and bottom.
+that leaves 143 px clear on the left and right and 51 px top and bottom.
An earlier draft weighted the placement 46% of the way from the S's own centre toward the glyph's
right edge, on the theory that the light point should not drag the heavy S leftward. It
@@ -183,18 +202,28 @@ bounding box is both simpler and visibly right.
### Small sizes
-At 32 px and below the 4.2-unit cut closes up. `psychsift-favicon.svg` is a separate optical cut for
-that range: the gap is widened to **7.2 units** by moving each facing edge 1.5 units away from the
-other, and the blends are re-solved against the lines they now meet. Because only the facing edges
-move, the outer silhouette is identical to the one in the primary file. Use it for favicons, browser
-tabs, and anything rendered under 32 px.
+At 32 px and below two things close up: the 4.2-unit cut between the strokes, and the 7.26-unit
+crescent around the point. `psychsift-favicon.svg` is a separate optical variant for that range, and
+it changes both.
+
+The cut is widened to **7.2 units** by moving each facing edge 1.5 units away from the other, with
+the blends re-solved against the lines they now meet. Because only the facing edges move, the outer
+silhouette is identical to the one in the primary file.
+
+The point slides **10 units out of its cradle**, to (54.8724, 20.0286), opening the crescent to
+11.55 units. That widens the ink bounding box to 65.33, so this variant also carries its own
+centring transform; the three changes are one set and must not be mixed with the primary variant's
+placement. Below about 20 px the crescent is under two pixels and the point fuses into the S
+whatever is done — that is the size, not the placement.
+
+Use this variant for favicons, browser tabs, and anything rendered under 32 px.
### The maskable icon
`psychsift-mark-maskable.svg` is full-bleed, because Android crops adaptive icons to whatever shape
the launcher uses. Everything that must survive that crop has to sit inside a centred circle of
**66.7% of the icon's width**. The glyph is scaled to **62% of the height**, which puts its furthest
-ink 168 px from the centre of a 512 px icon against the 171 px the safe circle allows. Do not raise
+ink 160 px from the centre of a 512 px icon against the 171 px the safe circle allows. Do not raise
that 62%: an earlier draft used 58% with a different centring and still put ink 176 px out, outside
the safe circle.
diff --git a/docs/design-system.md b/docs/design-system.md
index f9a9cea09..5b4337676 100644
--- a/docs/design-system.md
+++ b/docs/design-system.md
@@ -258,12 +258,32 @@ image"}` — never a possibly-empty variable alone.
Do not re-draw the paths by hand: they are the exact output of the construction recorded in
`docs/brand/psychsift-logo.md`, whose master artwork is in `public/brand/`, and the two strokes
are one path plus its point reflection — which is the only reason the cut between them stays
- parallel. `app/icon.svg` deliberately uses the mark's small-size cut (a wider gap), because that
- is the file browsers render at 16–32 px.
-- **The tile colour is not the brand's.** `BRAND_LIGHT.tile` / `BRAND_DARK.tile` are pinned to
- `--clinical-accent` per theme by `tests/design-token-contract.test.ts`, so the mark rides the
- application's accent rather than the brand sheet's Deep Navy. Putting the mark on navy means
- moving that accent, which is an application-wide decision — not a brand-asset one.
+ parallel. `app/icon.svg` and `favicon.ico` deliberately use the mark's **small-size set**, because
+ they are the files browsers render at 16–32 px: the widened cut (`BRAND_STROKE_PATH_SMALL`), the
+ point slid out of its cradle (`BRAND_POINT_SMALL`), and the centring that the wider ink box needs
+ (`BRAND_GLYPH_TRANSFORM_SMALL`). Those three travel together — mixing one with the other
+ variant's placement puts the glyph off-centre in the tile — and `brandMarkInner(colors, true)`
+ selects all three from the single `small` flag so a caller cannot pick them apart.
+- **The brand sheet is mirrored into `public/`.** `docs/brand/preview.html` is the generated
+ construction record; `public/brand/preview.html` is a byte-identical copy so the Developer Hub's
+ "Brand and design" card can link to it as a static file (`/brand/preview.html`). It is the one
+ hub panel that is not an app route, so `HubPanel.external` marks it, `PanelCard` renders it as a
+ real anchor rather than a `` (the client router has no entry for a file), and
+ `tests/developer-hub-panels.test.ts` both excludes it from the route-existence check and holds
+ the two copies identical by hash — a stale copy would show a retired mark to the one reader most
+ likely to trust it. Regenerate the doc, then copy it over the served one.
+- **In the app the mark has no tile.** `BrandMark` draws the symbol alone, filled
+ `--clinical-accent`, standing directly on the page ground — so on a white page it reads as a
+ mark rather than an app-store tile pasted into the chrome. It uses
+ `BRAND_GLYPH_TRANSFORM_BARE`, which scales the glyph to fill its box, so it occupies the same
+ slot the tiled version did. The tiled form survives only where the format has no transparency
+ to fall back on: `favicon.ico`, `apple-icon`, and the PWA raster icons.
+- **The tile is the ground, the ink is the brand.** `BRAND_*.ink` is pinned to `--clinical-accent`
+ and `BRAND_*.tile` to `--surface-raised`, per theme, by `tests/design-token-contract.test.ts`.
+ So the symbol rides the application's accent and the tile only ever matches the surface behind
+ it. The brand sheet's Deep Navy tile lives on in `public/brand/psychsift-mark.svg` for use off
+ the app; putting the in-app mark on navy would mean moving the accent, which is an
+ application-wide decision, not a brand-asset one.
## 11. What NOT to do
diff --git a/docs/site-map.md b/docs/site-map.md
index 8b7d5bdd3..2c27e0735 100644
--- a/docs/site-map.md
+++ b/docs/site-map.md
@@ -1,10 +1,10 @@
-# Clinical KB Site Map
+# PsychSift Site Map
This file is generated by `npm run docs:update` (or `npm run sitemap:update` directly). Run `npm run sitemap:check` to verify it is current.
## Main product routes
-- `/` - Main Clinical KB shell. Source: `src/app/(search-app)/page.tsx`.
+- `/` - Main PsychSift shell. Source: `src/app/(search-app)/page.tsx`.
- `/calculators` - Compatibility redirect to the shared home at `/?mode=calculators`; a submitted `?q=…&run=1` forwards to `/calculators/search`. Source: `src/app/(search-app)/calculators/page.tsx`.
- `/calculators/search` - Browsable calculator catalogue and scored results. An empty query lists every calculator; a submitted query narrows the same list. Source: `src/app/(search-app)/calculators/search/page.tsx`.
- `/caring-contacts` - Caring Contacts workspace — a synthetic, non-clinical demonstration of caring-contact follow-up. Standalone: it owns its own navigation and is entered from the Tools catalogue. Source: `src/app/caring-contacts/page.tsx`.
diff --git a/plugins/clinical-kb/.codex-plugin/plugin.json b/plugins/clinical-kb/.codex-plugin/plugin.json
index 67e4aaf1c..f310515e6 100644
--- a/plugins/clinical-kb/.codex-plugin/plugin.json
+++ b/plugins/clinical-kb/.codex-plugin/plugin.json
@@ -1,26 +1,26 @@
{
"name": "clinical-kb",
"version": "0.1.0",
- "description": "Repo guidance for Clinical KB, a Next.js clinical reference RAG app.",
+ "description": "Repo guidance for PsychSift, a Next.js clinical reference RAG app.",
"author": {
- "name": "Clinical KB maintainers",
+ "name": "PsychSift maintainers",
"url": "https://github.com/BigSimmo"
},
"repository": "https://github.com/BigSimmo/Database",
"keywords": ["clinical-kb", "nextjs", "rag", "supabase", "clinical-safety", "local-development"],
"skills": "./skills/",
"interface": {
- "displayName": "Clinical KB",
- "shortDescription": "Work safely in the Clinical KB Next.js and Supabase RAG repo.",
- "longDescription": "Clinical KB provides repo-specific Codex guidance for local server safety, Next.js 16 conventions, Supabase project safety, no-API verification, clinical governance checks, and focused verification choices.",
- "developerName": "Clinical KB maintainers",
+ "displayName": "PsychSift",
+ "shortDescription": "Work safely in the PsychSift Next.js and Supabase RAG repo.",
+ "longDescription": "PsychSift provides repo-specific Codex guidance for local server safety, Next.js 16 conventions, Supabase project safety, no-API verification, clinical governance checks, and focused verification choices.",
+ "developerName": "PsychSift maintainers",
"category": "Developer Tools",
"capabilities": ["Read", "Write"],
"websiteURL": "https://github.com/BigSimmo/Database",
"defaultPrompt": [
- "Run the safe Clinical KB local server.",
- "Verify my Clinical KB change without API calls.",
- "Review this Clinical KB RAG change."
+ "Run the safe PsychSift local server.",
+ "Verify my PsychSift change without API calls.",
+ "Review this PsychSift RAG change."
],
"brandColor": "#0B6F86"
}
diff --git a/plugins/clinical-kb/README.md b/plugins/clinical-kb/README.md
index f99b1d08d..5e2cfe5e4 100644
--- a/plugins/clinical-kb/README.md
+++ b/plugins/clinical-kb/README.md
@@ -1,4 +1,4 @@
-# Clinical KB Codex Plugin
+# PsychSift Codex Plugin
This plugin follows the repo-local structure used by `openai/plugins`:
diff --git a/plugins/clinical-kb/skills/clinical-kb-workflow/SKILL.md b/plugins/clinical-kb/skills/clinical-kb-workflow/SKILL.md
index 48fb55cf5..ee4b0318f 100644
--- a/plugins/clinical-kb/skills/clinical-kb-workflow/SKILL.md
+++ b/plugins/clinical-kb/skills/clinical-kb-workflow/SKILL.md
@@ -1,11 +1,11 @@
---
name: clinical-kb-workflow
-description: Use when working in the D:\Repos\Database Clinical KB repo, especially for local run, UI/browser QA, Supabase/OpenAI/RAG changes, clinical governance, dependency/upload shortcuts, or choosing verification.
+description: Use when working in the D:\Repos\Database PsychSift repo, especially for local run, UI/browser QA, Supabase/OpenAI/RAG changes, clinical governance, dependency/upload shortcuts, or choosing verification.
---
-# Clinical KB Workflow
+# PsychSift Workflow
-Use this skill for `D:\Repos\Database`, the Clinical KB Next.js clinical reference RAG app.
+Use this skill for `D:\Repos\Database`, the PsychSift Next.js clinical reference RAG app.
Root `AGENTS.md` remains authoritative. If these notes drift, inspect the repo before acting.
## Repo Basics
diff --git a/public/brand/preview.html b/public/brand/preview.html
new file mode 100644
index 000000000..e2df335b8
--- /dev/null
+++ b/public/brand/preview.html
@@ -0,0 +1,1324 @@
+PsychSift Mark
+
+
+
+
+
+
+
+
+
+
PsychSift
+
The mark, rebuilt as true vector geometry — every curve a circle with a stated centre and radius.
+
+
+
+
Drawn 28 Aug 2026
+
Primary file 863 bytes
+
Curves 4 arcs, 1 line, 1 circle
+
Source public/brand/
+
+
+
+
+ 01
+
The set
+ 13 SVG · 2 PNG
+
+
+ One mark, cut for the grounds it actually has to sit on. The checkered stage shows where each file is transparent.
+
+
+
+
+
+
+ Primary markpsychsift-mark.svg
+
+
+
+
+
+ On brand bluepsychsift-mark-blue.svg
+
+
+
+
+
+ On a light tilepsychsift-mark-light.svg
+
+
+
+
+
+ Maskablepsychsift-mark-maskable.svg
+
+
+
+
+
+ Small-size cutpsychsift-favicon.svg
+
+
+
+
+
+
+
+
+
+
+ Glyph, no tilepsychsift-glyph-*.svg
+
+
+
+
+
+
+ 02
+
How it is built
+ glyph units, S height = 100
+
+
+ The gap down the middle is drawn first, and it is one straight line. Each stroke's facing edge is that line,
+ offset by half the gap, so the two edges are exactly parallel — one width the whole way down, and neither can
+ curve against the other. Each stroke is then built out from its own edge: an outer sweep on a circle centred on
+ its own radius, tangent to the top and left of its box; a flatter arc two-thirds of the way down that hooks the
+ tail into a long fine point; a throat under the head; and a single blend that carries the throat onto the cut.
+ Both blends bend the same way, away from the other stroke, so nothing on either facing edge turns over. At both
+ ends of each stroke the two edges simply run into each other, and that crossing is the point — a sharp cusp, not a
+ rounded cap.
+
+
+ The round point is placed by the same rule as the cut, not by eye. Its centre is exactly the centre of the throat
+ arc — the circle whose arc forms the concave face that cups it — so the crescent of white between the two is a
+ constant 7.2646 units all the way round, with no variation at all. Anywhere else in that bay the crescent tapers.
+ One measured width of negative space, twice: down the middle, and around the point.
+
+
+
+
+
+
+
+
+
+
Segment
+
Centre
+
r
+
Role
+
+
+
+
+
The cut
+
44.6629
+
118.806°
+
one straight line; both facing edges are it, offset ±2.1
+
+
+
Outer sweep
+
29.2009, 29.2009
+
29.2009
+
upper outer edge, head to two-thirds down
+
+
+
Tail hook
+
51.5937, 16.1418
+
55.1234
+
draws the tail to a point
+
+
+
Throat
+
44.8724, 20.0286
+
17.7232
+
the scoop under the head
+
+
+
Blend
+
17.4753, 33.9324
+
13.0
+
carries the throat onto the cut
+
+
+
Head cusp
+
41.3675, 2.6554
+
36°
+
outer sweep meets throat, sharp
+
+
+
Tail cusp
+
18.0434, 59.8793
+
81°
+
the cut meets the tail hook, sharp
+
+
+
Lower stroke
+
55.1029, 100.3813
+
×−1.07
+
the upper stroke, turned and 7% larger — exactly the same path
+
+
+
The point
+
44.8724, 20.0286
+
10.4586
+
concentric with the throat — a constant 7.2646 crescent
+
+
+
Small-size point
+
54.8724, 20.0286
+
10.4586
+
slid 10 out of the cradle; crescent opens to 11.55
+
+
+
+
+
+
+
+
+
+ 03
+
Down to 16 px
+ rendered at true size
+
+
+ Two gaps close up first: the 4.2-unit cut between the strokes, and the 7.26-unit crescent around the point. The
+ second row is the small-size variant, which opens both. Each facing edge of the cut moves 1.5 units away from the
+ other, widening it to 7.2; only those two lines move, so the outer silhouette is the one in the primary file. The
+ point slides 10 units out of its cradle, opening the crescent to 11.55 and widening the ink box, so this variant
+ also carries its own centring. The three travel as a set. Below about 20 px the point fuses into the S whatever is
+ done — that is the size, not the placement.
+
+
Primary markpsychsift-mark.svg
+
+
+ 16
+
+
+ 20
+
+
+ 24
+
+
+ 32
+
+
+ 48
+
+
+ 64
+
+
+ 96
+
+
+
Small-size cutpsychsift-favicon.svg — use at 32 px and below
+
+
+ 16
+
+
+ 20
+
+
+ 24
+
+
+ 32
+
+
+ 48
+
+
+ 64
+
+
+ 96
+
+
+
+
+
+
+ 04
+
Lockups
+ Inter Display SemiBold, outlined
+
+
+ The wordmark is embedded as outlines, so the lockups render identically on a machine that has never seen Inter.
+
+
+
+ psychsift-lockup-horizontal.svg
+
+
+ psychsift-lockup-horizontal-tagline.svg
+
+
+ psychsift-lockup-horizontal-reverse.svg
+
+
+ psychsift-lockup-stacked.svg
+
+
+ psychsift-wordmark.svg
+
+
+
+
+
+
+ 05
+
Colours
+ the symbol carries the colour
+
+
+ In the application the mark has no tile at all: the S is drawn in the accent colour, standing directly on the
+ page, so on a white ground it reads as a mark rather than an app-store tile dropped into the chrome. The tile
+ survives only where the format cannot be transparent and something has to be painted — the .ico, the Apple touch
+ icon and the Android icons — and there it is the surface colour, not a brand colour. The navy tile below is the
+ brand sheet's own, for use away from the app.
+
+
+
+
+
+
Name
+
Hex
+
Where it is used
+
+
+
+
+
Deep Navy
+
#0D1B2A
+
The brand-sheet tile, and the S on light grounds
+
+
+
White
+
#FFFFFF
+
The S on navy; and the ground of every app icon
+
+
+
Accent Blue
+
#1D6FB8
+
The S in the application, light theme — the accent token
+
+
+
Accent Blue, dark
+
#74BDF0
+
The S in the application, dark theme
+
+
+
Brand Blue
+
#2563EB
+
The blue tile; the lockup tagline
+
+
+
Cool Gray
+
#F2F4F7
+
The light tile
+
+
+
+
+
+
+
+
+ 06
+
What changed from the original
+
+
+ The mark on the brand sheet is the design. Measured from a high-resolution view of it, arc by arc, at the 50%
+ level of its anti-aliased edges — the one place on a blurred edge the blur does not bias. Three earlier drafts got
+ it wrong in instructive ways, and every error came from trusting a measurement the source could not support.
+
+
+
+ 01
+
+ The terminals are sharp. At the size the original was first sampled, a sharp point blurs into a rounded
+ blob. The first draft fitted that blur and gave the mark rounded club-ends. Both tips are genuine cusps.
+
+
+
+ 02
+
+ The tail leaves the main sweep. The second draft put the whole outer edge on one circle. It is not:
+ two-thirds of the way down, the outer edge peels away and hooks out — by three full units at the tip. That
+ hook is what draws the tail into a long fine point. Nearest-point fitting had hidden it; comparing coverage
+ against the original's grey levels showed it at once.
+
+
+
+ 03
+
+ The middle line is one straight cut. Two drafts got this wrong the same way. The first gave each
+ stroke's facing edge its own circle, curving opposite ways, and the gap swelled from 5.4 units at its ends to
+ 8.6 in the middle. The second made both edges arcs of one circle, which fixed the width but left a 7.5-unit
+ blend reading as a knuckle on the spine. The strokes are now divided by a single straight line and each facing
+ edge is that line, offset — parallel by construction, so the gap cannot open and neither edge can curve
+ against the other.
+
+
+
+ 04
+
+ The two blue points are gone, and the glyph is now centred in its tile rather than pressed against the
+ right edge.
+
+
+
+ 05
+
+ The second stroke's outline stays 7% larger — kept, not corrected. Forcing the two to be identical
+ measurably worsens the match and opens the channel between them, which is the tension the mark depends on.
+
+
+
+
+
+
+
+ 07
+
Clear space and misuse
+ the four rules that matter
+
+
+ Keep a margin of at least one quarter of the mark's height clear on every side — of type, of image edges, of other
+ logos. The mark is already inset inside its own tile; this margin is measured from the tile.
+
+
+
+
+
+
+
+
+
+
Rule
+
Why
+
+
+
+
+
Never re-space the two strokes
+
+ the gap is a constructed 4.2 units; widening it breaks the one relationship the mark is built on
+
+
+
+
Never stretch it
+
+ every curve is a true circle; a non-uniform scale turns them into ellipses and the cut stops being
+ parallel
+
+
+
+
Never add a shadow or gradient
+
+ the mark is one flat colour on one flat ground, and it has to survive being printed in black
+
+
+
+
Never place the navy mark on a mid-tone
+
+ use psychsift-mark-light.svg on pale grounds and
+ psychsift-lockup-horizontal-reverse.svg on dark ones
+
+
+
+
Never re-trace a PNG
+
start from the SVG; the raster exports exist only for systems that refuse vectors
+
+
+
+
+
+
+
+
+
+
+
+ Do not stretch itthe circles become ellipses and the cut stops being parallel
+
+
+
+
+
+
+
+ Do not add a shadow or gradientthe mark is one flat colour on one flat ground
+
+
+
+
+
+
+
+ Do not re-space the strokesthe 4.2-unit gap is the relationship the mark is built on
+
+
+
+
+
+
+
+ Do not put it on a mid-toneuse the light file on pale grounds, the reverse on dark
+
+
+
+
+
+
+
+ 08
+
The files
+ 13 SVG · 2 PNG · public/brand/
+
+
+ Every file here is generated from the same geometry, so they cannot drift apart. If the mark ever changes, all
+ fifteen are rebuilt together.
+
+
+
+
+
+
File
+
Use it for
+
+
+
+
+
psychsift-mark.svg
+
the primary mark, navy tile — the default everywhere
+
+
+
psychsift-mark-blue.svg
+
on brand blue
+
+
+
psychsift-mark-light.svg
+
on a light tile, for pale backgrounds
+
+
+
psychsift-mark-maskable.svg
+
full-bleed square for PWA install and Android adaptive icons
+
+
+
psychsift-favicon.svg
+
browser tabs and anything under 32 px
+
+
+
psychsift-glyph-white.svg
+
the glyph alone, white, no tile
+
+
+
psychsift-glyph-navy.svg
+
the glyph alone, navy, no tile
+
+
+
psychsift-glyph-mono.svg
+
the glyph in currentColor, for inlining
+
+
+
psychsift-lockup-horizontal.svg
+
mark plus wordmark, light backgrounds
+
+
+
psychsift-lockup-horizontal-reverse.svg
+
the same, dark backgrounds
+
+
+
psychsift-lockup-horizontal-tagline.svg
+
with CLARITY. EVIDENCE. BETTER CARE.
+
+
+
psychsift-lockup-stacked.svg
+
mark above wordmark, for narrow spaces
+
+
+
psychsift-wordmark.svg
+
the wordmark alone
+
+
+
psychsift-mark-1024.png
+
raster export, where SVG is refused
+
+
+
psychsift-mark-maskable-1024.png
+
raster export of the maskable icon
+
+
+
+
+
+ The mark carries role="img" and a <title>, so a screen reader announces it as
+ "PsychSift" when it is inlined. Next to the word PsychSift, mark it aria-hidden instead, so the name
+ is not read twice.
+
+
+
+
+
+ 09
+
Still open
+ one for the owner; two now settled
+
+
+
+ 01
+
+ The strapline — chosen, on trial. The application now sets "From question to source" under the
+ wordmark: it names the exact job the app does, and it promises a route to evidence rather than an answer,
+ which is the honest claim for a reference tool that is not validated decision support. It replaces
+ "Source-backed clinical search". The brand sheet's own two taglines — "CLARITY. EVIDENCE. BETTER CARE." in its
+ header and "Clinical clarity. Evidence. Better care." in its footer — are still both in the sheet, and the
+ tagline lockup still carries the first. Once the strapline is confirmed, one line should serve everywhere and
+ the other two retired.
+
+
+
+ 02
+
+ Inter or Geist. The sheet specifies Inter throughout; the running application sets its interface in
+ Geist. The wordmark here is outlined artwork so it is unaffected either way, but a wordmark set live in Geist
+ would not match it.
+
+
+
+ 03
+
+ The tail tips — settled. Both tails end in a clean angled cut at about 81°. A flatter tail hook would
+ draw them into finer points, closer to the blurry original; it was drawn, compared and rejected by the owner
+ on 2026-08-28. Fine points thin both strokes, they belong with a curved middle rather than a straight one, and
+ they are the first thing to disappear at 16 px. Do not revisit this without a reason the three of those do not
+ already answer.
+
diff --git a/src/app/mockups/calculators-bedside-sheet/page.tsx b/src/app/mockups/calculators-bedside-sheet/page.tsx
index fdfd598da..882b86fce 100644
--- a/src/app/mockups/calculators-bedside-sheet/page.tsx
+++ b/src/app/mockups/calculators-bedside-sheet/page.tsx
@@ -3,8 +3,8 @@ import type { Metadata } from "next";
import { CalculatorsBedsideSheetMockup } from "@/components/calculator-mockups";
export const metadata: Metadata = {
- title: "Calculators Bedside Sheet Mockup - Clinical KB",
- description: "Multi-scale bedside assessment sheet with a running session summary for Clinical KB.",
+ title: "Calculators Bedside Sheet Mockup - PsychSift",
+ description: "Multi-scale bedside assessment sheet with a running session summary for PsychSift.",
};
export default function CalculatorsBedsideSheetMockupRoute() {
diff --git a/src/app/mockups/calculators-clinical-console/page.tsx b/src/app/mockups/calculators-clinical-console/page.tsx
index baf66eeb2..509caa888 100644
--- a/src/app/mockups/calculators-clinical-console/page.tsx
+++ b/src/app/mockups/calculators-clinical-console/page.tsx
@@ -3,8 +3,8 @@ import type { Metadata } from "next";
import { CalculatorsClinicalConsoleMockup } from "@/components/calculator-mockups";
export const metadata: Metadata = {
- title: "Calculators Clinical Console Mockup - Clinical KB",
- description: "Split-pane psychiatry calculator console with a live score ticker for Clinical KB.",
+ title: "Calculators Clinical Console Mockup - PsychSift",
+ description: "Split-pane psychiatry calculator console with a live score ticker for PsychSift.",
};
export default function CalculatorsClinicalConsoleMockupRoute() {
diff --git a/src/app/mockups/calculators-directory-grid/page.tsx b/src/app/mockups/calculators-directory-grid/page.tsx
index 811927db5..5bce7f632 100644
--- a/src/app/mockups/calculators-directory-grid/page.tsx
+++ b/src/app/mockups/calculators-directory-grid/page.tsx
@@ -3,8 +3,8 @@ import type { Metadata } from "next";
import { CalculatorsDirectoryGridMockup } from "@/components/calculator-mockups";
export const metadata: Metadata = {
- title: "Calculators Directory Grid Mockup - Clinical KB",
- description: "Searchable psychiatry calculator directory with expand-in-place scoring for Clinical KB.",
+ title: "Calculators Directory Grid Mockup - PsychSift",
+ description: "Searchable psychiatry calculator directory with expand-in-place scoring for PsychSift.",
};
export default function CalculatorsDirectoryGridMockupRoute() {
diff --git a/src/app/mockups/calculators-guided-flow/page.tsx b/src/app/mockups/calculators-guided-flow/page.tsx
index eeab3f746..98c2fd103 100644
--- a/src/app/mockups/calculators-guided-flow/page.tsx
+++ b/src/app/mockups/calculators-guided-flow/page.tsx
@@ -3,8 +3,8 @@ import type { Metadata } from "next";
import { CalculatorsGuidedFlowMockup } from "@/components/calculator-mockups";
export const metadata: Metadata = {
- title: "Calculators Guided Flow Mockup - Clinical KB",
- description: "Phone-first one-question-at-a-time psychiatry calculator flow for Clinical KB.",
+ title: "Calculators Guided Flow Mockup - PsychSift",
+ description: "Phone-first one-question-at-a-time psychiatry calculator flow for PsychSift.",
};
export default function CalculatorsGuidedFlowMockupRoute() {
diff --git a/src/app/mockups/calculators-popup-sheet/page.tsx b/src/app/mockups/calculators-popup-sheet/page.tsx
index ef91a5d44..96837a8ed 100644
--- a/src/app/mockups/calculators-popup-sheet/page.tsx
+++ b/src/app/mockups/calculators-popup-sheet/page.tsx
@@ -3,9 +3,9 @@ import type { Metadata } from "next";
import { CalculatorsPopupSheetMockup } from "@/components/calculator-mockups";
export const metadata: Metadata = {
- title: "Calculators Popup Sheet Mockup - Clinical KB",
+ title: "Calculators Popup Sheet Mockup - PsychSift",
description:
- "Search-first psychiatry calculators page where each calculator opens as a desktop dialog or mobile bottom sheet for Clinical KB.",
+ "Search-first psychiatry calculators page where each calculator opens as a desktop dialog or mobile bottom sheet for PsychSift.",
};
export default function CalculatorsPopupSheetMockupRoute() {
diff --git a/src/app/mockups/calculators-search-page/page.tsx b/src/app/mockups/calculators-search-page/page.tsx
index 2e39887c4..025ec4dfd 100644
--- a/src/app/mockups/calculators-search-page/page.tsx
+++ b/src/app/mockups/calculators-search-page/page.tsx
@@ -3,9 +3,9 @@ import type { Metadata } from "next";
import { CalculatorsSearchPageMockup } from "@/components/calculator-mockups";
export const metadata: Metadata = {
- title: "Calculators Search Page Mockup - Clinical KB",
+ title: "Calculators Search Page Mockup - PsychSift",
description:
- "Search-results-shell psychiatry calculators page listing every calculator as a tile with a domain rail and popup scoring for Clinical KB.",
+ "Search-results-shell psychiatry calculators page listing every calculator as a tile with a domain rail and popup scoring for PsychSift.",
};
export default function CalculatorsSearchPageMockupRoute() {
diff --git a/src/app/mockups/calculators-search/page.tsx b/src/app/mockups/calculators-search/page.tsx
index 804b0a21d..f80b6dc1a 100644
--- a/src/app/mockups/calculators-search/page.tsx
+++ b/src/app/mockups/calculators-search/page.tsx
@@ -3,9 +3,9 @@ import type { Metadata } from "next";
import { CalculatorsSearchDetailMockup } from "@/components/calculator-mockups";
export const metadata: Metadata = {
- title: "Calculators Search Mockup - Clinical KB",
+ title: "Calculators Search Mockup - PsychSift",
description:
- "Search-first psychiatry calculators page with individual calculator detail view and score-linked next clinical actions for Clinical KB.",
+ "Search-first psychiatry calculators page with individual calculator detail view and score-linked next clinical actions for PsychSift.",
};
export default function CalculatorsSearchMockupRoute() {
diff --git a/src/app/mockups/calculators-show-all/page.tsx b/src/app/mockups/calculators-show-all/page.tsx
index 2fb4a04a2..98e907d10 100644
--- a/src/app/mockups/calculators-show-all/page.tsx
+++ b/src/app/mockups/calculators-show-all/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { CalculatorsShowAllDirectionsMockup } from "@/components/calculator-mockups";
export const metadata: Metadata = {
- title: "Calculators Show all buttons - Clinical KB",
+ title: "Calculators Show all buttons - PsychSift",
description:
"Recommended Show all chip plus two polished phone alternatives. The homes are identical except the chip.",
};
diff --git a/src/app/mockups/care-plan/page.tsx b/src/app/mockups/care-plan/page.tsx
index f8890508e..1cffe3e42 100644
--- a/src/app/mockups/care-plan/page.tsx
+++ b/src/app/mockups/care-plan/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { CarePlanRoutePage } from "./route-page";
export const metadata: Metadata = {
- title: "Care Plan prototype · Clinical KB",
+ title: "Care Plan prototype · PsychSift",
description: "A fully synthetic, memory-only prototype for continuity planning in recurrent emergency care.",
};
diff --git a/src/app/mockups/caring-contacts/page.tsx b/src/app/mockups/caring-contacts/page.tsx
index 5ce20c921..fa6c583b7 100644
--- a/src/app/mockups/caring-contacts/page.tsx
+++ b/src/app/mockups/caring-contacts/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { CaringContactRoutePage } from "./route-page";
export const metadata: Metadata = {
- title: "Caring Contact prototype · Clinical KB",
+ title: "Caring Contact prototype · PsychSift",
description: "A fully synthetic, one-way Caring Contact coordination prototype.",
};
diff --git a/src/app/mockups/development/clinical-trust/page.tsx b/src/app/mockups/development/clinical-trust/page.tsx
index 57988e86b..2079031bf 100644
--- a/src/app/mockups/development/clinical-trust/page.tsx
+++ b/src/app/mockups/development/clinical-trust/page.tsx
@@ -5,7 +5,7 @@ import { ArrowLeft } from "lucide-react";
import { ClinicalTrustCockpit } from "@/components/developer-area/clinical-trust-cockpit";
export const metadata: Metadata = {
- title: "Clinical trust · Developer · Clinical KB",
+ title: "Clinical trust · Developer · PsychSift",
description: "Administrator-only quality feedback, source-impact, and content-maturity evidence.",
};
diff --git a/src/app/mockups/development/documentation/page.tsx b/src/app/mockups/development/documentation/page.tsx
index dc6f4cab6..6d47c6841 100644
--- a/src/app/mockups/development/documentation/page.tsx
+++ b/src/app/mockups/development/documentation/page.tsx
@@ -15,7 +15,7 @@ import {
} from "@/lib/developer-area/repo-awareness-snapshot";
export const metadata: Metadata = {
- title: "Documentation · Developer · Clinical KB",
+ title: "Documentation · Developer · PsychSift",
description: "Every committed document, its area of the repository, and whether the docs index lists it.",
};
diff --git a/src/app/mockups/development/ingestion/page.tsx b/src/app/mockups/development/ingestion/page.tsx
index a66abf073..79a40885f 100644
--- a/src/app/mockups/development/ingestion/page.tsx
+++ b/src/app/mockups/development/ingestion/page.tsx
@@ -5,7 +5,7 @@ import { PanelPageShell } from "@/components/developer-area/hub/panel-page-shell
import { resolveLiveFreshness } from "@/lib/developer-area/freshness";
export const metadata: Metadata = {
- title: "Ingestion · Developer · Clinical KB",
+ title: "Ingestion · Developer · PsychSift",
description: "Whether an uploaded document actually indexed — queued, processing, finished, or stuck — read live.",
};
diff --git a/src/app/mockups/development/ledger/page.tsx b/src/app/mockups/development/ledger/page.tsx
index 32fed581b..130f4ece5 100644
--- a/src/app/mockups/development/ledger/page.tsx
+++ b/src/app/mockups/development/ledger/page.tsx
@@ -12,7 +12,7 @@ import {
} from "@/lib/developer-area/ledger-snapshot";
export const metadata: Metadata = {
- title: "Task ledger · Developer · Clinical KB",
+ title: "Task ledger · Developer · PsychSift",
description: "Every outstanding task, recommendation and issue, read from the committed ledger snapshot.",
};
diff --git a/src/app/mockups/development/page.tsx b/src/app/mockups/development/page.tsx
index 4d1b1d9e3..5ff711fed 100644
--- a/src/app/mockups/development/page.tsx
+++ b/src/app/mockups/development/page.tsx
@@ -10,7 +10,7 @@ import { loadLedgerSnapshot } from "@/lib/developer-area/ledger-snapshot";
import { resolveDeploymentCommitSha } from "@/lib/observability/sentry-release";
export const metadata: Metadata = {
- title: "Developer · Clinical KB",
+ title: "Developer · PsychSift",
description: "In-progress surfaces and repository state, reachable only to a signed-in administrator account.",
};
diff --git a/src/app/mockups/development/review-state/page.tsx b/src/app/mockups/development/review-state/page.tsx
index 1ce04a9a7..8d153b48f 100644
--- a/src/app/mockups/development/review-state/page.tsx
+++ b/src/app/mockups/development/review-state/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { ReviewStatePageContent } from "@/components/developer-area/hub/review-state-page-content";
export const metadata: Metadata = {
- title: "Review state · Developer · Clinical KB",
+ title: "Review state · Developer · PsychSift",
description: "Every immutable review record: which ref was reviewed, at which head, with what outcome.",
};
diff --git a/src/app/mockups/development/routes/page.tsx b/src/app/mockups/development/routes/page.tsx
index f8b3c12dd..b0718db3d 100644
--- a/src/app/mockups/development/routes/page.tsx
+++ b/src/app/mockups/development/routes/page.tsx
@@ -12,7 +12,7 @@ import { PanelPageShell } from "@/components/developer-area/hub/panel-page-shell
import { loadRepoAwarenessSnapshot, resolveRepoFreshness } from "@/lib/developer-area/repo-awareness-snapshot";
export const metadata: Metadata = {
- title: "Routes and modes · Developer · Clinical KB",
+ title: "Routes and modes · Developer · PsychSift",
description: "Every page route, redirect, API route and app mode, read from the committed repository snapshot.",
};
diff --git a/src/app/mockups/development/test-health/page.tsx b/src/app/mockups/development/test-health/page.tsx
index 78e4b2a55..7e2fbb566 100644
--- a/src/app/mockups/development/test-health/page.tsx
+++ b/src/app/mockups/development/test-health/page.tsx
@@ -6,7 +6,7 @@ import { QuarantineList } from "@/components/developer-area/hub/quarantine-list"
import { loadRepoAwarenessSnapshot, resolveRepoFreshness } from "@/lib/developer-area/repo-awareness-snapshot";
export const metadata: Metadata = {
- title: "Test health · Developer · Clinical KB",
+ title: "Test health · Developer · PsychSift",
description: "Quarantined tests, why each was quarantined, and when its quarantine lapses.",
};
diff --git a/src/app/mockups/document-navigation-contract/page.tsx b/src/app/mockups/document-navigation-contract/page.tsx
index 3739903c5..9a824d919 100644
--- a/src/app/mockups/document-navigation-contract/page.tsx
+++ b/src/app/mockups/document-navigation-contract/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { DocumentNavigationContractMockups } from "@/components/document-navigation-contract-mockups";
export const metadata: Metadata = {
- title: "Document navigation against the chrome contract - Clinical KB",
+ title: "Document navigation against the chrome contract - PsychSift",
description:
"Two complete document-navigation candidates at desktop, tablet, and phone, built to the shipped header and footer behaviour.",
};
diff --git a/src/app/mockups/document-navigation-final-review/page.tsx b/src/app/mockups/document-navigation-final-review/page.tsx
index 72cf0b5b6..038106df6 100644
--- a/src/app/mockups/document-navigation-final-review/page.tsx
+++ b/src/app/mockups/document-navigation-final-review/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { DocumentNavigationFinalReviewMockups } from "@/components/document-navigation-final-review-mockups";
export const metadata: Metadata = {
- title: "Document navigation, final review - Clinical KB",
+ title: "Document navigation, final review - PsychSift",
description:
"Two final document-navigation versions at desktop, tablet, and phone, with every issue from the study resolved.",
};
diff --git a/src/app/mockups/document-navigation-final/page.tsx b/src/app/mockups/document-navigation-final/page.tsx
index 79a9cd047..83c0468ec 100644
--- a/src/app/mockups/document-navigation-final/page.tsx
+++ b/src/app/mockups/document-navigation-final/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { DocumentNavigationFinalMockups } from "@/components/document-navigation-final-mockups";
export const metadata: Metadata = {
- title: "Document navigation, final design - Clinical KB",
+ title: "Document navigation, final design - PsychSift",
description:
"The final document navigation design: segment-track header row and a two-column section grid, at desktop, tablet, and phone.",
};
diff --git a/src/app/mockups/document-navigation-pane/page.tsx b/src/app/mockups/document-navigation-pane/page.tsx
index f3638f10b..77242caf4 100644
--- a/src/app/mockups/document-navigation-pane/page.tsx
+++ b/src/app/mockups/document-navigation-pane/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { DocumentNavigationPaneMockups } from "@/components/document-navigation-pane-mockups";
export const metadata: Metadata = {
- title: "Document navigation pane mockups - Clinical KB",
+ title: "Document navigation pane mockups - PsychSift",
description:
"Three navigation panes anchored to the universal header for the document page, shown on desktop, tablet, and phone.",
};
diff --git a/src/app/mockups/document-navigation-perfected/page.tsx b/src/app/mockups/document-navigation-perfected/page.tsx
index dca4dbdef..7637e5396 100644
--- a/src/app/mockups/document-navigation-perfected/page.tsx
+++ b/src/app/mockups/document-navigation-perfected/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { DocumentNavigationPerfectedMockups } from "@/components/document-navigation-perfected-mockups";
export const metadata: Metadata = {
- title: "Document navigation, perfected - Clinical KB",
+ title: "Document navigation, perfected - PsychSift",
description:
"The final document navigation build, including the phone hide and reveal cycle and documents with fewer sections.",
};
diff --git a/src/app/mockups/document-phone-fused-directions/page.tsx b/src/app/mockups/document-phone-fused-directions/page.tsx
index 89fac1545..9ec47701b 100644
--- a/src/app/mockups/document-phone-fused-directions/page.tsx
+++ b/src/app/mockups/document-phone-fused-directions/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { DocumentPhoneFusedDirectionsMockups } from "@/components/document-phone-fused-directions-mockups";
export const metadata: Metadata = {
- title: "Document phone fused row directions - Clinical KB",
+ title: "Document phone fused row directions - PsychSift",
description: "Three directions built on the fused phone title row for the document page.",
};
diff --git a/src/app/mockups/document-phone-title-refined/page.tsx b/src/app/mockups/document-phone-title-refined/page.tsx
index bb5945ab7..6d54c263f 100644
--- a/src/app/mockups/document-phone-title-refined/page.tsx
+++ b/src/app/mockups/document-phone-title-refined/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { DocumentPhoneTitleRefinedMockups } from "@/components/document-phone-title-refined-mockups";
export const metadata: Metadata = {
- title: "Document phone title refined mockups - Clinical KB",
+ title: "Document phone title refined mockups - PsychSift",
description: "Three corrected variants of the fused phone title row for the document page.",
};
diff --git a/src/app/mockups/document-phone-title/page.tsx b/src/app/mockups/document-phone-title/page.tsx
index 32fe1c767..cb6851249 100644
--- a/src/app/mockups/document-phone-title/page.tsx
+++ b/src/app/mockups/document-phone-title/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { DocumentPhoneTitleMockups } from "@/components/document-phone-title-mockups";
export const metadata: Metadata = {
- title: "Document phone title mockups - Clinical KB",
+ title: "Document phone title mockups - PsychSift",
description: "Three ways to keep the document title visible on a phone alongside the navigation pane.",
};
diff --git a/src/app/mockups/document-phone-zero-chrome/page.tsx b/src/app/mockups/document-phone-zero-chrome/page.tsx
index 404350d27..c037bddbb 100644
--- a/src/app/mockups/document-phone-zero-chrome/page.tsx
+++ b/src/app/mockups/document-phone-zero-chrome/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { DocumentPhoneZeroChromeMockups } from "@/components/document-phone-zero-chrome-mockups";
export const metadata: Metadata = {
- title: "Document phone navigation, zero new chrome - Clinical KB",
+ title: "Document phone navigation, zero new chrome - PsychSift",
description:
"Section navigation on the document page that adds no permanent phone chrome and no second scroll owner.",
};
diff --git a/src/app/mockups/document-search-evidence-lens/page.tsx b/src/app/mockups/document-search-evidence-lens/page.tsx
index b23844c34..3b52a7132 100644
--- a/src/app/mockups/document-search-evidence-lens/page.tsx
+++ b/src/app/mockups/document-search-evidence-lens/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { DocumentSearchMockupPage } from "@/components/document-search-mockups";
export const metadata: Metadata = {
- title: "Document Search Evidence Lens Mockup - Clinical KB",
+ title: "Document Search Evidence Lens Mockup - PsychSift",
description: "Document search evidence lens mockup with selected source proof in view.",
};
diff --git a/src/app/mockups/document-search-triage-board/page.tsx b/src/app/mockups/document-search-triage-board/page.tsx
index 959f58f66..7ee8a9c21 100644
--- a/src/app/mockups/document-search-triage-board/page.tsx
+++ b/src/app/mockups/document-search-triage-board/page.tsx
@@ -3,8 +3,8 @@ import type { Metadata } from "next";
import { DocumentSearchMockupPage } from "@/components/document-search-mockups";
export const metadata: Metadata = {
- title: "Document Search Triage Board Mockup - Clinical KB",
- description: "Discovery-first document library triage board mockup for Clinical KB.",
+ title: "Document Search Triage Board Mockup - PsychSift",
+ description: "Discovery-first document library triage board mockup for PsychSift.",
};
export default function DocumentSearchTriageBoardMockupRoute() {
diff --git a/src/app/mockups/document-search/page.tsx b/src/app/mockups/document-search/page.tsx
index c35ddd4b3..23c46c04c 100644
--- a/src/app/mockups/document-search/page.tsx
+++ b/src/app/mockups/document-search/page.tsx
@@ -4,8 +4,8 @@ import { Suspense } from "react";
import { MasterDocumentIndex } from "@/components/master-document-flow-mockups";
export const metadata: Metadata = {
- title: "Document Search Mockups - Clinical KB",
- description: "Master runnable document-search UX flow for Clinical KB document mode.",
+ title: "Document Search Mockups - PsychSift",
+ description: "Master runnable document-search UX flow for PsychSift document mode.",
};
import { DocumentSearchPageSkeleton } from "@/components/mode-home-page-skeleton";
diff --git a/src/app/mockups/document-search/search/page.tsx b/src/app/mockups/document-search/search/page.tsx
index 9e2326423..23b93c236 100644
--- a/src/app/mockups/document-search/search/page.tsx
+++ b/src/app/mockups/document-search/search/page.tsx
@@ -2,7 +2,7 @@ import type { Metadata } from "next";
import { Suspense } from "react";
import { MasterDocumentSearch } from "@/components/master-document-flow-mockups";
-export const metadata: Metadata = { title: "Document Search Mockup - Clinical KB" };
+export const metadata: Metadata = { title: "Document Search Mockup - PsychSift" };
export default function DocumentSearchMockupRoute() {
return (
diff --git a/src/app/mockups/document-search/source-overlays/page.tsx b/src/app/mockups/document-search/source-overlays/page.tsx
index c414d5f96..6ce29ae81 100644
--- a/src/app/mockups/document-search/source-overlays/page.tsx
+++ b/src/app/mockups/document-search/source-overlays/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { SourceOverlayRedesignMockups } from "@/components/source-overlay-redesign-mockups";
export const metadata: Metadata = {
- title: "Source Overlay Redesign Mockups - Clinical KB",
+ title: "Source Overlay Redesign Mockups - PsychSift",
description: "Document scope and source library overlay redesign mockups for desktop and phone.",
};
diff --git a/src/app/mockups/document-search/source/evidence/page.tsx b/src/app/mockups/document-search/source/evidence/page.tsx
index 6d291518d..da34deb83 100644
--- a/src/app/mockups/document-search/source/evidence/page.tsx
+++ b/src/app/mockups/document-search/source/evidence/page.tsx
@@ -4,7 +4,7 @@ import { Suspense } from "react";
import { MasterEvidenceDetail } from "@/components/master-document-flow-mockups";
export const metadata: Metadata = {
- title: "Evidence Detail Mockup - Clinical KB",
+ title: "Evidence Detail Mockup - PsychSift",
description: "Functional evidence object mockup for tables, quotes, images, and source page context.",
};
diff --git a/src/app/mockups/document-search/source/page.tsx b/src/app/mockups/document-search/source/page.tsx
index cb9c3cf34..406d02fdd 100644
--- a/src/app/mockups/document-search/source/page.tsx
+++ b/src/app/mockups/document-search/source/page.tsx
@@ -2,7 +2,7 @@ import type { Metadata } from "next";
import { Suspense } from "react";
import { MasterDocumentReader } from "@/components/master-document-flow-mockups";
-export const metadata: Metadata = { title: "Document Reader Mockup - Clinical KB" };
+export const metadata: Metadata = { title: "Document Reader Mockup - PsychSift" };
export default function DocumentReaderMockupRoute() {
return (
diff --git a/src/app/mockups/document-top-navigation/page.tsx b/src/app/mockups/document-top-navigation/page.tsx
index adb72b4c0..aec4ed915 100644
--- a/src/app/mockups/document-top-navigation/page.tsx
+++ b/src/app/mockups/document-top-navigation/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { DocumentTopNavigationMockups } from "@/components/document-top-navigation-mockups";
export const metadata: Metadata = {
- title: "Document navigation menu mockups - Clinical KB",
+ title: "Document navigation menu mockups - PsychSift",
description: "Three responsive document-page navigation concepts for phone, tablet, and desktop.",
};
diff --git a/src/app/mockups/favourites-phone-perfected/page.tsx b/src/app/mockups/favourites-phone-perfected/page.tsx
index c05030b89..27fa67142 100644
--- a/src/app/mockups/favourites-phone-perfected/page.tsx
+++ b/src/app/mockups/favourites-phone-perfected/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { FavouritesPhonePerfectedMockupsPage } from "@/components/favourites-phone-perfected-mockups";
export const metadata: Metadata = {
- title: "Favourites Phone Perfected Mockup - Clinical KB",
+ title: "Favourites Phone Perfected Mockup - PsychSift",
description: "Phone-first Favourites page mockup drawn across every signed-in state.",
};
diff --git a/src/app/mockups/filter-sheet-restyle/page.tsx b/src/app/mockups/filter-sheet-restyle/page.tsx
index b3cfd2ed3..9b006140c 100644
--- a/src/app/mockups/filter-sheet-restyle/page.tsx
+++ b/src/app/mockups/filter-sheet-restyle/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { FilterSheetRestyleMockupsPage } from "@/components/filter-sheet-restyle-mockups";
export const metadata: Metadata = {
- title: "Filter sheet restyle · three styles - Clinical KB",
+ title: "Filter sheet restyle · three styles - PsychSift",
description:
"Three style directions for the shared filter sheet, drawn on the formulation specimen, with the segmented bar repurposed as a result-scope control.",
};
diff --git a/src/app/mockups/mode-dropdown/page.tsx b/src/app/mockups/mode-dropdown/page.tsx
index e4f4aecaa..7189feacd 100644
--- a/src/app/mockups/mode-dropdown/page.tsx
+++ b/src/app/mockups/mode-dropdown/page.tsx
@@ -179,7 +179,7 @@ export default function ModeDropdownMockupPage() {
- Clinical KB mockup
+ PsychSift mockup
diff --git a/src/app/mockups/phone-inpage-navigation/page.tsx b/src/app/mockups/phone-inpage-navigation/page.tsx
index e3fdfa1ce..955ed1018 100644
--- a/src/app/mockups/phone-inpage-navigation/page.tsx
+++ b/src/app/mockups/phone-inpage-navigation/page.tsx
@@ -497,7 +497,7 @@ export default function PhoneInPageNavigationMockup() {
,
diff --git a/src/app/privacy/page.tsx b/src/app/privacy/page.tsx
index 6d86b037f..675fc0864 100644
--- a/src/app/privacy/page.tsx
+++ b/src/app/privacy/page.tsx
@@ -3,8 +3,8 @@ import type { Metadata } from "next";
import { PrivacyQuietSignalPage } from "@/components/privacy-quiet-signal-page";
export const metadata: Metadata = {
- title: "How Clinical KB handles your data",
- description: "Learn what Clinical KB processes, where data is handled, and how long information is retained.",
+ title: "How PsychSift handles your data",
+ description: "Learn what PsychSift processes, where data is handled, and how long information is retained.",
};
/**
diff --git a/src/app/reference/colour-coding/page.tsx b/src/app/reference/colour-coding/page.tsx
index caa171dd4..633b389a9 100644
--- a/src/app/reference/colour-coding/page.tsx
+++ b/src/app/reference/colour-coding/page.tsx
@@ -6,7 +6,7 @@ import { SHARED_APP_HOME_ROUTE } from "@/lib/reference-routes";
import { cn, searchPageCanvas, searchPageContainer, searchPageShellStandalone } from "@/components/ui-primitives";
export const metadata: Metadata = {
- title: "Colour coding reference — Clinical KB",
+ title: "Colour coding reference — PsychSift",
description:
"The site-wide badge colour system: what each tone means and which signals are flagged in each content area.",
};
diff --git a/src/app/safety-plan/page.tsx b/src/app/safety-plan/page.tsx
index f404cff09..595641214 100644
--- a/src/app/safety-plan/page.tsx
+++ b/src/app/safety-plan/page.tsx
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { PatientSafetyPlan } from "@/components/patient-safety-plan";
export const metadata: Metadata = {
- title: "Safety plan generator - Clinical KB",
+ title: "Safety plan generator - PsychSift",
description:
"Build an identifier-free patient safety plan with the Stanley-Brown six steps in a transient browser session, then export it through an approved clinical workflow.",
};
diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx
index 61c6a20d2..205f0ddf3 100644
--- a/src/components/ClinicalDashboard.tsx
+++ b/src/components/ClinicalDashboard.tsx
@@ -1629,13 +1629,13 @@ function ClinicalDashboardContent({
function searchNetworkFailure(label: string) {
const offline = typeof navigator !== "undefined" && !navigator.onLine;
- const origin = typeof window !== "undefined" ? window.location.origin : "Clinical KB";
+ const origin = typeof window !== "undefined" ? window.location.origin : "PsychSift";
return makeSearchError(
offline
? `${label} could not run because the browser is offline.`
: isDeployedClinicalKb()
- ? `${label} could not reach Clinical KB at ${origin}. Check your connection and try again shortly.`
- : `${label} could not reach Clinical KB at ${origin}. The local server may still be starting or restarting; retry shortly or run npm run ensure.`,
+ ? `${label} could not reach PsychSift at ${origin}. Check your connection and try again shortly.`
+ : `${label} could not reach PsychSift at ${origin}. The local server may still be starting or restarting; retry shortly or run npm run ensure.`,
undefined,
true,
);
diff --git a/src/components/answer-chat-perfected-mockups.tsx b/src/components/answer-chat-perfected-mockups.tsx
index f52c36ed2..3d1990f66 100644
--- a/src/components/answer-chat-perfected-mockups.tsx
+++ b/src/components/answer-chat-perfected-mockups.tsx
@@ -1287,7 +1287,7 @@ export function AnswerChatPerfectedMockupsPage() {
- Clinical KB · answer page · direction A, finished
+ PsychSift · answer page · direction A, finished
diff --git a/src/components/answer-chat-perfected-v2-mockups.tsx b/src/components/answer-chat-perfected-v2-mockups.tsx
index 5110501a3..7c2f9774e 100644
--- a/src/components/answer-chat-perfected-v2-mockups.tsx
+++ b/src/components/answer-chat-perfected-v2-mockups.tsx
@@ -1680,7 +1680,7 @@ export function AnswerChatPerfectedV2MockupsPage() {
- Clinical KB · answer page · direction A, second pass
+ PsychSift · answer page · direction A, second pass
diff --git a/src/components/answer-chat-redesign-mockups.tsx b/src/components/answer-chat-redesign-mockups.tsx
index 941a6b071..d87d833e3 100644
--- a/src/components/answer-chat-redesign-mockups.tsx
+++ b/src/components/answer-chat-redesign-mockups.tsx
@@ -1312,7 +1312,7 @@ export function AnswerChatRedesignMockupsPage() {
diff --git a/src/components/answer-loading-redesign-mockups.tsx b/src/components/answer-loading-redesign-mockups.tsx
index 12b08b08f..f3929bbed 100644
--- a/src/components/answer-loading-redesign-mockups.tsx
+++ b/src/components/answer-loading-redesign-mockups.tsx
@@ -860,7 +860,7 @@ export function AnswerLoadingRedesignMockupsPage() {
- Clinical KB · answer page · the wait
+ PsychSift · answer page · the wait
Direction B shipped
diff --git a/src/components/caring-contacts/mockups/foundation-board.tsx b/src/components/caring-contacts/mockups/foundation-board.tsx
index dfcb2fb88..e354609da 100644
--- a/src/components/caring-contacts/mockups/foundation-board.tsx
+++ b/src/components/caring-contacts/mockups/foundation-board.tsx
@@ -17,7 +17,7 @@ export function FoundationBoard() {
diff --git a/src/components/caring-contacts/workspace/unavailable-destination.tsx b/src/components/caring-contacts/workspace/unavailable-destination.tsx
index ea2bc9d05..207d4be2b 100644
--- a/src/components/caring-contacts/workspace/unavailable-destination.tsx
+++ b/src/components/caring-contacts/workspace/unavailable-destination.tsx
@@ -42,7 +42,7 @@ export type UnavailableDestinationProps = {
*
* What actually holds Ruling 13 is the MODULE BOUNDARY, which does not decay:
* nothing outside the `/caring-contacts` route segment imports this workspace —
- * the tools catalogue names it by href, never by import — so the Clinical KB
+ * the tools catalogue names it by href, never by import — so the PsychSift
* dashboard references no chunk exclusive to it, whatever this directory grows
* to. A screen that adds no client component of its own therefore adds no client
* payload, and that is the property worth checking, not the number of files.
diff --git a/src/components/clinical-dashboard/brand.tsx b/src/components/clinical-dashboard/brand.tsx
index a3a58f37a..5c16343c4 100644
--- a/src/components/clinical-dashboard/brand.tsx
+++ b/src/components/clinical-dashboard/brand.tsx
@@ -1,20 +1,26 @@
import { cn } from "@/components/ui-primitives";
import {
BRAND_COUNTER_TRANSFORM,
- BRAND_GLYPH_TRANSFORM,
+ BRAND_GLYPH_TRANSFORM_BARE,
BRAND_POINT,
BRAND_STROKE_PATH,
- BRAND_TILE,
BRAND_VIEWBOX,
} from "@/lib/brand-mark";
/**
* Site brand mark: the PsychSift S — two counter-turning strokes divided by one
- * straight cut, with a settled point — on a rounded tile. Colours come from the
- * clinical accent tokens so the mark adapts to light/dark/forced colors.
- * Geometry is the single source in `@/lib/brand-mark` (shared with app/icon.svg
- * and the app-icon image routes). Size it via className (h-10 w-10 expanded
- * sidebar, h-7 w-7 collapsed rail).
+ * straight cut, with a settled point.
+ *
+ * In the app the symbol is drawn on its own, with no tile behind it, so it sits
+ * directly on the page ground and reads as a mark rather than as an app-store
+ * tile pasted into the chrome. The tiled form still exists, but only where a
+ * ground has to be painted because the format has no transparency to fall back
+ * on: the .ico, the Apple touch icon and the PWA raster icons.
+ *
+ * The colour is the clinical accent token, so the mark follows light, dark and
+ * forced-colors without a second definition. Geometry is the single source in
+ * `@/lib/brand-mark` (shared with app/icon.svg and the app-icon image routes).
+ * Size it via className (h-10 w-10 expanded sidebar, h-7 w-7 collapsed rail).
*/
export function BrandMark({ className }: { className?: string }) {
return (
@@ -25,15 +31,7 @@ export function BrandMark({ className }: { className?: string }) {
focusable="false"
className={cn("shrink-0", className)}
>
-
-
+
diff --git a/src/components/clinical-dashboard/document-search-unavailable-status.ts b/src/components/clinical-dashboard/document-search-unavailable-status.ts
index 58bf5c775..097c12aca 100644
--- a/src/components/clinical-dashboard/document-search-unavailable-status.ts
+++ b/src/components/clinical-dashboard/document-search-unavailable-status.ts
@@ -20,7 +20,7 @@ export function deriveDocumentSearchUnavailable(input: {
if (input.apiUnavailable) {
return {
message: input.deployedClinicalKb
- ? "Clinical KB could not be reached. Check your connection and try again shortly."
+ ? "PsychSift could not be reached. Check your connection and try again shortly."
: "The local API is unavailable. Check the app server before searching documents.",
status: "error",
};
diff --git a/src/components/clinical-dashboard/guide-content.ts b/src/components/clinical-dashboard/guide-content.ts
index b608583ae..b646e8974 100644
--- a/src/components/clinical-dashboard/guide-content.ts
+++ b/src/components/clinical-dashboard/guide-content.ts
@@ -30,14 +30,14 @@ export type GuideTopic = {
export const guideTopics: readonly GuideTopic[] = [
{
id: "getting-started",
- title: "Getting started with Clinical KB",
+ title: "Getting started with PsychSift",
navLabel: "Getting started",
- summary: "Understand what Clinical KB does and follow the evidence-first workflow from question to source.",
+ summary: "Understand what PsychSift does and follow the evidence-first workflow from question to source.",
sections: [
{
heading: "Use it as a source-backed starting point",
paragraphs: [
- "Clinical KB helps you search indexed clinical documents, review a concise answer, and move quickly to the evidence behind it. It is designed to shorten the path to relevant guidance; it does not replace the original document, local policy, clinical assessment, or professional judgement.",
+ "PsychSift helps you search indexed clinical documents, review a concise answer, and move quickly to the evidence behind it. It is designed to shorten the path to relevant guidance; it does not replace the original document, local policy, clinical assessment, or professional judgement.",
"Begin with one focused question. Add document scope only when the task should use particular guidance. Read the answer as a structured orientation, then follow its citations to the retrieved source passages and original document before applying it.",
],
},
@@ -165,7 +165,7 @@ export const guideTopics: readonly GuideTopic[] = [
{
heading: "Meaning drives colour",
paragraphs: [
- "Clinical KB uses exactly six badge tones. The colour always reflects meaning — never the other way round. Green means current, reviewed, or source-backed; it does not mean clinically safe. Clinical blue means an action to carry out, not verified or trustworthy.",
+ "PsychSift uses exactly six badge tones. The colour always reflects meaning — never the other way round. Green means current, reviewed, or source-backed; it does not mean clinically safe. Clinical blue means an action to carry out, not verified or trustworthy.",
"Badges highlight information for faster scanning. They supplement readable text and never replace contraindications, dosing detail, monitoring requirements, or source provenance.",
],
},
diff --git a/src/components/clinical-dashboard/guide-dialog.tsx b/src/components/clinical-dashboard/guide-dialog.tsx
index c91b0d774..07672140a 100644
--- a/src/components/clinical-dashboard/guide-dialog.tsx
+++ b/src/components/clinical-dashboard/guide-dialog.tsx
@@ -778,7 +778,7 @@ function GuideDialogSession({ onClose }: { onClose: () => void }) {
open
onClose={onClose}
labelledBy={guideAccessibleNameId}
- title="Clinical KB Guide Centre"
+ title="PsychSift Guide Centre"
descriptionContent={
-
- Clinical KB
+ {/* The name leads and the strapline supports, which is a weight and a
+ colour apart, not just a size. The wordmark takes the display
+ tracking the rest of the interface's headings use — at 18px/800 the
+ untracked default reads loose. The strapline drops from 600 to 500:
+ at 600 it sat almost level with the name and the two lines competed.
+ The colour stays --text-muted and the size stays 12px, both measured
+ rather than chosen — on this surface --text-soft composites to
+ #8894a6 and gives 3.07:1 against the header, under the 4.5:1 floor,
+ and 11px made the block bottom-light for no gain. Tracking stays on
+ the ladder's zero step; positive tracking belongs to uppercase
+ labels, and this is a sentence. */}
+
+ PsychSift
-
- Source-backed clinical search
+
+ From question to source
diff --git a/src/components/clinical-dashboard/medication-record-page.tsx b/src/components/clinical-dashboard/medication-record-page.tsx
index f3b3edf90..d58bcf663 100644
--- a/src/components/clinical-dashboard/medication-record-page.tsx
+++ b/src/components/clinical-dashboard/medication-record-page.tsx
@@ -495,7 +495,7 @@ export function MedicationRecordPage({
)}
- Clinical KB provides evidence summaries, not medical advice. Verify clinical decisions.
+ PsychSift provides evidence summaries, not medical advice. Verify clinical decisions.
>
diff --git a/src/components/clinical-dashboard/universal-search-command-surface.tsx b/src/components/clinical-dashboard/universal-search-command-surface.tsx
index 12f269ce3..330619e3c 100644
--- a/src/components/clinical-dashboard/universal-search-command-surface.tsx
+++ b/src/components/clinical-dashboard/universal-search-command-surface.tsx
@@ -391,7 +391,7 @@ function CommandDropdown({
className="flex items-center gap-2 px-3 py-2 text-xs font-semibold text-[color:var(--text-muted)]"
>
- Searching across Clinical KB…
+ Searching across PsychSift…
) : null}
{!hasItems && !universalPending ? (
@@ -752,7 +752,7 @@ export function UniversalSearchCommandSurface({
});
}
- // Cross-entity typeahead ("Across Clinical KB"): live grouped matches from the universal
+ // Cross-entity typeahead ("Across PsychSift"): live grouped matches from the universal
// search endpoint across every domain (including the active mode's own), rendered in the
// server's intent-aware order. Selecting an item navigates straight to the record; each group
// ends with a cross-mode "view all" that re-runs the query in the owning mode. Enter with
diff --git a/src/components/developer-area/hub/panel-card.tsx b/src/components/developer-area/hub/panel-card.tsx
index bad20a1b3..1c697fcb6 100644
--- a/src/components/developer-area/hub/panel-card.tsx
+++ b/src/components/developer-area/hub/panel-card.tsx
@@ -9,6 +9,31 @@ const CARD_CLASS =
"grid min-h-12 gap-1 rounded-xl border border-[color:var(--border)] p-4 text-left focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--focus)]";
export function PanelCard({ panel }: { panel: HubPanel }) {
+ // A static file under `public/` is not an app route, so it gets a real
+ // anchor: would hand it to the client router, which has no entry for
+ // it. It opens in a new tab because it is a reference sheet rather than a
+ // destination inside the hub, and the reason is announced rather than left
+ // to the icon-less visual.
+ if (panel.phase === 1 && panel.href && panel.external) {
+ const noteId = `developer-hub-panel-${panel.id}-newtab`;
+ return (
+
+ {panel.name}
+ {panel.summary}
+
+ Opens in a new tab
+
+
+ );
+ }
+
if (panel.phase === 1 && panel.href) {
return (
diff --git a/src/components/master-document-flow-mockups.tsx b/src/components/master-document-flow-mockups.tsx
index 1afba998e..30faa9b6f 100644
--- a/src/components/master-document-flow-mockups.tsx
+++ b/src/components/master-document-flow-mockups.tsx
@@ -165,7 +165,7 @@ const documents: DocumentFixture[] = [
title: "Psychotropic medications monitoring handbook",
shortTitle: "Psychotropic monitoring handbook",
source: "Reference",
- kind: "Clinical KB Repository",
+ kind: "PsychSift Repository",
version: "v2.1",
status: "Current",
review: "Review 2026",
@@ -184,7 +184,7 @@ const documents: DocumentFixture[] = [
title: "Clozapine: Safe Prescribing Quick Reference",
shortTitle: "Safe prescribing quick reference",
source: "Guideline Summary",
- kind: "Clinical KB Repository",
+ kind: "PsychSift Repository",
version: "v1.4",
status: "Current",
review: "Review 2026",
@@ -203,7 +203,7 @@ const documents: DocumentFixture[] = [
title: "Neutropenia management in clozapine therapy",
shortTitle: "Neutropenia management",
source: "Clinical Review",
- kind: "Clinical KB Repository",
+ kind: "PsychSift Repository",
version: "v1.0",
status: "Review due",
review: "Review 2025",
@@ -222,7 +222,7 @@ const documents: DocumentFixture[] = [
title: "Community mental health protocols",
shortTitle: "Community mental health protocols",
source: "Procedure",
- kind: "Clinical KB Repository",
+ kind: "PsychSift Repository",
version: "v5.0",
status: "Current",
review: "Review 2026",
diff --git a/src/components/patient-safety-plan.tsx b/src/components/patient-safety-plan.tsx
index 7662ef213..451b7a8d5 100644
--- a/src/components/patient-safety-plan.tsx
+++ b/src/components/patient-safety-plan.tsx
@@ -48,7 +48,7 @@ import {
* the app neither stores it nor sends it to a server. Copy and print are
* explicit user-directed exports. Plans start blank; "Load example" can demo
* the layout with sample content that stays non-shareable until edited.
- * Australian English + AU crisis resources throughout, per the Clinical KB
+ * Australian English + AU crisis resources throughout, per the PsychSift
* (en-AU) voice. All chrome is token-driven so light/dark, reduced-motion and
* forced-colors follow the shared design system.
*/
@@ -647,7 +647,7 @@ export function PatientSafetyPlan() {
-
Clinical KB · Clinical tool
+
PsychSift · Clinical tool
Safety plan generator
@@ -773,8 +773,8 @@ export function PatientSafetyPlan() {
Do not enter the patient's name, date of birth, or record number. Enter only the minimum plan
- details and support contacts needed. Working content is kept only in this browser tab; Clinical KB
- does not save it or send it to a server.
+ details and support contacts needed. Working content is kept only in this browser tab; PsychSift does
+ not save it or send it to a server.
@@ -901,7 +901,7 @@ export function PatientSafetyPlan() {
data-print-hide
className="mb-3 rounded-lg border border-[color:var(--border)] bg-[color:var(--surface-subtle)] px-3 py-2 text-2xs font-semibold leading-5 text-[color:var(--text-muted)]"
>
- Copying, printing, or saving a PDF moves the plan outside Clinical KB. Add any patient identifier only after
+ Copying, printing, or saving a PDF moves the plan outside PsychSift. Add any patient identifier only after
export, using your organisation's approved clinical record and handling process.
diff --git a/src/components/privacy-live-signal-perfected-mockups.tsx b/src/components/privacy-live-signal-perfected-mockups.tsx
index d5f7d410a..2b96c2496 100644
--- a/src/components/privacy-live-signal-perfected-mockups.tsx
+++ b/src/components/privacy-live-signal-perfected-mockups.tsx
@@ -72,13 +72,13 @@ const SECTIONS: Section[] = [
heading: "What this tool is",
short: "Tool",
gist: "Clinical reference KB — not a patient-record system",
- body: "Clinical KB is a knowledge base over clinical reference material. It is not a patient-record system and its provider-backed features do not ask for patient identifiers. The Safety Plan Generator accepts sensitive working content and support contacts but deliberately omits a patient-identifier field.",
+ body: "PsychSift is a knowledge base over clinical reference material. It is not a patient-record system and its provider-backed features do not ask for patient identifiers. The Safety Plan Generator accepts sensitive working content and support contacts but deliberately omits a patient-identifier field.",
},
{
heading: "What is collected",
short: "Collected",
gist: "Questions, docs, telemetry — safety-plan work stays in-tab",
- body: "Questions, generated answers, account identifiers, administrator-provided documents, retrieved excerpts, document metadata, and operational or retrieval telemetry may be processed. Free text and source material can contain sensitive information. Safety-plan working content is different: it remains in the current browser tab and is not sent to the application service or stored by Clinical KB.",
+ body: "Questions, generated answers, account identifiers, administrator-provided documents, retrieved excerpts, document metadata, and operational or retrieval telemetry may be processed. Free text and source material can contain sensitive information. Safety-plan working content is different: it remains in the current browser tab and is not sent to the application service or stored by PsychSift.",
},
{
heading: "How questions are handled",
@@ -102,7 +102,7 @@ const SECTIONS: Section[] = [
heading: "Retention",
short: "Retention",
gist: "30-day queries · 90-day logs · hourly cache purge",
- body: "Repository migrations configure 30-day retention for RAG query records, 90-day retention for retrieval logs and query-miss telemetry, and a bounded hourly purge of expired response-cache rows when the database scheduler is available. The operator must verify that those scheduled jobs are active. Administrator-provided documents remain until removed under the applicable process. Safety-plan working content has no Clinical KB retention: it is discarded when the component is cleared or the tab is closed. Clipboard, print, and PDF copies are outside the app and must follow the organisation's approved record-handling process.",
+ body: "Repository migrations configure 30-day retention for RAG query records, 90-day retention for retrieval logs and query-miss telemetry, and a bounded hourly purge of expired response-cache rows when the database scheduler is available. The operator must verify that those scheduled jobs are active. Administrator-provided documents remain until removed under the applicable process. Safety-plan working content has no PsychSift retention: it is discarded when the component is cleared or the tab is closed. Clipboard, print, and PDF copies are outside the app and must follow the organisation's approved record-handling process.",
},
{
heading: "Your responsibilities",
diff --git a/src/components/privacy-page-directions-mockups.tsx b/src/components/privacy-page-directions-mockups.tsx
index 040842091..4087fe056 100644
--- a/src/components/privacy-page-directions-mockups.tsx
+++ b/src/components/privacy-page-directions-mockups.tsx
@@ -33,12 +33,12 @@ const SECTIONS: Section[] = [
{
heading: "What this tool is",
short: "Tool",
- body: "Clinical KB is a knowledge base over clinical reference material. It is not a patient-record system and its provider-backed features do not ask for patient identifiers. The Safety Plan Generator accepts sensitive working content and support contacts but deliberately omits a patient-identifier field.",
+ body: "PsychSift is a knowledge base over clinical reference material. It is not a patient-record system and its provider-backed features do not ask for patient identifiers. The Safety Plan Generator accepts sensitive working content and support contacts but deliberately omits a patient-identifier field.",
},
{
heading: "What is collected",
short: "Collected",
- body: "Questions, generated answers, account identifiers, administrator-provided documents, retrieved excerpts, document metadata, and operational or retrieval telemetry may be processed. Free text and source material can contain sensitive information. Safety-plan working content is different: it remains in the current browser tab and is not sent to the application service or stored by Clinical KB.",
+ body: "Questions, generated answers, account identifiers, administrator-provided documents, retrieved excerpts, document metadata, and operational or retrieval telemetry may be processed. Free text and source material can contain sensitive information. Safety-plan working content is different: it remains in the current browser tab and is not sent to the application service or stored by PsychSift.",
},
{
heading: "How questions are handled",
@@ -58,7 +58,7 @@ const SECTIONS: Section[] = [
{
heading: "Retention",
short: "Retention",
- body: "Repository migrations configure 30-day retention for RAG query records, 90-day retention for retrieval logs and query-miss telemetry, and a bounded hourly purge of expired response-cache rows when the database scheduler is available. The operator must verify that those scheduled jobs are active. Administrator-provided documents remain until removed under the applicable process. Safety-plan working content has no Clinical KB retention: it is discarded when the component is cleared or the tab is closed. Clipboard, print, and PDF copies are outside the app and must follow the organisation's approved record-handling process.",
+ body: "Repository migrations configure 30-day retention for RAG query records, 90-day retention for retrieval logs and query-miss telemetry, and a bounded hourly purge of expired response-cache rows when the database scheduler is available. The operator must verify that those scheduled jobs are active. Administrator-provided documents remain until removed under the applicable process. Safety-plan working content has no PsychSift retention: it is discarded when the component is cleared or the tab is closed. Clipboard, print, and PDF copies are outside the app and must follow the organisation's approved record-handling process.",
},
{
heading: "Your responsibilities",
@@ -85,7 +85,7 @@ const directions: Array<{
name: "Statement theatre",
verdict: "Brand-led first viewport",
summary:
- "First screen is one composition: Clinical KB mark, display title, and a full-bleed amber obligation band — then a calm 68ch reading column. Desktop pins a graphite command rail; phone keeps sticky glass chrome below the notch.",
+ "First screen is one composition: PsychSift mark, display title, and a full-bleed amber obligation band — then a calm 68ch reading column. Desktop pins a graphite command rail; phone keeps sticky glass chrome below the notch.",
strengths: ["Hero reads as brand, not a form", "Obligation is the loudest plane", "Almost no card chrome"],
cost: "Long scroll on phone with no section jump.",
},
@@ -298,7 +298,7 @@ function TheatreFrame({ phone = false }: { phone?: boolean }) {
Privacy & data handling
diff --git a/src/components/privacy-quiet-signal-page.tsx b/src/components/privacy-quiet-signal-page.tsx
index ee473f2e7..cdcd7d712 100644
--- a/src/components/privacy-quiet-signal-page.tsx
+++ b/src/components/privacy-quiet-signal-page.tsx
@@ -245,7 +245,7 @@ export function PrivacyQuietSignalPage() {
{privacyCopy.pageTitle}
- Understand what information Clinical KB handles, where it is processed, how long it is retained, and
+ Understand what information PsychSift handles, where it is processed, how long it is retained, and
what you need to do before using it.
@@ -264,7 +264,7 @@ export function PrivacyQuietSignalPage() {
Coverage
- Applies to every Clinical KB mode
+ Applies to every PsychSift mode
@@ -295,7 +295,7 @@ export function PrivacyQuietSignalPage() {
id="privacy-important-heading"
className="text-2xs font-extrabold uppercase tracking-kicker text-[color:var(--warning-text)]"
>
- Before you use Clinical KB
+ Before you use PsychSift
{PRIVACY_IMPORTANT_SHORT}
diff --git a/src/components/pwa-lifecycle.tsx b/src/components/pwa-lifecycle.tsx
index 6b3c38392..5c2329858 100644
--- a/src/components/pwa-lifecycle.tsx
+++ b/src/components/pwa-lifecycle.tsx
@@ -201,7 +201,7 @@ function InstallBenefits() {
function InstallManualSteps() {
return (
-
- {/* Ward Flow's own identity, not the host application's. This read "Clinical KB /
+ {/* Ward Flow's own identity, not the host application's. This read "PsychSift /
Source-backed clinical search" on every board of a sandboxed synthetic prototype that
does no searching and is not source-backed. Found by looking at a screenshot — every
measurement run against this codebase missed it, because nothing was structurally
diff --git a/src/lib/brand-image.tsx b/src/lib/brand-image.tsx
index 431d9b173..a4c645231 100644
--- a/src/lib/brand-image.tsx
+++ b/src/lib/brand-image.tsx
@@ -4,7 +4,9 @@
// from the in-app mark or the favicon.
import { BRAND_LIGHT, brandMarkSvg, type BrandColors } from "@/lib/brand-mark";
-/** Teal field used behind full-bleed (apple / maskable) icons. */
+/** Opaque field behind full-bleed (apple / maskable) icons. These formats
+ * cannot be transparent, so they paint the light surface the mark stands on
+ * and let the accent-coloured symbol carry the identity. */
export const BRAND_ICON_FIELD = BRAND_LIGHT.tile;
/** Single-colour palette for manifest `monochrome` icons: platforms read only
diff --git a/src/lib/brand-mark.ts b/src/lib/brand-mark.ts
index 661e83776..018321ee8 100644
--- a/src/lib/brand-mark.ts
+++ b/src/lib/brand-mark.ts
@@ -21,8 +21,20 @@ export const BRAND_VIEWBOX = "0 0 512 512";
/** Rounded tile: a corner radius of 3/16 of the side. */
export const BRAND_TILE = { x: 0, y: 0, size: 512, rx: 96 } as const;
-/** Places the 100-unit glyph inside the tile, centred on its ink bounding box. */
-export const BRAND_GLYPH_TRANSFORM = "translate(111.2867 51.2) scale(4.0804)";
+/** Places the 100-unit glyph inside the tile, centred on its ink bounding box,
+ * at 80% of the tile height so the rounded corners keep their margin. */
+export const BRAND_GLYPH_TRANSFORM = "translate(143.1125 51.2) scale(4.0804)";
+
+/** The small-size variant sits wider, because its point is slid out of the
+ * cradle (see BRAND_POINT_SMALL) and so the ink bounding box it is centred on
+ * is 10 units wider. Same scale, different centring. */
+export const BRAND_GLYPH_TRANSFORM_SMALL = "translate(122.7103 51.2) scale(4.0804)";
+
+/** The same glyph with no tile behind it, scaled so its ink fills the box top to
+ * bottom. Used by the in-app mark, where the symbol stands on the page ground
+ * and the surrounding layout — not a tile — provides the breathing room. The
+ * mark therefore occupies exactly the slot the tiled version used to. */
+export const BRAND_GLYPH_TRANSFORM_BARE = "translate(114.8907 0) scale(5.1006)";
/** The upper stroke. Four arcs and the straight cut, meeting at two cusps. */
export const BRAND_STROKE_PATH =
@@ -40,18 +52,36 @@ export const BRAND_STROKE_PATH_SMALL =
* stroke's facing edge exactly onto the lower one; see the brand doc. */
export const BRAND_COUNTER_TRANSFORM = "translate(55.1029 100.3813) scale(-1.07)";
-/** The settled point. */
-export const BRAND_POINT = { cx: 60.4716, cy: 17.3581, r: 10.4586 } as const;
+/** The settled point, cradled in the S's throat. Its centre is exactly the
+ * centre of the throat arc (17.7232 at (44.8724, 20.0286)), so the crescent of
+ * white between the point and the curve that cups it is a constant 7.2646
+ * units all the way round — the same constant-width idea as the straight cut
+ * between the two strokes. Move it off that centre and the crescent starts to
+ * taper. */
+export const BRAND_POINT = { cx: 44.8724, cy: 20.0286, r: 10.4586 } as const;
+
+/** The small-size point: the same circle slid 10 units out of the cradle, so
+ * the crescent opens from 7.26 to 11.55 units and the point still separates
+ * from the S at 20–32 px instead of fusing into it. The counterpart of the
+ * widened cut in BRAND_STROKE_PATH_SMALL, and used by the same surfaces. At
+ * 16 px the crescent is still under two pixels and the two do merge; that is
+ * the size, not the placement. */
+export const BRAND_POINT_SMALL = { cx: 54.8724, cy: 20.0286, r: 10.4586 } as const;
-/** Brand colours per theme. These mirror --clinical-accent and
- * --clinical-accent-contrast per theme in globals.css. They cannot read the
- * tokens (the favicon and the generated PNG icon routes render outside any
- * stylesheet), so they must be re-derived by hand whenever the accent moves —
- * then `npm run brand:update` regenerates app/icon.svg, which
- * `npm run brand:check` verifies in verify:cheap, and the design-token
+/** Brand colours per theme. The symbol carries the colour and the ground stays
+ * out of its way: `ink` mirrors --clinical-accent, and `tile` mirrors the page
+ * ground it sits on (--surface-raised). So on a white page the mark reads as
+ * the bare symbol with no box around it, which is how it is meant to be seen;
+ * the tile exists only because a .ico and a raster app icon have no
+ * transparency to fall back on and must paint some ground.
+ *
+ * These cannot read the tokens (the favicon and the generated PNG icon routes
+ * render outside any stylesheet), so they must be re-derived by hand whenever
+ * the accent moves — then `npm run brand:update` regenerates app/icon.svg,
+ * which `npm run brand:check` verifies in verify:cheap, and the design-token
* contract test fails if they ever disagree with the token. */
-export const BRAND_LIGHT = { tile: "#1d6fb8", ink: "#ffffff" } as const;
-export const BRAND_DARK = { tile: "#74bdf0", ink: "#08203a" } as const;
+export const BRAND_LIGHT = { tile: "#ffffff", ink: "#1d6fb8" } as const;
+export const BRAND_DARK = { tile: "#171b1e", ink: "#74bdf0" } as const;
export type BrandColors = { tile: string; ink: string };
@@ -60,11 +90,15 @@ export type BrandColors = { tile: string; ink: string };
* the exported constants above. */
export function brandMarkInner({ tile, ink }: BrandColors, small = false): string {
const t = BRAND_TILE;
+ // The small-size variant is a set: the widened cut, the point slid out of the
+ // cradle, and the centring that its wider ink box needs. Mixing one with the
+ // other's placement puts the glyph off-centre in the tile.
const stroke = small ? BRAND_STROKE_PATH_SMALL : BRAND_STROKE_PATH;
- const p = BRAND_POINT;
+ const p = small ? BRAND_POINT_SMALL : BRAND_POINT;
+ const place = small ? BRAND_GLYPH_TRANSFORM_SMALL : BRAND_GLYPH_TRANSFORM;
return (
`` +
- `` +
+ `` +
`` +
`` +
`` +
@@ -84,7 +118,7 @@ export function brandMarkSvg(colors: BrandColors = BRAND_LIGHT): string {
* app/icon.svg by scripts/generate-brand-assets.ts (verified in verify:cheap). */
export function brandIconSvg(): string {
const t = BRAND_TILE;
- const p = BRAND_POINT;
+ const p = BRAND_POINT_SMALL;
return `