@nexus-cortex/server 4.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cortex/agents/AGENT_PROFILE_GUIDE.md +307 -0
- package/.cortex/agents/README.md +268 -0
- package/.cortex/agents/a-frontend-landing-page-designer.md +41 -0
- package/.cortex/agents/autoresearch-agent.md +49 -0
- package/.cortex/agents/code-reviewer.md +63 -0
- package/.cortex/agents/context-research.md +26 -0
- package/.cortex/agents/doc-writer.md +92 -0
- package/.cortex/agents/explore.md +63 -0
- package/.cortex/agents/new-model-api-integrator-analyst.md +41 -0
- package/.cortex/agents/plan.md +109 -0
- package/.cortex/agents/pr-architecture-reviewer.md +77 -0
- package/.cortex/agents/pr-code-quality.md +78 -0
- package/.cortex/agents/pr-implementer.md +50 -0
- package/.cortex/agents/pr-security-auditor.md +62 -0
- package/.cortex/agents/pr-test-writer.md +67 -0
- package/.cortex/agents/refactor.md +118 -0
- package/.cortex/agents/test-writer.md +72 -0
- package/.cortex/agents/web-researcher.md +72 -0
- package/.cortex/bench/tasks/sample-tasks.json +20 -0
- package/.cortex/commands/compare.md +14 -0
- package/.cortex/commands/deps.md +16 -0
- package/.cortex/commands/diff.md +14 -0
- package/.cortex/commands/explain.md +16 -0
- package/.cortex/commands/find-bug.md +13 -0
- package/.cortex/commands/profile.md +15 -0
- package/.cortex/commands/review.md +18 -0
- package/.cortex/commands/search.md +16 -0
- package/.cortex/commands/test.md +15 -0
- package/.cortex/permissions.dev.json +20 -0
- package/.cortex/permissions.example.json +71 -0
- package/.cortex/permissions.prod.json +63 -0
- package/.cortex/permissions.test.json +19 -0
- package/.cortex/skills/autoresearch/SKILL.md +77 -0
- package/.cortex/skills/autoresearch/personas/README.md +45 -0
- package/.cortex/skills/autoresearch/personas/aggressive-refactor.md +25 -0
- package/.cortex/skills/autoresearch/personas/creative.md +29 -0
- package/.cortex/skills/autoresearch/personas/perf-hunter.md +27 -0
- package/.cortex/skills/autoresearch/personas/precise.md +23 -0
- package/.cortex/skills/autoresearch/personas/root-cause.md +26 -0
- package/.cortex/skills/autoresearch/personas/security-auditor.md +29 -0
- package/.cortex/skills/autoresearch/personas/skeptic-reviewer.md +31 -0
- package/.cortex/skills/autoresearch/personas/test-first.md +25 -0
- package/.cortex/skills/best-of-n/SKILL.md +76 -0
- package/.cortex/skills/cortex/SKILL.md +834 -0
- package/.cortex/skills/cortex-bench/SKILL.md +354 -0
- package/.cortex/skills/docx/SKILL.md +83 -0
- package/.cortex/skills/pdf-documents/SKILL.md +297 -0
- package/.cortex/skills/pdf-documents/sections/01-image-acquisition.md +132 -0
- package/.cortex/skills/pdf-documents/sections/02-ai-image-generation.md +274 -0
- package/.cortex/skills/pdf-documents/sections/03-paper-sizes.md +89 -0
- package/.cortex/skills/pdf-documents/sections/04-design-system.md +549 -0
- package/.cortex/skills/pdf-documents/sections/05-css-print-rules.md +135 -0
- package/.cortex/skills/pdf-documents/sections/06-svg-charts.md +100 -0
- package/.cortex/skills/pdf-documents/sections/07-templates.md +224 -0
- package/.cortex/skills/pdf-documents/sections/08-scaled-output.md +164 -0
- package/.cortex/skills/pdf-documents/sections/09-preview-qa.md +66 -0
- package/.cortex/skills/pdf-documents/sections/10-reading-pdfs.md +499 -0
- package/.cortex/skills/pdf-documents/sections/11-form-filling.md +241 -0
- package/.cortex/skills/pptx/SKILL.md +90 -0
- package/.cortex/skills/resume-analyst/SKILL.md +373 -0
- package/.cortex/skills/verify-work/SKILL.md +74 -0
- package/.cortex/skills/xlsx/SKILL.md +101 -0
- package/.cortex/system-messages/messages/WORK_QUALITY.md +159 -0
- package/.cortex/system-messages/registry.json +18 -0
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +13 -0
- package/bin/cortex-daemon.js +47 -0
- package/bin/cortex-server.js +15 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +513 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/cors.d.ts +10 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +11 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/errorHandler.d.ts +10 -0
- package/dist/middleware/errorHandler.d.ts.map +1 -0
- package/dist/middleware/errorHandler.js +15 -0
- package/dist/middleware/errorHandler.js.map +1 -0
- package/dist/routes/approval.d.ts +2 -0
- package/dist/routes/approval.d.ts.map +1 -0
- package/dist/routes/approval.js +96 -0
- package/dist/routes/approval.js.map +1 -0
- package/dist/routes/config.d.ts +2 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +70 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/health.d.ts +2 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +1031 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/mcp.d.ts +2 -0
- package/dist/routes/mcp.d.ts.map +1 -0
- package/dist/routes/mcp.js +251 -0
- package/dist/routes/mcp.js.map +1 -0
- package/dist/routes/messages.d.ts +5 -0
- package/dist/routes/messages.d.ts.map +1 -0
- package/dist/routes/messages.js +136 -0
- package/dist/routes/messages.js.map +1 -0
- package/dist/routes/middleware.d.ts +2 -0
- package/dist/routes/middleware.d.ts.map +1 -0
- package/dist/routes/middleware.js +146 -0
- package/dist/routes/middleware.js.map +1 -0
- package/dist/routes/models.d.ts +2 -0
- package/dist/routes/models.d.ts.map +1 -0
- package/dist/routes/models.js +29 -0
- package/dist/routes/models.js.map +1 -0
- package/dist/routes/permissions.d.ts +2 -0
- package/dist/routes/permissions.d.ts.map +1 -0
- package/dist/routes/permissions.js +253 -0
- package/dist/routes/permissions.js.map +1 -0
- package/dist/routes/pr.d.ts +2 -0
- package/dist/routes/pr.d.ts.map +1 -0
- package/dist/routes/pr.js +222 -0
- package/dist/routes/pr.js.map +1 -0
- package/dist/routes/sessions.d.ts +2 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +628 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/system-messages.d.ts +2 -0
- package/dist/routes/system-messages.d.ts.map +1 -0
- package/dist/routes/system-messages.js +146 -0
- package/dist/routes/system-messages.js.map +1 -0
- package/dist/routes/tools.d.ts +2 -0
- package/dist/routes/tools.d.ts.map +1 -0
- package/dist/routes/tools.js +79 -0
- package/dist/routes/tools.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
# Design System for Print (Frontend Design Adapted for PDF)
|
|
2
|
+
|
|
3
|
+
This section adapts frontend design principles to print documents. The same skills that make a web interface distinctive and polished make a PDF document visually compelling. A research report should look as intentionally designed as a landing page. **Generic AI document aesthetics are just as unacceptable as generic AI web aesthetics.**
|
|
4
|
+
|
|
5
|
+
## Design Thinking — Before Writing ANY HTML
|
|
6
|
+
|
|
7
|
+
Before coding the document, commit to a bold aesthetic direction:
|
|
8
|
+
|
|
9
|
+
1. **Purpose**: What is this document? Who reads it?
|
|
10
|
+
2. **Tone**: Pick a clear direction — not "clean and professional" (that's the default, which means no design):
|
|
11
|
+
- **Editorial / Magazine** — large pull quotes, asymmetric columns, dramatic white space, serif display fonts
|
|
12
|
+
- **Technical / Engineering** — monospace headings, tight grid, minimal color, high information density
|
|
13
|
+
- **Luxury / Refined** — generous margins, thin rules, restrained palette (2 colors max), elegant serif
|
|
14
|
+
- **Bold / Activist** — oversized type, high-contrast colors, full-bleed images, condensed sans-serif
|
|
15
|
+
- **Academic / Scholarly** — two-column body, footnotes, running headers, traditional serif (Garamond, Caslon)
|
|
16
|
+
- **Corporate / Clean** — sans-serif, brand colors, sidebar callouts, consistent iconography
|
|
17
|
+
- **Vintage / Archival** — aged paper tones, decorative borders, ornamental capitals, old-style figures
|
|
18
|
+
- **Data-Dense / Dashboard** — small type, many tables/charts, color-coded sections, maximum content per page
|
|
19
|
+
3. **Differentiation**: What makes this document visually memorable? Commit to ONE signature element.
|
|
20
|
+
4. **Constraints**: Paper size, print vs. screen-only, color vs. grayscale, binding margin.
|
|
21
|
+
|
|
22
|
+
**CRITICAL**: The design direction drives EVERY subsequent CSS decision. Don't bolt on aesthetics after writing content — design first, then fill.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Typography System
|
|
27
|
+
|
|
28
|
+
**NEVER use**: Arial, Inter, Roboto, Calibri, system-ui as the primary font. These are non-decisions. If the document could have been generated by any default template, the typography has failed.
|
|
29
|
+
|
|
30
|
+
### Font Classification Guide
|
|
31
|
+
|
|
32
|
+
**Serif** — strokes have finishing "feet." Best for: body text in long-form print.
|
|
33
|
+
|
|
34
|
+
| Font | Character | Print Size Sweet Spot | Weight Range | Free? |
|
|
35
|
+
|------|-----------|----------------------|-------------|-------|
|
|
36
|
+
| **EB Garamond** | Classical, scholarly, timeless | 10-12pt body | 400-800 | Yes (Google) |
|
|
37
|
+
| **Source Serif Pro** | Modern serif, clean, versatile | 10-12pt body | 200-900 | Yes (Google) |
|
|
38
|
+
| **Playfair Display** | High contrast, dramatic, editorial | 18pt+ display ONLY | 400-900 | Yes (Google) |
|
|
39
|
+
| **Crimson Pro** | Warm, humanist, book-like | 10-12pt body | 200-900 | Yes (Google) |
|
|
40
|
+
| **Libre Baskerville** | British classical, authoritative | 10-14pt body + display | 400-700 | Yes (Google) |
|
|
41
|
+
| **Cormorant Garamond** | Elegant, high contrast, luxury | 14pt+ display preferred | 300-700 | Yes (Google) |
|
|
42
|
+
| **Merriweather** | Screen-optimised but prints well, wide | 10-12pt body | 300-900 | Yes (Google) |
|
|
43
|
+
| **Lora** | Contemporary, calligraphic roots | 10-12pt body | 400-700 | Yes (Google) |
|
|
44
|
+
| **Spectral** | Designed for screen AND print, large x-height | 9-11pt body | 200-800 | Yes (Google) |
|
|
45
|
+
|
|
46
|
+
**Sans-Serif** — no finishing strokes. Best for: headings, captions, technical content.
|
|
47
|
+
|
|
48
|
+
| Font | Character | Print Size Sweet Spot | Weight Range | Free? |
|
|
49
|
+
|------|-----------|----------------------|-------------|-------|
|
|
50
|
+
| **IBM Plex Sans** | Technical, structured, IBM heritage | 9-11pt body, 16pt+ heading | 100-700 | Yes (Google) |
|
|
51
|
+
| **Nunito Sans** | Friendly, rounded, approachable | 10-12pt body | 200-900 | Yes (Google) |
|
|
52
|
+
| **Montserrat** | Geometric, strong, urban | 16pt+ heading preferred | 100-900 | Yes (Google) |
|
|
53
|
+
| **Oswald** | Condensed, bold, impactful | 20pt+ heading ONLY | 200-700 | Yes (Google) |
|
|
54
|
+
| **Barlow** | Slightly condensed, efficient, modern | 9-11pt body | 100-900 | Yes (Google) |
|
|
55
|
+
| **DM Sans** | Geometric, contemporary, clean | 10-12pt body | 100-1000 | Yes (Google) |
|
|
56
|
+
| **Outfit** | Modern geometric, wide weight range | 14pt+ heading, 10pt body | 100-900 | Yes (Google) |
|
|
57
|
+
| **Manrope** | Semi-rounded, tech-forward | 10-12pt body | 200-800 | Yes (Google) |
|
|
58
|
+
|
|
59
|
+
**Monospace** — fixed-width. Best for: code, data, technical specifications.
|
|
60
|
+
|
|
61
|
+
| Font | Character | Print Size Sweet Spot | Free? |
|
|
62
|
+
|------|-----------|----------------------|-------|
|
|
63
|
+
| **JetBrains Mono** | Modern, coding-optimised, ligatures | 8-10pt code, 16pt+ heading | Yes (Google) |
|
|
64
|
+
| **Space Mono** | Retro-futuristic, editorial | 8-10pt code, 14pt+ heading | Yes (Google) |
|
|
65
|
+
| **IBM Plex Mono** | Neutral, technical, wide | 8-10pt code/tables | Yes (Google) |
|
|
66
|
+
| **Fira Code** | Ligatures, developer-favourite | 8-10pt code | Yes (Google) |
|
|
67
|
+
| **Source Code Pro** | Adobe, clean, readable | 8-10pt code | Yes (Google) |
|
|
68
|
+
|
|
69
|
+
**Display / Decorative** — titles and hero text ONLY. Never body text.
|
|
70
|
+
|
|
71
|
+
| Font | Character | Use At | Free? |
|
|
72
|
+
|------|-----------|--------|-------|
|
|
73
|
+
| **Abril Fatface** | Ultra-bold serif, poster style | 28pt+ titles only | Yes (Google) |
|
|
74
|
+
| **Bebas Neue** | All-caps, condensed, loud | 24pt+ titles only | Yes (Google) |
|
|
75
|
+
| **Righteous** | Retro, rounded, playful | 20pt+ titles only | Yes (Google) |
|
|
76
|
+
| **Archivo Black** | Heavy grotesque, powerful | 20pt+ titles only | Yes (Google) |
|
|
77
|
+
| **Yeseva One** | Decorative serif, ornamental | 28pt+ titles only | Yes (Google) |
|
|
78
|
+
|
|
79
|
+
### Font Selection Decision Framework
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
STEP 1: What is the document's reading context?
|
|
83
|
+
Long-form reading (>5 pages) → Serif body (EB Garamond, Source Serif Pro, Crimson Pro)
|
|
84
|
+
Short-form / scannable (1-3 pg) → Sans-serif body (IBM Plex Sans, Barlow, DM Sans)
|
|
85
|
+
Technical / data-heavy → Sans-serif + monospace for data
|
|
86
|
+
Code documentation → Monospace body, sans-serif headings
|
|
87
|
+
|
|
88
|
+
STEP 2: What tone?
|
|
89
|
+
Authority / tradition → classical serifs (Garamond, Baskerville)
|
|
90
|
+
Innovation / tech → geometric sans (Montserrat, DM Sans)
|
|
91
|
+
Warmth / approachability → humanist sans (Nunito Sans) or soft serif (Lora)
|
|
92
|
+
Urgency / impact → condensed sans (Oswald, Barlow Condensed)
|
|
93
|
+
Elegance / luxury → high-contrast serif (Cormorant Garamond, Playfair Display)
|
|
94
|
+
|
|
95
|
+
STEP 3: Pair display + body
|
|
96
|
+
RULE: Maximum contrast between display and body font.
|
|
97
|
+
- Serif display + sans-serif body (classic editorial)
|
|
98
|
+
- Sans-serif display + serif body (modern contrast)
|
|
99
|
+
- Heavy weight display + light weight body (same family OK)
|
|
100
|
+
NEVER: Two decorative fonts. Two very similar sans-serifs. Same weight for both.
|
|
101
|
+
|
|
102
|
+
STEP 4: Verify at target print size
|
|
103
|
+
- Body readable at 10-11pt in a full paragraph?
|
|
104
|
+
- Headings have enough visual weight?
|
|
105
|
+
- Captions legible at 8-9pt?
|
|
106
|
+
- Numbers align in columns? (use tabular-nums)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Font Weight Usage Guide
|
|
110
|
+
|
|
111
|
+
```css
|
|
112
|
+
:root {
|
|
113
|
+
--weight-light: 300; /* large display text, pull quotes */
|
|
114
|
+
--weight-regular: 400; /* body text, default */
|
|
115
|
+
--weight-medium: 500; /* subtitles, navigation, table headers */
|
|
116
|
+
--weight-semibold: 600; /* h3, emphasis, sidebar headings */
|
|
117
|
+
--weight-bold: 700; /* h1, h2, strong emphasis */
|
|
118
|
+
--weight-heavy: 800; /* cover title, hero text */
|
|
119
|
+
--weight-black: 900; /* poster titles, decorative ONLY */
|
|
120
|
+
}
|
|
121
|
+
/* PRINT RULE: avoid 100-200 weights at body size (too thin to print cleanly) */
|
|
122
|
+
/* PRINT RULE: avoid 900 weight below 20pt (fills in at small sizes) */
|
|
123
|
+
/* PRINT RULE: use 400-600 range for body text — most readable */
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Line Height and Letter Spacing for Print
|
|
127
|
+
|
|
128
|
+
```css
|
|
129
|
+
/* Line height (print-optimised — wider than screen) */
|
|
130
|
+
body { line-height: 1.55-1.7; }
|
|
131
|
+
h1 { line-height: 1.1-1.2; }
|
|
132
|
+
h2 { line-height: 1.2-1.3; }
|
|
133
|
+
caption, figcaption { line-height: 1.4; }
|
|
134
|
+
table td { line-height: 1.3; }
|
|
135
|
+
blockquote { line-height: 1.6-1.8; }
|
|
136
|
+
|
|
137
|
+
/* Letter spacing */
|
|
138
|
+
body { letter-spacing: normal; } /* NEVER touch body */
|
|
139
|
+
h1 { letter-spacing: -0.02em; } /* large text: tighten */
|
|
140
|
+
.all-caps { letter-spacing: 0.12em; text-transform: uppercase; } /* caps MUST be tracked */
|
|
141
|
+
table th { letter-spacing: 0.03em; }
|
|
142
|
+
/* NEVER: letter-space body text. It destroys word shapes. */
|
|
143
|
+
/* ALWAYS: letter-space ALL CAPS text. Caps without tracking looks cramped. */
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Print-Optimised Font Pairing Patterns
|
|
147
|
+
|
|
148
|
+
| Direction | Display Font | Body Font | Why It Works |
|
|
149
|
+
|-----------|-------------|-----------|-------------|
|
|
150
|
+
| Editorial | Playfair Display | Source Serif Pro | High contrast display + readable body |
|
|
151
|
+
| Technical | JetBrains Mono | IBM Plex Sans | Monospace authority + clean body |
|
|
152
|
+
| Luxury | Cormorant Garamond | Lato Light | Elegant + readable light weight |
|
|
153
|
+
| Bold | Oswald | Nunito Sans | Condensed impact + friendly body |
|
|
154
|
+
| Academic | EB Garamond | EB Garamond | Single family, weight contrast |
|
|
155
|
+
| Corporate | Montserrat | Open Sans | Geometric headers + neutral body |
|
|
156
|
+
| Vintage | Libre Baskerville | Crimson Pro | Period-appropriate pairing |
|
|
157
|
+
| Data-Dense | Space Mono | Inter Tight | Tabular monospace + compact body |
|
|
158
|
+
| Government | Libre Baskerville | Spectral | Authoritative + high legibility |
|
|
159
|
+
| Medical | DM Sans | Source Serif Pro | Clean modern + readable long-form |
|
|
160
|
+
| Creative | Abril Fatface | Barlow | Ultra-bold impact + efficient body |
|
|
161
|
+
| Financial | Montserrat | IBM Plex Sans + IBM Plex Mono | Geometric + tabular data |
|
|
162
|
+
|
|
163
|
+
### Font Libraries and Sources
|
|
164
|
+
|
|
165
|
+
| Library | Fonts Available | License | How to Use |
|
|
166
|
+
|---------|----------------|---------|------------|
|
|
167
|
+
| **Google Fonts** | 1,700+ families | Open source (SIL OFL / Apache) | `@import url('https://fonts.googleapis.com/css2?family=...')` |
|
|
168
|
+
| **Adobe Fonts** | 25,000+ families | Creative Cloud subscription | Web font embed code |
|
|
169
|
+
| **Font Squirrel** | 1,000+ families | 100% free commercial | Download .woff2, self-host |
|
|
170
|
+
| **Fontsource** | 1,700+ (mirrors Google) | Open source | `npm install @fontsource/font-name` |
|
|
171
|
+
| **Bunny Fonts** | 1,400+ (Google mirror) | Privacy-first, GDPR-safe | `fonts.bunny.net/css?family=...` |
|
|
172
|
+
| **The League of Moveable Type** | ~20 curated | Open source | Download, high quality |
|
|
173
|
+
| **Velvetyne Type Foundry** | 40+ display | Libre / open source | Download, highly creative |
|
|
174
|
+
| **UNCUT.wtf** | 150+ curated | Various open | Download, curated quality |
|
|
175
|
+
|
|
176
|
+
**Platform fonts:**
|
|
177
|
+
|
|
178
|
+
| Platform | Notable Families |
|
|
179
|
+
|----------|-----------------|
|
|
180
|
+
| **macOS / iOS** | San Francisco, New York, SF Mono, Helvetica Neue, Avenir, Futura, Gill Sans, Garamond, Baskerville, Optima |
|
|
181
|
+
| **Windows** | Segoe UI, Cambria, Calibri, Consolas, Georgia, Palatino Linotype, Book Antiqua, Century |
|
|
182
|
+
| **Linux** | DejaVu, Liberation (metric-compatible), Noto (100+ languages), Ubuntu, Cantarell |
|
|
183
|
+
|
|
184
|
+
**Apple font → open alternative mapping:**
|
|
185
|
+
|
|
186
|
+
| Apple Font | Open Alternative |
|
|
187
|
+
|-----------|-----------------|
|
|
188
|
+
| San Francisco | **Inter** or **DM Sans** |
|
|
189
|
+
| New York | **Source Serif Pro** |
|
|
190
|
+
| SF Mono | **JetBrains Mono** |
|
|
191
|
+
| Helvetica Neue | **Inter** or **Noto Sans** |
|
|
192
|
+
| Avenir | **Nunito Sans** or **Outfit** |
|
|
193
|
+
| Futura | **Jost** |
|
|
194
|
+
| Didot | **Playfair Display** |
|
|
195
|
+
|
|
196
|
+
**Loading fonts for PDF generation:**
|
|
197
|
+
```html
|
|
198
|
+
<style>
|
|
199
|
+
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&family=Source+Serif+Pro:wght@400;600&display=swap');
|
|
200
|
+
</style>
|
|
201
|
+
<!-- IMPORTANT: only load weights you actually use -->
|
|
202
|
+
|
|
203
|
+
<!-- Offline: download .woff2 and self-host -->
|
|
204
|
+
<style>
|
|
205
|
+
@font-face {
|
|
206
|
+
font-family: 'EB Garamond';
|
|
207
|
+
src: url('./fonts/EBGaramond-Regular.woff2') format('woff2');
|
|
208
|
+
font-weight: 400; font-style: normal; font-display: swap;
|
|
209
|
+
}
|
|
210
|
+
</style>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Type Scale for Print (Modular Scale — 1.25 ratio)
|
|
214
|
+
|
|
215
|
+
```css
|
|
216
|
+
:root {
|
|
217
|
+
--type-xs: 8pt; /* footnotes, fine print */
|
|
218
|
+
--type-sm: 9pt; /* captions, table cells */
|
|
219
|
+
--type-base: 11pt; /* body text — MINIMUM for comfortable reading */
|
|
220
|
+
--type-md: 13pt; /* h4, lead paragraphs */
|
|
221
|
+
--type-lg: 16pt; /* h3 */
|
|
222
|
+
--type-xl: 20pt; /* h2 */
|
|
223
|
+
--type-2xl: 26pt; /* h1 */
|
|
224
|
+
--type-3xl: 32pt; /* cover title */
|
|
225
|
+
--type-hero: 48pt; /* poster / banner hero */
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
body { font-size: var(--type-base); line-height: 1.65; }
|
|
229
|
+
h1 { font-size: var(--type-2xl); line-height: 1.15; letter-spacing: -0.02em; }
|
|
230
|
+
h2 { font-size: var(--type-xl); line-height: 1.25; letter-spacing: -0.01em; }
|
|
231
|
+
h3 { font-size: var(--type-lg); line-height: 1.3; }
|
|
232
|
+
figcaption{ font-size: var(--type-sm); line-height: 1.4; }
|
|
233
|
+
.footnote { font-size: var(--type-xs); line-height: 1.4; }
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Modern CSS Typography Features for Print
|
|
237
|
+
|
|
238
|
+
```css
|
|
239
|
+
h1, h2, h3 { text-wrap: balance; } /* no awkward single-word last lines */
|
|
240
|
+
p { text-wrap: pretty; } /* prettier paragraph wrapping */
|
|
241
|
+
body { font-optical-sizing: auto; } /* variable font optical sizing */
|
|
242
|
+
table { font-variant-numeric: tabular-nums; } /* aligned number columns */
|
|
243
|
+
.prose { font-variant-numeric: oldstyle-nums; } /* traditional figures for body */
|
|
244
|
+
p.justified {
|
|
245
|
+
text-align: justify; hyphens: auto;
|
|
246
|
+
hyphenate-limit-chars: 6 3 2;
|
|
247
|
+
}
|
|
248
|
+
body { font-kerning: normal; }
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Color System
|
|
254
|
+
|
|
255
|
+
### The OKLCH Hue Wheel (degrees)
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
0° / 360° = Red 90° = Yellow-Green 180° = Cyan 270° = Blue-Violet
|
|
259
|
+
30° = Orange 120° = Green 210° = Sky Blue 300° = Purple
|
|
260
|
+
60° = Yellow 150° = Teal 250° = Blue 330° = Pink
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Color Harmony Strategies
|
|
264
|
+
|
|
265
|
+
**Monochromatic** — one hue, vary lightness and chroma. Safest, most cohesive. For: professional reports, legal documents.
|
|
266
|
+
```css
|
|
267
|
+
:root {
|
|
268
|
+
--color-dark: oklch(0.25 0.08 250); /* headings */
|
|
269
|
+
--color-mid: oklch(0.45 0.12 250); /* accents */
|
|
270
|
+
--color-light: oklch(0.85 0.04 250); /* backgrounds */
|
|
271
|
+
--color-pale: oklch(0.95 0.02 250); /* table stripes */
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Complementary** — two hues 180° apart. Maximum contrast. For: bold reports, marketing.
|
|
276
|
+
```css
|
|
277
|
+
:root {
|
|
278
|
+
--color-primary: oklch(0.30 0.10 250); /* navy */
|
|
279
|
+
--color-accent: oklch(0.60 0.18 30); /* warm orange */
|
|
280
|
+
}
|
|
281
|
+
/* RULE: dominant at 80%+ area, accent at <20%. */
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Split-Complementary** — one hue + two flanking its complement (±30°). For: editorial, branded reports.
|
|
285
|
+
```css
|
|
286
|
+
:root {
|
|
287
|
+
--color-primary: oklch(0.30 0.10 250);
|
|
288
|
+
--color-accent-1: oklch(0.55 0.18 15);
|
|
289
|
+
--color-accent-2: oklch(0.60 0.15 45);
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Analogous** — 2-3 hues within 60°. Harmonious, calm. For: nature, wellness, understated.
|
|
294
|
+
```css
|
|
295
|
+
:root {
|
|
296
|
+
--color-primary: oklch(0.35 0.10 210);
|
|
297
|
+
--color-mid: oklch(0.45 0.12 180);
|
|
298
|
+
--color-accent: oklch(0.50 0.14 150);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**Triadic** — three hues 120° apart. Vibrant. For: infographics, data viz.
|
|
303
|
+
```css
|
|
304
|
+
:root {
|
|
305
|
+
--color-1: oklch(0.50 0.12 10);
|
|
306
|
+
--color-2: oklch(0.50 0.12 130);
|
|
307
|
+
--color-3: oklch(0.50 0.12 250);
|
|
308
|
+
}
|
|
309
|
+
/* Keep chroma low (0.08-0.15) for print triads. */
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Neutral + Single Accent** — grayscale + one color. Most sophisticated. For: luxury, executive summaries.
|
|
313
|
+
```css
|
|
314
|
+
:root {
|
|
315
|
+
--color-text: oklch(0.20 0.01 0);
|
|
316
|
+
--color-muted: oklch(0.50 0.01 0);
|
|
317
|
+
--color-surface: oklch(0.97 0.005 0);
|
|
318
|
+
--color-accent: oklch(0.55 0.20 15); /* ONE bold accent */
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Accent Color by Subject
|
|
323
|
+
|
|
324
|
+
| Subject | Recommended Hue | OKLCH Example |
|
|
325
|
+
|---------|----------------|---------------|
|
|
326
|
+
| Finance | Navy or Forest Green | `oklch(0.40 0.12 250)` or `oklch(0.40 0.12 145)` |
|
|
327
|
+
| Medical | Teal or Calming Blue | `oklch(0.50 0.14 180)` |
|
|
328
|
+
| Legal | Burgundy or Navy | `oklch(0.40 0.10 15)` |
|
|
329
|
+
| Technology | Electric Blue or Violet | `oklch(0.55 0.18 260)` |
|
|
330
|
+
| Environment | Green or Earth Tones | `oklch(0.45 0.14 140)` |
|
|
331
|
+
| Education | Warm Blue or Amber | `oklch(0.45 0.12 230)` |
|
|
332
|
+
| Creative | Magenta or Deep Purple | `oklch(0.50 0.18 320)` |
|
|
333
|
+
| Maritime | Deep Navy or Sky Blue | `oklch(0.30 0.10 250)` |
|
|
334
|
+
|
|
335
|
+
### OKLCH in CSS
|
|
336
|
+
|
|
337
|
+
```css
|
|
338
|
+
:root {
|
|
339
|
+
--color-primary: oklch(0.45 0.15 250);
|
|
340
|
+
--color-accent: oklch(0.55 0.20 15);
|
|
341
|
+
--color-neutral: oklch(0.20 0.02 250);
|
|
342
|
+
|
|
343
|
+
/* Derived variants */
|
|
344
|
+
--color-primary-light: color-mix(in oklch, var(--color-primary), white 70%);
|
|
345
|
+
--color-primary-muted: color-mix(in oklch, var(--color-primary), white 85%);
|
|
346
|
+
--color-accent-light: color-mix(in oklch, var(--color-accent), white 75%);
|
|
347
|
+
|
|
348
|
+
/* Print-safe grays */
|
|
349
|
+
--color-text: oklch(0.20 0.01 250);
|
|
350
|
+
--color-text-muted: oklch(0.45 0.01 250);
|
|
351
|
+
--color-border: oklch(0.80 0.01 250);
|
|
352
|
+
--color-surface: oklch(0.97 0.005 90);
|
|
353
|
+
|
|
354
|
+
/* Semantic mapping */
|
|
355
|
+
--color-heading: var(--color-primary);
|
|
356
|
+
--color-table-header: var(--color-primary);
|
|
357
|
+
--color-table-stripe: var(--color-primary-light);
|
|
358
|
+
--color-callout-border: var(--color-accent);
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Chart palette (perceptually equidistant):**
|
|
363
|
+
```css
|
|
364
|
+
:root {
|
|
365
|
+
--chart-1: oklch(0.55 0.15 15); /* red */
|
|
366
|
+
--chart-2: oklch(0.55 0.15 75); /* yellow-green */
|
|
367
|
+
--chart-3: oklch(0.55 0.15 145); /* teal */
|
|
368
|
+
--chart-4: oklch(0.55 0.15 210); /* sky blue */
|
|
369
|
+
--chart-5: oklch(0.55 0.15 270); /* violet */
|
|
370
|
+
--chart-6: oklch(0.55 0.15 330); /* pink */
|
|
371
|
+
}
|
|
372
|
+
/* Holding L and C constant while rotating H gives equal visual weight — critical for fair data viz. */
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Print Color Palettes by Direction
|
|
376
|
+
|
|
377
|
+
| Direction | Primary | Accent | Surface | Text |
|
|
378
|
+
|-----------|---------|--------|---------|------|
|
|
379
|
+
| Editorial | `oklch(0.25 0.05 250)` | `oklch(0.55 0.20 15)` | `oklch(0.98 0.005 90)` | `oklch(0.20 0.01 250)` |
|
|
380
|
+
| Technical | `oklch(0.30 0.10 250)` | `oklch(0.60 0.15 145)` | `oklch(0.99 0 0)` | `oklch(0.15 0 0)` |
|
|
381
|
+
| Luxury | `oklch(0.25 0.04 50)` | `oklch(0.65 0.12 80)` | `oklch(0.97 0.01 80)` | `oklch(0.25 0.02 50)` |
|
|
382
|
+
| Bold | `oklch(0.15 0 0)` | `oklch(0.60 0.25 30)` | `oklch(0.99 0 0)` | `oklch(0.15 0 0)` |
|
|
383
|
+
| Academic | `oklch(0.30 0.08 250)` | `oklch(0.45 0.10 30)` | `oklch(0.97 0.005 70)` | `oklch(0.20 0.01 0)` |
|
|
384
|
+
| Vintage | `oklch(0.35 0.06 50)` | `oklch(0.50 0.12 30)` | `oklch(0.93 0.02 70)` | `oklch(0.30 0.04 50)` |
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Spacing System (4pt Base Unit)
|
|
389
|
+
|
|
390
|
+
```css
|
|
391
|
+
:root {
|
|
392
|
+
--space-1: 2pt; --space-2: 4pt; --space-3: 8pt; --space-4: 12pt;
|
|
393
|
+
--space-5: 16pt; --space-6: 24pt; --space-7: 32pt; --space-8: 48pt;
|
|
394
|
+
--space-9: 64pt;
|
|
395
|
+
}
|
|
396
|
+
p { margin-bottom: var(--space-3); }
|
|
397
|
+
h2 { margin-top: var(--space-6); margin-bottom: var(--space-4); }
|
|
398
|
+
h3 { margin-top: var(--space-5); margin-bottom: var(--space-3); }
|
|
399
|
+
table { margin: var(--space-5) 0; }
|
|
400
|
+
figure { margin: var(--space-5) 0; }
|
|
401
|
+
blockquote { padding: var(--space-4) var(--space-5); }
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Visual Texture and Atmosphere
|
|
407
|
+
|
|
408
|
+
```css
|
|
409
|
+
/* Textured cover (CSS gradients — no images) */
|
|
410
|
+
.cover {
|
|
411
|
+
background:
|
|
412
|
+
radial-gradient(circle at 20% 80%, var(--color-primary-light) 0%, transparent 50%),
|
|
413
|
+
radial-gradient(circle at 80% 20%, var(--color-accent-light) 0%, transparent 40%),
|
|
414
|
+
var(--color-surface);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/* Decorative section rules */
|
|
418
|
+
h2::after {
|
|
419
|
+
content: ''; display: block; width: 60px; height: 3px;
|
|
420
|
+
background: var(--color-accent); margin-top: var(--space-2); border-radius: 2px;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/* Pull quotes */
|
|
424
|
+
.pull-quote {
|
|
425
|
+
font-size: var(--type-lg); font-style: italic;
|
|
426
|
+
border-left: 4px solid var(--color-accent); padding-left: var(--space-5);
|
|
427
|
+
margin: var(--space-6) 0; color: var(--color-primary);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/* Drop caps */
|
|
431
|
+
.chapter-opening::first-letter {
|
|
432
|
+
float: left; font-size: 4em; line-height: 0.8; padding-right: 8pt;
|
|
433
|
+
font-weight: 700; color: var(--color-primary);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/* Sidebar callouts */
|
|
437
|
+
.callout {
|
|
438
|
+
background: var(--color-sidebar-bg);
|
|
439
|
+
border-left: 4px solid var(--color-accent);
|
|
440
|
+
border-radius: 0 6px 6px 0;
|
|
441
|
+
padding: var(--space-4) var(--space-5); margin: var(--space-5) 0;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/* Styled tables */
|
|
445
|
+
thead th {
|
|
446
|
+
background: var(--color-table-header); color: white;
|
|
447
|
+
padding: var(--space-3) var(--space-4); font-weight: 600;
|
|
448
|
+
}
|
|
449
|
+
tbody tr:nth-child(even) { background: var(--color-table-stripe); }
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Layout Patterns
|
|
455
|
+
|
|
456
|
+
```css
|
|
457
|
+
/* Two-column with full-width headings */
|
|
458
|
+
.content { column-count: 2; column-gap: 8mm; column-rule: 0.5pt solid var(--color-border); }
|
|
459
|
+
.content h2 { column-span: all; }
|
|
460
|
+
|
|
461
|
+
/* Sidebar layout */
|
|
462
|
+
.section-with-sidebar {
|
|
463
|
+
display: grid; grid-template-columns: 2fr 1fr; gap: var(--space-5);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/* Full-bleed image */
|
|
467
|
+
.full-bleed {
|
|
468
|
+
margin-left: calc(-1 * var(--page-margin));
|
|
469
|
+
margin-right: calc(-1 * var(--page-margin));
|
|
470
|
+
width: calc(100% + 2 * var(--page-margin));
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/* Asymmetric editorial */
|
|
474
|
+
.hero-section { display: grid; grid-template-columns: 1fr 2fr; gap: var(--space-6); align-items: center; }
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Complete Starter Template
|
|
480
|
+
|
|
481
|
+
```html
|
|
482
|
+
<!DOCTYPE html>
|
|
483
|
+
<html lang="en">
|
|
484
|
+
<head>
|
|
485
|
+
<meta charset="UTF-8">
|
|
486
|
+
<title>Document Title</title>
|
|
487
|
+
<style>
|
|
488
|
+
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&family=Source+Serif+Pro:wght@400;600&display=swap');
|
|
489
|
+
|
|
490
|
+
:root {
|
|
491
|
+
--font-display: 'Playfair Display', Georgia, serif;
|
|
492
|
+
--font-body: 'Source Serif Pro', Georgia, serif;
|
|
493
|
+
--font-mono: 'JetBrains Mono', 'Courier New', monospace;
|
|
494
|
+
--type-base: 11pt; --type-lg: 16pt; --type-xl: 20pt;
|
|
495
|
+
--type-2xl: 26pt; --type-hero: 42pt; --type-sm: 9pt; --type-xs: 8pt;
|
|
496
|
+
--color-primary: oklch(0.30 0.08 250);
|
|
497
|
+
--color-accent: oklch(0.55 0.20 15);
|
|
498
|
+
--color-text: oklch(0.20 0.01 250);
|
|
499
|
+
--color-text-muted: oklch(0.45 0.01 250);
|
|
500
|
+
--color-surface: oklch(0.97 0.005 90);
|
|
501
|
+
--color-border: oklch(0.80 0.01 250);
|
|
502
|
+
--color-primary-light: color-mix(in oklch, var(--color-primary), white 85%);
|
|
503
|
+
--sp-1: 2pt; --sp-2: 4pt; --sp-3: 8pt; --sp-4: 12pt;
|
|
504
|
+
--sp-5: 16pt; --sp-6: 24pt; --sp-7: 32pt; --sp-8: 48pt;
|
|
505
|
+
--page-margin: 20mm;
|
|
506
|
+
}
|
|
507
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
508
|
+
body {
|
|
509
|
+
font-family: var(--font-body); font-size: var(--type-base);
|
|
510
|
+
color: var(--color-text); background: var(--color-surface);
|
|
511
|
+
line-height: 1.65; max-width: 800px; margin: 0 auto; padding: 40px 50px;
|
|
512
|
+
}
|
|
513
|
+
p { margin-bottom: var(--sp-3); text-align: justify; text-wrap: pretty; }
|
|
514
|
+
h1, h2, h3, h4 { font-family: var(--font-display); color: var(--color-primary); text-wrap: balance; }
|
|
515
|
+
h1 { font-size: var(--type-2xl); margin: var(--sp-7) 0 var(--sp-5); }
|
|
516
|
+
h2 { font-size: var(--type-xl); margin: var(--sp-6) 0 var(--sp-4);
|
|
517
|
+
border-bottom: 2px solid var(--color-accent); padding-bottom: var(--sp-2); }
|
|
518
|
+
table { width: 100%; border-collapse: collapse; margin: var(--sp-5) 0;
|
|
519
|
+
font-size: var(--type-sm); font-variant-numeric: tabular-nums; }
|
|
520
|
+
thead th { background: var(--color-primary); color: #fff; padding: var(--sp-3) var(--sp-4); }
|
|
521
|
+
tbody td { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--color-border); }
|
|
522
|
+
tbody tr:nth-child(even) { background: var(--color-primary-light); }
|
|
523
|
+
figure { margin: var(--sp-5) 0; text-align: center; }
|
|
524
|
+
figcaption { font-size: var(--type-sm); color: var(--color-text-muted); margin-top: var(--sp-2); font-style: italic; }
|
|
525
|
+
.callout { background: var(--color-primary-light); border-left: 4px solid var(--color-accent);
|
|
526
|
+
padding: var(--sp-4) var(--sp-5); margin: var(--sp-5) 0; border-radius: 0 6px 6px 0; }
|
|
527
|
+
|
|
528
|
+
@page { size: A4; margin: var(--page-margin); }
|
|
529
|
+
@page :first { margin-top: 40mm; }
|
|
530
|
+
@media print {
|
|
531
|
+
body { background: white; padding: 0; max-width: none; }
|
|
532
|
+
h1, h2, h3, h4 { break-after: avoid; }
|
|
533
|
+
table, figure, .chart-container, .callout { break-inside: avoid; }
|
|
534
|
+
tr { break-inside: avoid; }
|
|
535
|
+
thead { display: table-header-group; }
|
|
536
|
+
p { widows: 3; orphans: 3; }
|
|
537
|
+
.cover { break-after: page; }
|
|
538
|
+
a { color: var(--color-text); text-decoration: none; }
|
|
539
|
+
}
|
|
540
|
+
</style>
|
|
541
|
+
</head>
|
|
542
|
+
<body>
|
|
543
|
+
<div class="cover"><!-- Cover page --></div>
|
|
544
|
+
<!-- Document sections -->
|
|
545
|
+
</body>
|
|
546
|
+
</html>
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
**Modify the design tokens aggressively** — changing `--font-display`, `--color-primary`, and `--color-accent` transforms the entire document's personality.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# CSS Print Rules — The Complete Toolkit
|
|
2
|
+
|
|
3
|
+
## Base Template (copy-paste starting point)
|
|
4
|
+
|
|
5
|
+
```css
|
|
6
|
+
/* ── Print Reset ─────────────────────────────────────────── */
|
|
7
|
+
@media print {
|
|
8
|
+
body {
|
|
9
|
+
background: white;
|
|
10
|
+
color: black;
|
|
11
|
+
font-size: 11pt; /* pt not px for print */
|
|
12
|
+
line-height: 1.5;
|
|
13
|
+
max-width: none;
|
|
14
|
+
padding: 0;
|
|
15
|
+
margin: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Hide screen-only elements */
|
|
19
|
+
.no-print, .screen-only, nav, .toolbar { display: none !important; }
|
|
20
|
+
|
|
21
|
+
/* Links: show URL for informational, hide for navigation */
|
|
22
|
+
a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #666; }
|
|
23
|
+
a[href^="#"]::after { content: none; }
|
|
24
|
+
a { color: black; text-decoration: none; }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* ── Page Configuration ──────────────────────────────────── */
|
|
28
|
+
@page {
|
|
29
|
+
size: A4 portrait;
|
|
30
|
+
margin: 20mm 15mm 25mm 15mm; /* top right bottom left */
|
|
31
|
+
|
|
32
|
+
/* Running header/footer (WeasyPrint + Prince; NOT Chromium) */
|
|
33
|
+
@top-center { content: "Document Title"; font-size: 9pt; color: #888; }
|
|
34
|
+
@bottom-right { content: "Page " counter(page) " of " counter(pages); font-size: 8pt; }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* First page: no header, larger top margin for cover */
|
|
38
|
+
@page :first {
|
|
39
|
+
margin-top: 40mm;
|
|
40
|
+
@top-center { content: none; }
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Page Break Control (CRITICAL for quality output)
|
|
45
|
+
|
|
46
|
+
```css
|
|
47
|
+
/* ── GOLDEN RULES ────────────────────────────────────────── */
|
|
48
|
+
|
|
49
|
+
/* 1. NEVER let headings orphan at page bottom */
|
|
50
|
+
h1, h2, h3, h4 {
|
|
51
|
+
break-after: avoid; /* don't break right after a heading */
|
|
52
|
+
page-break-after: avoid; /* legacy fallback */
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* 2. Keep tables, charts, figures together */
|
|
56
|
+
table, figure, .chart-container, svg {
|
|
57
|
+
break-inside: avoid;
|
|
58
|
+
page-break-inside: avoid;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* 3. Force page breaks where you WANT them */
|
|
62
|
+
.page-break { break-before: page; page-break-before: always; }
|
|
63
|
+
.cover { break-after: page; page-break-after: always; }
|
|
64
|
+
|
|
65
|
+
/* 4. Avoid widows and orphans (single lines stranded) */
|
|
66
|
+
p {
|
|
67
|
+
widows: 3; /* min lines at top of new page */
|
|
68
|
+
orphans: 3; /* min lines at bottom before break */
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* 5. For LONG sections that MUST break, remove avoid */
|
|
72
|
+
/* LESSON LEARNED: break-inside:avoid on a section taller than
|
|
73
|
+
one page creates a BLANK page before it. Only use avoid on
|
|
74
|
+
elements shorter than one full page. */
|
|
75
|
+
.timeline-item { break-inside: avoid; } /* individual items OK */
|
|
76
|
+
.timeline { /* NO break-inside:avoid — section is multi-page */ }
|
|
77
|
+
|
|
78
|
+
/* 6. Table rows: keep header visible after break */
|
|
79
|
+
thead { display: table-header-group; } /* repeat header on each page */
|
|
80
|
+
tfoot { display: table-footer-group; }
|
|
81
|
+
tr { break-inside: avoid; page-break-inside: avoid; }
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Common Print Pitfalls and Fixes
|
|
85
|
+
|
|
86
|
+
| Problem | Cause | Fix |
|
|
87
|
+
|---------|-------|-----|
|
|
88
|
+
| **Blank page before section** | `break-inside: avoid` on element taller than page | Remove `avoid` from container; apply to children |
|
|
89
|
+
| **Table split mid-row** | Missing `break-inside: avoid` on `<tr>` | Add `tr { break-inside: avoid; }` |
|
|
90
|
+
| **Heading alone at page bottom** | No `break-after: avoid` on `<h2>` | Add heading break rules |
|
|
91
|
+
| **Background colors missing** | Chromium strips backgrounds by default | Use `--print-background` flag or `color-adjust: exact` |
|
|
92
|
+
| **SVG chart cut in half** | SVG inside a div without `break-inside: avoid` | Wrap SVG in `.chart-container { break-inside: avoid; }` |
|
|
93
|
+
| **Margins too small for binding** | Equal margins all sides | Use asymmetric: `@page :left { margin-left: 25mm; }` |
|
|
94
|
+
| **Dark backgrounds waste ink** | Designed for screen | Use `@media print` to flip to light backgrounds |
|
|
95
|
+
| **Font size too small** | Using `px` (screen) not `pt` (print) | `1pt = 1/72 inch`. Use 10-12pt body, 8-9pt captions |
|
|
96
|
+
| **Images overflow page** | Fixed-width images | `img { max-width: 100%; height: auto; }` |
|
|
97
|
+
| **Code blocks cut off** | Long lines + `overflow: hidden` | `pre { white-space: pre-wrap; word-wrap: break-word; }` |
|
|
98
|
+
|
|
99
|
+
## Named Pages (Mixed Layouts in One Document)
|
|
100
|
+
|
|
101
|
+
```css
|
|
102
|
+
/* Define named page types */
|
|
103
|
+
@page cover-page { size: A4; margin: 0; }
|
|
104
|
+
@page content-page { size: A4; margin: 20mm 15mm 25mm 15mm; }
|
|
105
|
+
@page landscape-page { size: A4 landscape; margin: 15mm; }
|
|
106
|
+
|
|
107
|
+
/* Assign sections to page types */
|
|
108
|
+
.cover { page: cover-page; break-after: page; }
|
|
109
|
+
.content { page: content-page; }
|
|
110
|
+
.wide-table { page: landscape-page; break-before: page; break-after: page; }
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Chromium-Specific Print Flags
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Print with backgrounds (colors, gradients)
|
|
117
|
+
chromium --headless --no-sandbox --disable-gpu \
|
|
118
|
+
--print-to-pdf=output.pdf \
|
|
119
|
+
--print-to-pdf-no-header \
|
|
120
|
+
--run-all-compositor-stages-before-draw \
|
|
121
|
+
input.html
|
|
122
|
+
|
|
123
|
+
# Note: --print-background is implied by --print-to-pdf in modern Chromium
|
|
124
|
+
# The CSS property `color-adjust: exact` forces background printing per-element
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
```css
|
|
128
|
+
/* Force background printing for specific elements */
|
|
129
|
+
.colored-header {
|
|
130
|
+
background: oklch(0.30 0.08 250);
|
|
131
|
+
color: white;
|
|
132
|
+
-webkit-print-color-adjust: exact;
|
|
133
|
+
print-color-adjust: exact;
|
|
134
|
+
}
|
|
135
|
+
```
|