diff --git a/docs/branch-review-records/2c6a919bc949df279d074bdf810c92f2cb5a090b3bd4b521a833f0baa002e0e3.record.md b/docs/branch-review-records/2c6a919bc949df279d074bdf810c92f2cb5a090b3bd4b521a833f0baa002e0e3.record.md new file mode 100644 index 0000000000..291aa1803d --- /dev/null +++ b/docs/branch-review-records/2c6a919bc949df279d074bdf810c92f2cb5a090b3bd4b521a833f0baa002e0e3.record.md @@ -0,0 +1 @@ +| 2026-08-13 | codex/performance-css-delivery | a324e067d2055fa3e32dd7a039c5e66a62bef3b9 | cold mobile CSS and font delivery | No unresolved findings; review added theme-aware responsive mockup utilities and corrected stale font commentary | build passed (1712 pages); CSS 302113 raw/46203 gzip; contract 2/2; production style 9/9; mockup 15/15; format/issues/ledger passed | diff --git a/docs/branch-review-records/e9ef965f3b9bffc0aef79a3be4d3c206f04207ac0e1b2d8696bb3f657b7df90a.record.md b/docs/branch-review-records/e9ef965f3b9bffc0aef79a3be4d3c206f04207ac0e1b2d8696bb3f657b7df90a.record.md new file mode 100644 index 0000000000..c573ff657c --- /dev/null +++ b/docs/branch-review-records/e9ef965f3b9bffc0aef79a3be4d3c206f04207ac0e1b2d8696bb3f657b7df90a.record.md @@ -0,0 +1 @@ +| 2026-08-13 | codex/performance-css-delivery | aa935df8fa13245af948c4574d791fe31f270d03 | cold mobile CSS and font delivery | No unresolved findings after clean current-main sync; shared header changes pass both production and mockup journeys | production style 9/9; mockup 15/15; contract rerun coordinator-blocked after prior 2/2 pass; no changed-path overlap | diff --git a/docs/outstanding-issues-inbox/66f364c0-5612-449b-9046-94b4dab0b152.json b/docs/outstanding-issues-inbox/66f364c0-5612-449b-9046-94b4dab0b152.json new file mode 100644 index 0000000000..183374266b --- /dev/null +++ b/docs/outstanding-issues-inbox/66f364c0-5612-449b-9046-94b4dab0b152.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "id": "66f364c0-5612-449b-9046-94b4dab0b152", + "createdOn": "2026-08-13", + "action": "update", + "payload": { + "id": "#117", + "summary": "All live mobile routes breach LCP; shared render-blocking CSS and font are the current bottleneck", + "detail": "PR #1915 is merged and deployed at exact Railway SHA ca788d41e1e6b64dc6b9bc63609074d92470d7e7. Three-sample live medians on that SHA are Documents 3611 ms, DSM 3600 ms, Forms 3715 ms, root 3948 ms, Therapy 3543 ms, and Services 3791 ms; desktop LCP is 584-691 ms and CLS is within the mobile rule. Trace attribution shows LCP equals FCP, TTFB is only 267-316 ms, and the shared render-blocking stylesheet plus preloaded 28 KB Geist font dominate cold mobile paint. The follow-up branch removes mockup-only Tailwind vocabulary from production CSS (367,050 to 302,113 raw bytes; 55,140 to 46,152 gzip) while retaining a complete route-only mockup sheet. It keeps the display-swap body font preloaded because two hosted Lighthouse runs showed that removing it delayed text LCP, while the non-LCP mono font remains on-demand. Next: merge/deploy that exact SHA, rerun the complete live matrix, then attribute remaining shared JS/hydration cost if any route still exceeds 2500 ms. Therapy field safety review remains required for search/pathways. INP remains unverified because Lighthouse does not measure it and no usable CrUX result exists. Stop: do not strip clinical fields, weaken the Lighthouse budget, or claim an INP pass.", + "source": "PR #1915; live Web Vitals runs 31704500966 and 31704504389; codex/performance-css-delivery" + } +} diff --git a/docs/outstanding-issues-inbox/f4b9c833-03f4-40bd-9537-90501c1287c4.json b/docs/outstanding-issues-inbox/f4b9c833-03f4-40bd-9537-90501c1287c4.json new file mode 100644 index 0000000000..fd49b9f967 --- /dev/null +++ b/docs/outstanding-issues-inbox/f4b9c833-03f4-40bd-9537-90501c1287c4.json @@ -0,0 +1,10 @@ +{ + "version": 1, + "id": "f4b9c833-03f4-40bd-9537-90501c1287c4", + "createdOn": "2026-08-13", + "action": "cancel", + "payload": { + "requestId": "67f9ce93-caf5-4cd4-89e1-742e61ce882a", + "reason": "Superseded by exact deployed-SHA live measurements and the shared CSS/font remediation." + } +} diff --git a/src/app/globals.css b/src/app/globals.css index 346265a373..e2e1b64419 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,4 +1,9 @@ @import "tailwindcss"; +/* Design-scratch routes have their own route-scoped utility sheet. Keeping + their rapidly growing utility vocabulary out of every production page cuts + the shared render-blocking stylesheet without changing mockup rendering. */ +@source not "./mockups"; +@source not "../components/**/*mockup*"; /* Opt-in v2 design-system token layer. Every rule is scoped to `.ckb-v2`, so importing it cannot change any surface that does not carry the class. */ @import "./ckb-v2-tokens.css"; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 817658f0be..0c8308d27b 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -47,7 +47,7 @@ const geistMono = localFont({ // The mono face is only used deep in the UI (tabular figures, `kbd`, code) and // never in initial/LCP text, so don't preload it on every route — it competes // for the critical-path connection. It still loads on-demand via `swap` when - // first painted. The sans face keeps the default preload. + // first painted, while the body sans face remains preloaded for LCP text. preload: false, }); diff --git a/src/app/mockups/layout.tsx b/src/app/mockups/layout.tsx index ec21ee5a5b..18e038c550 100644 --- a/src/app/mockups/layout.tsx +++ b/src/app/mockups/layout.tsx @@ -5,6 +5,7 @@ import type { ReactNode } from "react"; import { mockupsEnabled } from "@/lib/env"; import { MockupsLayoutClient } from "./mockups-layout-client"; +import "./mockups.css"; // Design-exploration prototypes: shipped for shareability, but never indexed // (belt-and-braces alongside the robots.ts /mockups/ disallow). diff --git a/src/app/mockups/mockups.css b/src/app/mockups/mockups.css new file mode 100644 index 0000000000..7647cdbbff --- /dev/null +++ b/src/app/mockups/mockups.css @@ -0,0 +1,9 @@ +@import "tailwindcss/utilities.css" layer(utilities) source(none); +@reference "../globals.css"; + +/* Re-emit the complete utility vocabulary for mockup routes. This preserves + Tailwind's responsive ordering when a mockup shares shell components with + production. The complete theme-aware sheet retains Tailwind's own base and + responsive ordering without overriding inline theming on later live routes. */ +@source "../"; +@source "../../components"; diff --git a/tests/css-delivery-contract.test.ts b/tests/css-delivery-contract.test.ts new file mode 100644 index 0000000000..033ef023fc --- /dev/null +++ b/tests/css-delivery-contract.test.ts @@ -0,0 +1,30 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; + +const read = (path: string) => readFileSync(resolve(process.cwd(), path), "utf8"); + +describe("cold-load CSS and font delivery", () => { + it("keeps mockup-only Tailwind utilities out of the production global sheet", () => { + const globals = read("src/app/globals.css"); + const mockups = read("src/app/mockups/mockups.css"); + const layout = read("src/app/mockups/layout.tsx"); + + expect(globals).toContain('@source not "./mockups";'); + expect(globals).toContain('@source not "../components/**/*mockup*";'); + expect(mockups).toContain('@import "tailwindcss/utilities.css" layer(utilities) source(none);'); + expect(mockups).not.toMatch(/source\(none\)\s+important/); + expect(mockups).toContain('@reference "../globals.css";'); + expect(mockups).toContain('@source "../";'); + expect(mockups).toContain('@source "../../components";'); + expect(layout).toContain('import "./mockups.css";'); + }); + + it("keeps the display-swap body font preloaded for LCP text", () => { + const rootLayout = read("src/app/layout.tsx"); + const geistSans = rootLayout.slice(rootLayout.indexOf("const geistSans"), rootLayout.indexOf("const geistMono")); + + expect(geistSans).toContain('display: "swap"'); + expect(geistSans).not.toContain("preload: false"); + }); +}); diff --git a/tests/ui-tools-search-mode-mockup.spec.ts b/tests/ui-tools-search-mode-mockup.spec.ts index f2c5cc8dd3..f1870b2a93 100644 --- a/tests/ui-tools-search-mode-mockup.spec.ts +++ b/tests/ui-tools-search-mode-mockup.spec.ts @@ -75,6 +75,23 @@ test.describe("Perfected Tools results mode mockup @mockup", () => { await expectNoHorizontalOverflow(page); }); + test("does not let persisted mockup utilities override live-route inline themes", async ({ page }) => { + const mockup = await gotoMockup(page, 1440); + + await mockup.getByRole("link", { name: "Colour coding reference" }).click(); + await expect(page).toHaveURL(/\/reference\/colour-coding$/); + await expect(page.getByRole("heading", { level: 1, name: "Colour coding reference" })).toBeVisible(); + + const inlineBorderColor = await page.evaluate(() => { + const themedCard = document.createElement("div"); + themedCard.className = "border border-[color:var(--border)]"; + themedCard.style.borderTopColor = "rgb(1, 2, 3)"; + document.body.append(themedCard); + return window.getComputedStyle(themedCard).borderTopColor; + }); + expect(inlineBorderColor).toBe("rgb(1, 2, 3)"); + }); + test("desktop details use inline semantics and preserve visible programmatic focus", async ({ page }) => { const mockup = await gotoMockup(page, 1440); const details = mockup.getByRole("button", { name: "View details for Differentials" });