fix(loading): home loading screen title uses the body face (BUG-1129)

The screen paints before the bundle runs; the serif title pulled 3-4 font
slices onto the critical path next to the first-screen JS.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
Jesse_Chen
2026-10-01 00:06:51 +08:00
co-authored by Claude Opus 5.5
parent 6a74a23093
commit 80ea7b0bc1
3 changed files with 12 additions and 2 deletions
+2 -1
View File
@@ -235,7 +235,8 @@ is read through an external store so a change in one tab reaches the others.
- Mixed headings stay in one face: the slice set carries Latin, so “D10 事业盘怎么读” is serif end to end (the reason Newsreader was rejected in BUG-737 does not apply).
- The stack may name only loadable families (next/font/local, the serif-sc `@font-face` list, or the system-face whitelist) and must not contain `Songti SC`, `STSong`, `SimSun`, `Noto Serif CJK SC` or end in generic `serif` — pinned by `font-stack-loadable-contract.test.ts`. BUG-737 is why: an unloaded serif head sent every CJK heading to SimSun on Windows.
- The `@font-face` list lives in its own file (`serif-sc.css`, ≈22 KB gzip of `unicode-range` data) imported by `src/app/site-styles.ts` next to `globals.css`, so admin never loads it.
- Deliberate sans headings (pinned by `serif-headings-contract.test.ts`): the rectification narrative's `h2`/`h3` (`.conversational-narrative .message-markdown h2, h3`, body face 600), report chart-card titles (`.personal-report-chart-card h3`), all admin UI, and the root boundary pages below. Chat body, buttons, tables, inputs and labels are body text and stay sans.
- Deliberate sans headings (pinned by `serif-headings-contract.test.ts`): the rectification narrative's `h2`/`h3` (`.conversational-narrative .message-markdown h2, h3`, body face 600), report chart-card titles (`.personal-report-chart-card h3`), the home loading screen title (`.app-loading-content strong`, 「正在载入账户 / 正在准备对话」, 2026-09-30, BUG-1129), all admin UI, and the root boundary pages below.
- The loading screen uses the body face only: it paints before the bundle runs, so a serif title would start 3–4 slice downloads (≈130–170 KB) that compete with the first-screen JS. No web font is requested for it before the page `load` event. Chat body, buttons, tables, inputs and labels are body text and stay sans.
- Body/UI: `var(--font-inter, Inter), -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif`. Inter is loaded with `next/font/local` from `src/app/fonts/InterVariable-latin.woff2` (`display: "swap"`, CSS variable `--font-inter`) so Windows/Linux no longer silently fall back past a never-requested Inter, and image builds do not call fonts.googleapis.com. `StyreneB` was removed from the head of this stack for the same reason as Tiempos: it never loaded, so it was dead configuration that made the stack look intentional.
- Code/data: `"JetBrains Mono", "SFMono-Regular", Consolas, monospace`, exposed as `--font-mono`.
- Root boundary pages (`error.tsx`, `not-found.tsx`, `forbidden.tsx`, `global-error.tsx`) sit in the shared root layout segment and must not import `globals.css` — importing it would drag the chat stylesheet onto every admin route. They therefore cannot read `--font-mono` or any token, and inline their own values: a system stack for body text and `ui-monospace, SFMono-Regular, Menlo, monospace` for code. Keep those literals in step with the stacks above by hand. They do not load the heading serif either: their titles stay in the inline sans stack by design (TASK-serif-headings-20260928), not by omission.