diff --git a/docs/design-system/GATES.md b/docs/design-system/GATES.md
index ce86429c3..0e654aca2 100644
--- a/docs/design-system/GATES.md
+++ b/docs/design-system/GATES.md
@@ -73,6 +73,29 @@ Canonical role → live utility (TOKENS §6): `--text-xs` → `text-xs`; `--text
`--text-body` → `text-base-minus`; `--text-md` → `text-[length:var(--text-md)]`;
`--text-lg` → `text-xl`; `--text-xl` → `text-2xl`; `--text-hero` → `text-hero`.
+**Step selection map (guidance only — DS-P2-02).** Pick the named step that matches the
+rendered size. The `*-minus` steps sit one notch under the Tailwind default they are
+named for. This table is documentation, not a gate: do not delete type steps, and do
+not add a blocking ESLint rule for which existing step a surface chooses.
+
+| Size | Utility | When to use |
+| ----- | ----------------- | ------------------------------------------------------------------- |
+| 10px | `text-3xs` | Micro floor: dense metadata, legends, count bubbles |
+| 11px | `text-2xs` | Chip compact / secondary labels |
+| 12px | `text-xs` | Tailwind default; Chip `standard` |
+| 13px | `text-sm-minus` | One notch under `text-sm` (14px) — dense body/labels |
+| 14px | `text-sm` | Tailwind default body/label |
+| 15px | `text-base-minus` | One notch under `text-base` (16px) — comfortable body just under 16 |
+| 16px | `text-base` | Tailwind default |
+| 17px | `text-lg-minus` | One notch under `text-lg` (18px) |
+| 18px | `text-lg` | Tailwind default |
+| 20px | `text-xl` | Tailwind default |
+| 22px | `text-2xl-minus` | One notch under `text-2xl` (24px) |
+| 24px | `text-2xl` | Tailwind default |
+| 26px | `text-3xl-minus` | One notch under `text-3xl` (30px) |
+| 30px | `text-3xl` | Tailwind default |
+| fluid | `text-hero` | Mode-home display heading (`clamp`) |
+
⚠️ **The "1 318 call sites" figure this section used to quote was a repo-wide grep including
`src/app/mockups/**`, which every one of these gates excludes** — 1 360 at `7aaf9349c`.
Production consumers of the eight non-standard steps total **705** **[verified: AST class-root
diff --git a/src/components/clinical-dashboard/dashboard-nav.tsx b/src/components/clinical-dashboard/dashboard-nav.tsx
index 58f15da44..b125f01f1 100644
--- a/src/components/clinical-dashboard/dashboard-nav.tsx
+++ b/src/components/clinical-dashboard/dashboard-nav.tsx
@@ -274,7 +274,7 @@ export function MobileSectionFab({
aria-hidden={!open}
inert={!open}
hidden={!open}
- className="fixed z-40 overflow-hidden rounded-lg border border-[color:var(--border-lux)] bg-[color:var(--surface-lux)] text-[color:var(--text)] shadow-[var(--shadow-lux)] ring-1 ring-[color:var(--ring-highlight)] backdrop-blur-md"
+ className="fixed z-40 overflow-hidden rounded-lg border border-[color:var(--border-lux)] bg-[color:var(--surface-lux)] text-[color:var(--text)] shadow-[var(--shadow-lux)] backdrop-blur-md"
style={{
right: "max(0.75rem, env(safe-area-inset-right))",
bottom: "calc(max(0.75rem, env(safe-area-inset-bottom)) + 4.5rem)",
diff --git a/src/components/clinical-dashboard/medication-prescribing-workspace.tsx b/src/components/clinical-dashboard/medication-prescribing-workspace.tsx
index f8025655d..37e2113ad 100644
--- a/src/components/clinical-dashboard/medication-prescribing-workspace.tsx
+++ b/src/components/clinical-dashboard/medication-prescribing-workspace.tsx
@@ -823,7 +823,7 @@ function MedicationResults({
data-medication-cell="action"
className="flex min-w-0 items-start gap-2 pt-0.5 text-sm-minus font-medium leading-5 text-[color:var(--text-heading)]"
>
-
+
{result.action}
{result.href ? (
diff --git a/src/components/document-viewer/document-rail-panels.tsx b/src/components/document-viewer/document-rail-panels.tsx
index 58dec45dd..45a130226 100644
--- a/src/components/document-viewer/document-rail-panels.tsx
+++ b/src/components/document-viewer/document-rail-panels.tsx
@@ -176,7 +176,7 @@ export function DocumentViewerRail({
diff --git a/src/components/sidebar-live-shell.module.css b/src/components/sidebar-live-shell.module.css
index 6b7a0797c..23cf660a6 100644
--- a/src/components/sidebar-live-shell.module.css
+++ b/src/components/sidebar-live-shell.module.css
@@ -50,7 +50,8 @@
.railDivider {
width: 2rem;
height: 1px;
- margin-block: 0.625rem;
+ /* 10px sat between --space-2 (8) and --space-3 (12); snap onto the 4px gap ladder. */
+ margin-block: var(--gap-tight);
flex: none;
background: var(--border);
}
@@ -275,8 +276,11 @@
.shell[data-collapsed="true"] .rail {
width: 5.5rem;
- height: calc(100dvh - 0.25rem);
- margin: 0.125rem 0.4375rem;
+ /* Subtract the full vertical margin (--space-1 top + --space-1 bottom =
+ --space-2) so the border-box height plus margins fits 100dvh exactly. */
+ height: calc(100dvh - var(--space-2));
+ /* 2px 7px sat off the 4px space ladder; snap to --space-1 / --space-2. */
+ margin: var(--space-1) var(--space-2);
padding: var(--radius-lg);
border: 1px solid var(--border);
border-radius: var(--radius-md);
diff --git a/src/components/therapy-compass/screens/brief-screen.tsx b/src/components/therapy-compass/screens/brief-screen.tsx
index 817a0f5fb..392dc29df 100644
--- a/src/components/therapy-compass/screens/brief-screen.tsx
+++ b/src/components/therapy-compass/screens/brief-screen.tsx
@@ -183,14 +183,14 @@ export function BriefScreen() {
className="flex flex-col gap-4 min-w-0"
provenance={`Source: ${t.name} Therapy record · ${durationLabel} intervention · Review status: ${t.reviewStatus === "reviewed" ? "reviewed" : "source review required"}`}
>
-
-
+
+
{t.name}
-
+
{durationLabel} mode
-
+
{t.reviewStatus === "reviewed" ? "Reviewed" : "Clinician review required"}
@@ -206,7 +206,7 @@ export function BriefScreen() {
-
+
-
+
{durationLabel} delivery
@@ -271,7 +271,7 @@ export function BriefScreen() {
{t.clinicianScripts.slice(0, 2).map((c, i) => (
{c.scriptType ? (
-
+
{c.scriptType}
) : null}
@@ -282,27 +282,24 @@ export function BriefScreen() {
) : null}
-
+
Before use
-
+
{CHECKLIST.map((item) => (
-
+
{item}
))}
-
+
Clinical review is required before saving or sharing.
diff --git a/src/components/therapy-compass/screens/compare-screen.tsx b/src/components/therapy-compass/screens/compare-screen.tsx
index 32fe0da78..b98520c66 100644
--- a/src/components/therapy-compass/screens/compare-screen.tsx
+++ b/src/components/therapy-compass/screens/compare-screen.tsx
@@ -128,7 +128,7 @@ export function CompareScreen() {
// which is not something `PageHeader` offers — and should not, since a
// count that grows cannot share a line with a title that wraps.
meta={
-
+
{items.length} of {THERAPY_MAX_COMPARE} selected
}
@@ -190,7 +190,7 @@ export function CompareScreen() {
<>
{/* decision summary */}
-
+
@@ -240,15 +240,15 @@ export function CompareScreen() {
scope="col"
className="min-w-[160px] border-l border-[color:var(--border)] px-5 py-3.5 align-top"
>
-
+
{t.name}
{t.reviewStatus === "reviewed" ? "Reviewed" : "Needs review"}
@@ -389,7 +389,7 @@ function SummaryCell({
}) {
return (
{label}
{value}
diff --git a/src/components/therapy-compass/screens/other-screen.tsx b/src/components/therapy-compass/screens/other-screen.tsx
index 272fe7b5d..1a14f5313 100644
--- a/src/components/therapy-compass/screens/other-screen.tsx
+++ b/src/components/therapy-compass/screens/other-screen.tsx
@@ -48,7 +48,7 @@ export function OtherScreen() {
return (
{/* BUILDER */}
-
+
Therapy
-
-
+
Sections
Toggle what appears on the sheet.
@@ -118,7 +118,7 @@ export function SheetsScreen() {
-
+
@@ -146,10 +146,10 @@ export function SheetsScreen() {
-
+
@@ -170,7 +170,7 @@ export function SheetsScreen() {
{t.bestUsedFor && t.bestUsedFor.length < 70 && !/^(most|the|a |an )/i.test(t.bestUsedFor)
? `A step-by-step plan to help with ${t.bestUsedFor.toLowerCase()}.`
@@ -180,7 +180,7 @@ export function SheetsScreen() {
{b.secAbout && about ? {about} : null}
{b.secSteps && steps.length ? (
-
+
+
+
+
Clinician: ____________________
@@ -285,7 +285,7 @@ export function SheetsScreen() {
function PaperSection({ title, children }: { title: string; children: ReactNode }) {
return (
-
+
setOpen((v) => !v)}
>
-
+
{b.selectedTherapy?.name ?? "Choose a therapy"}
@@ -354,7 +354,7 @@ function TherapyPicker() {
placeholder="Search therapies..."
aria-label="Search therapies for the patient sheet"
autoFocus
- className="w-full h-tap pt-0 pr-3 pb-0 pl-[34px] border border-[color:var(--border)] rounded-md bg-[color:var(--surface)] text-[color:var(--text)] text-sm-minus"
+ className="w-full h-tap pt-0 pr-3 pb-0 pl-8.5 border border-[color:var(--border)] rounded-md bg-[color:var(--surface)] text-[color:var(--text)] text-sm-minus"
/>
diff --git a/src/components/therapy-compass/workspace.tsx b/src/components/therapy-compass/workspace.tsx
index ac27cfdbd..6f9ce142b 100644
--- a/src/components/therapy-compass/workspace.tsx
+++ b/src/components/therapy-compass/workspace.tsx
@@ -15,7 +15,7 @@ import { TherapyCompareTray } from "./therapy-compare-tray";
function TherapyCompassFooter() {
return (
-
+
);
diff --git a/src/components/ui/retrieval-state-banner.tsx b/src/components/ui/retrieval-state-banner.tsx
index fb5dcf8d1..bc21fb5cb 100644
--- a/src/components/ui/retrieval-state-banner.tsx
+++ b/src/components/ui/retrieval-state-banner.tsx
@@ -129,7 +129,7 @@ function StaleEvidenceBody({
data-status={source.status}
className="flex flex-wrap items-center gap-x-2 gap-y-1"
>
-
+
{source.title}
{source.locator ?
{source.locator} : null}
diff --git a/src/lib/medication-records.ts b/src/lib/medication-records.ts
index 28ba5a7fa..e2905395f 100644
--- a/src/lib/medication-records.ts
+++ b/src/lib/medication-records.ts
@@ -111,6 +111,8 @@ export function rowToMedicationRecord(row: MedicationRecordRow): MedicationRecor
class: row.class ?? "",
subclass: row.subclass ?? "",
category: row.category ?? "",
+ // Per-record user colour (Postgres medications.accent default). Stored as a
+ // hex swatch for inline styles; not --clinical-accent (app chrome).
accent: row.accent ?? "#0f766e",
tag: row.tag ?? "",
schedule: row.schedule ?? "",
diff --git a/src/lib/medications.ts b/src/lib/medications.ts
index b80fa0dd6..05d4dd63a 100644
--- a/src/lib/medications.ts
+++ b/src/lib/medications.ts
@@ -86,6 +86,8 @@ export function normalizeRecord(record: MedicationRecord): MedicationRecord {
class: record.class?.trim() ?? "",
subclass: record.subclass?.trim() ?? "",
category: record.category?.trim() ?? "",
+ // Per-record user colour (Postgres medications.accent default). Stored as a
+ // hex swatch for inline styles; not --clinical-accent (app chrome).
accent: record.accent?.trim() || "#0f766e",
tag: record.tag?.trim() ?? "",
schedule: record.schedule?.trim() ?? "",
diff --git a/tests/design-system-contract-utils.test.ts b/tests/design-system-contract-utils.test.ts
index 76f6a7731..04269a6a5 100644
--- a/tests/design-system-contract-utils.test.ts
+++ b/tests/design-system-contract-utils.test.ts
@@ -687,6 +687,28 @@ describe("design-system contract helpers", () => {
expect(reportFailure).toHaveBeenCalledWith("pre-paint theme-color boundary is missing");
});
+ it("masks only the medication accent-default swatch, not other hex in the same file", () => {
+ const reportFailure = vi.fn();
+ const source = ['export const UNRELATED = "#123456";', 'accent: row.accent ?? "#0f766e",'].join("\n");
+ const scoped = rawColorContractSource("src/lib/medication-records.ts", source, reportFailure);
+ expect(scoped).toContain("#123456");
+ expect(scoped).not.toContain("#0f766e");
+ expect(reportFailure).not.toHaveBeenCalled();
+ const meds = rawColorContractSource(
+ "src/lib/medications.ts",
+ 'accent: record.accent?.trim() || "#0f766e",',
+ reportFailure,
+ );
+ expect(meds).not.toContain("#0f766e");
+ });
+
+ it("fails closed when the medication accent-default swatch disappears", () => {
+ const reportFailure = vi.fn();
+ const source = 'export const UNRELATED = "#123456";';
+ expect(rawColorContractSource("src/lib/medications.ts", source, reportFailure)).toBe(source);
+ expect(reportFailure).toHaveBeenCalledWith("medication accent default boundary is missing");
+ });
+
it("fails closed when a fixed-paper factsheet boundary disappears", () => {
const reportFailure = vi.fn();
const source = 'const appChrome = "#123456";';