feat(ui): headings use self-hosted Jyotisha Serif SC, body stays sans (T2-T5)

- --font-display leads with "Jyotisha Serif SC", then exactly the body
  sans stack; no system 宋体 or generic serif (BUG-737 guards kept).
- serif-sc.css imported from site-styles.ts beside globals.css (root
  layout also serves admin); swap, no preload.
- Long-form report title (.personal-report-md-article h1) takes the
  heading face; deliberate sans headings pinned by a new contract test.
- font-stack-loadable-contract: loadable now includes self-hosted
  @font-face with existing files; "no CJK serif" replaced by
  "leads with Jyotisha Serif SC, never a system 宋体" (brief T3).
- DESIGN §3, BUG-737 note, CHANGELOG, device checklist, PROGRESS.

TASK-serif-headings-20260928 T2-T5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199rbQDTsUbCVw84wc8BTFe
This commit is contained in:
Jesse_Chen
2026-09-28 19:48:43 +08:00
co-authored by Claude Opus 5.5
parent 308f5502cb
commit 6c421219a1
12 changed files with 374 additions and 30 deletions
+11 -8
View File
@@ -167,14 +167,14 @@
--color-element-water: #d3e6e8;
--shadow-soft: 0 1px 2px rgba(29, 29, 31, .06), 0 8px 20px -18px rgba(29, 29, 31, .2);
--shadow-elevated: 0 1px 2px rgba(29, 29, 31, .07), 0 12px 28px -16px rgba(29, 29, 31, .18);
/* Display and body share one sans stack. The old value led with two Anthropic
licensed faces (Tiempos Headline, StyreneB) that this app never loads — no
@font-face, nothing in public/, and layout.tsx vendors only Inter — so every
CJK heading fell through to Songti SC / SimSun. A Latin-serif-first stack was
measured and rejected: the Newsreader latin subset costs 132 KB to serif one
wordmark, and it splits mixed headings ("D10 事业盘怎么读") into two scripts.
Display rank now comes from weight and tracking, not family. See BUG-737. */
--font-display: var(--font-inter, Inter), -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
/* Headings (display) lead with the self-hosted "Jyotisha Serif SC" — a
sliced Noto Serif SC SemiBold, declared in fonts/serif-sc/serif-sc.css with
font-weight 500 700 and font-display: swap, no preload. Until a slice
arrives, and for any character outside the 6500 it covers, the heading
falls through to the same sans stack as body — never to a system 宋体:
no Songti / STSong / SimSun / generic serif may appear here (BUG-737,
TASK-serif-headings-20260928). Body text stays sans. */
--font-display: "Jyotisha Serif SC", var(--font-inter, Inter), -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
--font-body: var(--font-inter, Inter), -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
--font-mono: "JetBrains Mono", "SFMono-Regular", Consolas, monospace;
--type-display-lg: 48px;
@@ -4118,6 +4118,9 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
overflow-wrap: anywhere;
padding: var(--space-8) var(--space-7) var(--space-10);
}
/* The report title (markdown `#`) is the md view's cover line; it takes the
heading face like the document view's `.personal-report-cover h1`. */
.personal-report-md-article h1 { font-family: var(--font-display); }
.personal-report-md-article h2,
.personal-report-md-article h3 { scroll-margin-top: 80px; }
.personal-report-md-article h2 {
+3
View File
@@ -1,2 +1,5 @@
import "./globals.css";
// Heading face @font-face list, kept out of globals.css (≈18 KB gzip of
// unicode-range data). Loaded wherever globals.css is, never on admin.
import "./fonts/serif-sc/serif-sc.css";
import "./birth-time-choice.css";