/** * Print stylesheet generator. * * Source of truth: .context/designs/make-pdf-print-reference.html and siblings. * Mirror those CSS rules here. The HTML references were approved via * /plan-design-review with explicit design decisions locked in the plan: * * - Helvetica first, with Liberation Sans as a metric-compatible Linux * fallback (Helvetica and Arial aren't installed on most Linux distros; * Liberation Sans ships via the fonts-liberation package and Playwright's * install-deps). No bundled webfonts — dodges the per-glyph Tj bug that * breaks copy-paste extraction. * - All paragraphs flush-left. No first-line indent, no justify, no * p+p indent. text-align: left everywhere. 12pt margin-bottom. * - Cover page has the same 1in margins as every other page. No flexbox * center, no inset padding, no vertical centering. Distinction comes * from eyebrow + larger title + hairline rule, not from centering. * - `@page :first` suppresses running header/footer but does NOT override * the 1in margin. * - No , no external CSS/fonts — everything inlined. * - CJK fallback: Helvetica, Liberation Sans, Arial, Hiragino Kaku Gothic * ProN, Noto Sans CJK JP, Microsoft YaHei, sans-serif. * - Emoji fallback: the body and @top-center running-header stacks end in an * emoji family group ("Apple Color Emoji", "Segoe UI Emoji", "Noto Color * Emoji"), placed BEFORE the generic `sans-serif` so Chromium has a glyph * source for emoji code points instead of emitting .notdef tofu (▯). The * @bottom-* margin boxes hold only counters / a fixed "CONFIDENTIAL" * string, so they get no emoji families. On Linux this requires an * installed color-emoji font — `setup` installs fonts-noto-color-emoji. * * Font stacks are composed from the constants below so each family list has a * single source of truth (DRY) and every stack stays in sync. */ // Metric-compatible sans stack: Helvetica (macOS), Liberation Sans (Linux, // ships via fonts-liberation), Arial (Windows). Shared by every text surface. const SANS_STACK = `Helvetica, "Liberation Sans", Arial`; // CJK fallback families, appended to the body stack only. const CJK_STACK = `"Hiragino Kaku Gothic ProN", "Noto Sans CJK JP", "Microsoft YaHei"`; // Color-emoji families: Apple (macOS), Segoe (Windows), Noto (Linux). const EMOJI_FAMILIES = `"Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji"`; export interface PrintCssOptions { // Document structure cover?: boolean; toc?: boolean; noChapterBreaks?: boolean; // Branding watermark?: string; confidential?: boolean; // Header (running title, top of page) runningHeader?: string; // Page size (in CSS `@page size:` terms) pageSize?: "letter" | "a4" | "legal" | "tabloid"; // Margins (default 1in) margins?: string; // Whether to render "N of M" page numbers in the @page @bottom-center rule. // Default true. Set false to suppress CSS numbering (used when the caller // supplies a custom Chromium footerTemplate, or when --no-page-numbers). pageNumbers?: boolean; } /** * Produce a CSS block (no