portable-agent-layer 0.30.1 → 0.31.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.
Files changed (52) hide show
  1. package/assets/skills/consulting-report/SKILL.md +68 -74
  2. package/assets/skills/consulting-report/demo/app/globals.css +344 -0
  3. package/assets/skills/consulting-report/demo/app/layout.tsx +32 -0
  4. package/assets/skills/consulting-report/demo/app/page.tsx +255 -0
  5. package/assets/skills/consulting-report/demo/bun.lock +240 -0
  6. package/assets/skills/consulting-report/demo/components/callout.tsx +13 -0
  7. package/assets/skills/consulting-report/demo/components/cover-page.tsx +34 -0
  8. package/assets/skills/consulting-report/demo/components/exhibit.tsx +21 -0
  9. package/assets/skills/consulting-report/demo/components/finding-card.tsx +28 -0
  10. package/assets/skills/consulting-report/demo/components/quote-block.tsx +17 -0
  11. package/assets/skills/consulting-report/demo/components/recommendation-card.tsx +52 -0
  12. package/assets/skills/consulting-report/demo/components/section.tsx +16 -0
  13. package/assets/skills/consulting-report/demo/components/severity-badge.tsx +19 -0
  14. package/assets/skills/consulting-report/demo/components/timeline.tsx +20 -0
  15. package/assets/skills/consulting-report/demo/lib/report-data.ts +247 -0
  16. package/assets/skills/consulting-report/demo/lib/utils.ts +6 -0
  17. package/assets/skills/consulting-report/demo/next.config.js +9 -0
  18. package/assets/skills/consulting-report/demo/package.json +27 -0
  19. package/assets/skills/consulting-report/demo/postcss.config.mjs +5 -0
  20. package/assets/skills/consulting-report/demo/tsconfig.json +41 -0
  21. package/assets/skills/consulting-report/template/app/globals.css +344 -0
  22. package/assets/skills/consulting-report/template/app/layout.tsx +32 -0
  23. package/assets/skills/consulting-report/template/app/page.tsx +255 -0
  24. package/assets/skills/consulting-report/template/bun.lock +240 -0
  25. package/assets/skills/consulting-report/template/components/callout.tsx +13 -0
  26. package/assets/skills/consulting-report/template/components/cover-page.tsx +34 -0
  27. package/assets/skills/consulting-report/template/components/exhibit.tsx +21 -0
  28. package/assets/skills/consulting-report/template/components/finding-card.tsx +28 -0
  29. package/assets/skills/consulting-report/template/components/quote-block.tsx +17 -0
  30. package/assets/skills/consulting-report/template/components/recommendation-card.tsx +52 -0
  31. package/assets/skills/consulting-report/template/components/section.tsx +16 -0
  32. package/assets/skills/consulting-report/template/components/severity-badge.tsx +19 -0
  33. package/assets/skills/consulting-report/template/components/timeline.tsx +20 -0
  34. package/assets/skills/consulting-report/template/lib/report-data.ts +176 -0
  35. package/assets/skills/consulting-report/template/lib/utils.ts +6 -0
  36. package/assets/skills/consulting-report/template/next.config.js +9 -0
  37. package/assets/skills/consulting-report/template/package.json +27 -0
  38. package/assets/skills/consulting-report/template/postcss.config.mjs +5 -0
  39. package/assets/skills/consulting-report/template/tsconfig.json +27 -0
  40. package/assets/skills/consulting-report/tools/dev.ts +47 -0
  41. package/assets/skills/consulting-report/tools/generate-pdf.ts +140 -408
  42. package/assets/skills/consulting-report/tools/scaffold.ts +83 -48
  43. package/assets/skills/presentation/SKILL.md +1 -1
  44. package/package.json +9 -9
  45. package/assets/skills/consulting-report/demo/content/current-state.md +0 -33
  46. package/assets/skills/consulting-report/demo/content/executive-summary.md +0 -19
  47. package/assets/skills/consulting-report/demo/content/report-data.ts +0 -101
  48. package/assets/skills/consulting-report/demo/diagrams/.gitkeep +0 -0
  49. package/assets/skills/consulting-report/template/README.md +0 -28
  50. package/assets/skills/consulting-report/template/content/executive-summary.md +0 -19
  51. package/assets/skills/consulting-report/template/content/report-data.ts +0 -59
  52. package/assets/skills/consulting-report/template/diagrams/.gitkeep +0 -0
@@ -1,115 +1,109 @@
1
1
  ---
2
2
  name: consulting-report
3
- description: Produce branded consulting-report PDFs from a structured report directory (cover page, linked TOC, headers/footers with page numbers, typography system, callout boxes, findings + recommendations). Use when generating an assessment report, strategic review, or consulting deliverable PDF.
4
- argument-hint: <report-dir> OR `scaffold <target-dir>` to start a new report
3
+ description: Build a beautifully-typeset consulting-report PDF from a typed data file and a React layout. Use when generating an assessment, strategic review, operational readiness check, or any McKinsey-style consulting deliverable as a PDF.
4
+ argument-hint: scaffold <target-dir> | dev <report-dir> | <report-dir> (render PDF)
5
5
  ---
6
6
 
7
7
  ## Overview
8
8
 
9
- Renders a structured consulting-report directory to a branded PDF: cover page, linked table of contents, page-numbered headers/footers, typography system (Georgia body + Inter headings), colored callout boxes for findings and recommendations, tables with zebra striping.
10
-
11
- Each report lives in its own directory with data (TypeScript) + narrative (Markdown) + diagrams (images). The skill provides a scaffolder to spin up new reports from a template and a generator to render them.
12
-
13
- **Default brand:** Konvert7. Override per report via the `brand` block in `report-data.ts`.
14
-
15
- ## Report Directory Layout
16
-
17
- ```
18
- <report-dir>/
19
- ├── content/
20
- │ ├── report-data.ts # report structure (schema: ConsultingReport)
21
- │ ├── executive-summary.md # narrative sections
22
- │ └── …
23
- ├── diagrams/ # source images (PNG/JPG)
24
- ├── diagrams-compressed/ # generated — ignore
25
- └── <client>-<title>-<date>.{pdf,html} # output
26
- ```
9
+ Every report is a self-contained Next.js app: typed report data in `lib/report-data.ts`, layout composed from React components in `app/page.tsx`, fonts via `next/font/google` (Source Serif 4 + Inter), Tailwind v4 for styling. `bun run dev` gives a live preview while authoring; the PDF is rendered by Playwright against a static export.
27
10
 
28
11
  ## Workflow
29
12
 
30
- ### Step 1: Scaffold a new report (skip if the report directory already exists)
13
+ ### 1. Scaffold a new report
31
14
 
32
15
  ```bash
33
16
  bun ~/.pal/skills/consulting-report/tools/scaffold.ts <target-dir> \
34
- --client "Client Name" \
35
- --title "Report Title"
17
+ [--client "Client Name"] [--title "Report Title"] [--no-install]
36
18
  ```
37
19
 
38
- Creates the directory, stamps today's date + client + title into `report-data.ts`, and writes a starter `executive-summary.md`. If the target directory already exists, the command errors — move or remove first.
20
+ Creates `<target-dir>` from the template and runs `bun install` inside. If `--client` / `--title` are passed, they're stamped into `lib/report-data.ts`. The scaffolder refuses to overwrite an existing directory.
21
+
22
+ ### 2. Fill in the content
39
23
 
40
- ### Step 2: Fill in content
24
+ Two files do the work:
41
25
 
42
- Edit:
26
+ - **`lib/report-data.ts`** — typed metadata: client, title, date, classification, consultancy name, executive summary, situation assessment, findings, risk analysis, strategic opportunity, recommendations, target state, roadmap, call to action. The `ReportData` interface guides what's required.
27
+ - **`app/page.tsx`** — the layout. Composes `<CoverPage/>`, `<Section/>`, `<Exhibit/>`, `<FindingCard/>`, `<RecommendationCard/>`, `<Callout/>`, `<Timeline/>`, etc. against the data. Edit freely — section titles, intros, ordering, custom JSX, anything.
43
28
 
44
- - `<dir>/content/report-data.ts` cover metadata, sections list, optional findings / recommendations / conclusion / appendix. Each `section.content` is either an inline markdown string OR a `.md` filename relative to `content/`.
45
- - `<dir>/content/*.md` — the narrative sections referenced from `report-data.ts`.
46
- - `<dir>/diagrams/` — drop PNG/JPG images. Reference them from markdown with relative paths, e.g. `![alt](../diagrams-compressed/architecture.jpg)`.
29
+ Static images go in `public/`; reference them from JSX as `<img src="/your-image.png">`.
47
30
 
48
- ### Step 3: Render
31
+ ### 3. Live preview while authoring
49
32
 
50
33
  ```bash
51
- node --experimental-strip-types ~/.pal/skills/consulting-report/tools/generate-pdf.ts <report-dir>
34
+ bun ~/.pal/skills/consulting-report/tools/dev.ts <report-dir>
52
35
  ```
53
36
 
54
- Output: `<dir>/<client-slug>-<title-slug>-<date>.pdf` and matching `.html`. Override with `--pdf <path>` / `--html <path>`.
55
-
56
- The generator:
57
- - Loads `content/report-data.ts` dynamically
58
- - Compresses `diagrams/*` to JPEG 70% / 1200px via `sips` (macOS); silently skips if `sips` is absent
59
- - Renders cover, auto-generated linked TOC, sections, findings, recommendations, conclusion, appendix
60
- - Prints via Playwright with page-numbered header/footer templates
37
+ Wraps `bun run dev` in the report directory. Open the URL printed by Next, edit `app/page.tsx` or `lib/report-data.ts`, browser hot-reloads.
61
38
 
62
- ### Step 4: Verify
39
+ ### 4. Render the PDF
63
40
 
64
41
  ```bash
65
- ls -lh <dir>/*.pdf
42
+ node --experimental-strip-types ~/.pal/skills/consulting-report/tools/generate-pdf.ts <report-dir>
66
43
  ```
67
44
 
68
- Open the PDF. Check: cover centered and branded; TOC links jump; findings render in red/amber boxes by severity; recommendations in blue boxes with priority badges; every page has the CONFIDENTIAL footer and page number.
69
-
70
- ## Report Schema
71
-
72
- ```ts
73
- interface ConsultingReport {
74
- clientName: string;
75
- reportTitle: string;
76
- reportDate: string;
77
- classification: string; // e.g., "CONFIDENTIAL"
78
- version: string;
79
- brand?: { businessName: string; brandLabel?: string; logoPath?: string; };
80
- sections: Section[];
81
- findings?: Finding[]; // renders as red/amber/blue boxes by severity
82
- recommendations?: Recommendation[]; // blue boxes with priority badges
83
- conclusion?: Conclusion;
84
- supportingEvidence?: Record<string, string[]>; // appendix
85
- }
86
-
87
- interface Section { id: string; title: string; content: string; subsections?: Section[]; }
88
- interface Finding { id: string; title: string; severity: "critical"|"high"|"medium"|"low"; evidence: string; impact?: string; }
89
- interface Recommendation { id: string; title: string; priority: "immediate"|"short-term"|"long-term"; detail: string; owner?: string; }
90
- interface Conclusion { assessorNote?: string; contextNote?: string; closingRemarks?: string; }
45
+ Runs `next build` (which produces a static export at `out/`), then Playwright loads it via a tiny in-process HTTP server and prints the PDF with page-numbered header/footer. Output:
46
+
47
+ ```
48
+ <report-dir>/<client-slug>-<title-slug>-<date>.pdf
91
49
  ```
92
50
 
93
- ## Styling
51
+ Override with `--pdf <path>`. Pass `--skip-build` to re-render the PDF from the existing `out/` without re-building.
94
52
 
95
- The typography system (Georgia body 10.5pt / Inter headings), color palette (navy #1B2A4A, blue #2E5090, red #DC2626, amber #D97706, green #059669), callout boxes, badges, table styling, cover layout, and header/footer templates are baked into `tools/generate-pdf.ts`. To customize: edit the `css()` function and the `renderPdf()` header/footer strings in one place.
53
+ Run with **Node**, not Bun Playwright's `chromium.launch()` hangs under Bun on Windows.
96
54
 
97
- Do NOT combine CSS `@page` margin-box rules with the Playwright `displayHeaderFooter` templates — they duplicate.
55
+ ## Directory Layout
98
56
 
99
- ## Demo
57
+ ```
58
+ <report-dir>/
59
+ ├── app/
60
+ │ ├── layout.tsx # font wiring (Inter + Source Serif 4)
61
+ │ ├── page.tsx # the report's layout — edit freely
62
+ │ └── globals.css # design tokens via @theme + custom CSS
63
+ ├── components/ # 9 ported components — edit if you need new shapes
64
+ │ ├── cover-page.tsx
65
+ │ ├── section.tsx
66
+ │ ├── exhibit.tsx
67
+ │ ├── finding-card.tsx
68
+ │ ├── recommendation-card.tsx
69
+ │ ├── severity-badge.tsx
70
+ │ ├── callout.tsx
71
+ │ ├── quote-block.tsx
72
+ │ └── timeline.tsx
73
+ ├── lib/
74
+ │ ├── report-data.ts # all your content
75
+ │ └── utils.ts
76
+ ├── public/ # static images, optional
77
+ ├── package.json # exact-pinned: next, react, tailwindcss, etc.
78
+ ├── tsconfig.json
79
+ ├── next.config.js
80
+ └── postcss.config.mjs
81
+ ```
82
+
83
+ ## Component Cheatsheet
100
84
 
101
- A runnable demo lives at `~/.pal/skills/consulting-report/demo/`:
85
+ - `<CoverPage clientName reportTitle reportDate classification consultancyName preTitle />` — full-bleed cover
86
+ - `<Section title>` — top-level section with bottom-rule heading
87
+ - `<Exhibit number title source?>` — bordered card for figures, tables, side data
88
+ - `<FindingCard finding={f} index={i} />` — driven by `Finding` type, includes severity badge
89
+ - `<RecommendationCard recommendation={r} index={i} />` — driven by `Recommendation` type, includes priority badge
90
+ - `<Callout label?>` — left-rule emphasis block (default label "Key Takeaway")
91
+ - `<QuoteBlock quote attribution role? />` — pull-quote with serif quote mark
92
+ - `<Timeline phases={r.roadmap} />` — vertical timeline with dotted line
93
+ - `<SeverityBadge severity />` — pill badge: critical / high / medium / low
94
+
95
+ ## Demo
102
96
 
103
97
  ```bash
104
98
  node --experimental-strip-types ~/.pal/skills/consulting-report/tools/generate-pdf.ts ~/.pal/skills/consulting-report/demo
105
99
  ```
106
100
 
107
- Inspect the produced PDF to see the full layout (cover, TOC, sections, findings, recommendations, conclusion, appendix) before writing your own report.
101
+ Renders the bundled Acme Industries example end-to-end. Inspect the resulting PDF to see the full layout before authoring your own.
108
102
 
109
103
  ## Important
110
104
 
111
- - Reports live wherever you want; the skill only needs the `<report-dir>` path
112
- - The scaffolder refuses to overwrite an existing directory
113
- - Images go in `diagrams/`; reference them from markdown via `diagrams-compressed/<name>.jpg` so the compressed output is used
114
- - Heading anchor IDs come from `section.id` keep them unique and slug-safe
115
- - Every report re-renders deterministically from source; the PDF and HTML are disposable artifacts
105
+ - Run on Node 22.6 (Playwright + `--experimental-strip-types`)
106
+ - Bundled fonts come from Google Fonts via `next/font/google` — no licensing surface, no CDN at runtime, glyphs embedded at build time
107
+ - Reports are disposable artifacts of `lib/report-data.ts` + `app/page.tsx`; commit the source, not the PDF
108
+ - The scaffolder runs `bun install` inside the target by default — pass `--no-install` to skip
109
+ - Header/footer templates render with `displayHeaderFooter: true` in Playwright; don't combine with CSS `@page` margin-box rules
@@ -0,0 +1,344 @@
1
+ @import "tailwindcss";
2
+
3
+ @theme {
4
+ --color-background: #ffffff;
5
+ --color-background-secondary: #f8fafc;
6
+ --color-background-tertiary: #f1f5f9;
7
+ --color-background-elevated: #e2e8f0;
8
+
9
+ --color-foreground: #0f172a;
10
+ --color-muted: #475569;
11
+ --color-muted-dark: #94a3b8;
12
+
13
+ --color-border: #e2e8f0;
14
+ --color-border-subtle: #f1f5f9;
15
+ --color-border-emphasis: #cbd5e1;
16
+
17
+ --color-primary: #1d4ed8;
18
+ --color-accent: #7c3aed;
19
+ --color-success: #16a34a;
20
+ --color-warning: #d97706;
21
+ --color-destructive: #dc2626;
22
+
23
+ --color-section: #f8fafc;
24
+ --color-callout: #eff6ff;
25
+
26
+ --font-sans: var(--font-inter), system-ui, sans-serif;
27
+ --font-serif: var(--font-source-serif), Georgia, serif;
28
+ --font-heading: var(--font-inter), system-ui, sans-serif;
29
+ --font-body: var(--font-source-serif), Georgia, serif;
30
+ }
31
+
32
+ @source "./**/*.{ts,tsx}";
33
+ @source "../components/**/*.{ts,tsx}";
34
+
35
+ body {
36
+ font-family: var(--font-body);
37
+ background: var(--color-background);
38
+ color: var(--color-foreground);
39
+ line-height: 1.7;
40
+ -webkit-font-smoothing: antialiased;
41
+ -moz-osx-font-smoothing: grayscale;
42
+ }
43
+
44
+ /* McKinsey-style report layout */
45
+ .report-container {
46
+ max-width: 850px;
47
+ margin: 0 auto;
48
+ padding: 2rem;
49
+ }
50
+
51
+ .report-section {
52
+ margin-bottom: 3rem;
53
+ page-break-inside: avoid;
54
+ }
55
+
56
+ .report-section h2 {
57
+ font-family: var(--font-heading);
58
+ font-size: 1.75rem;
59
+ font-weight: 600;
60
+ color: var(--color-foreground);
61
+ margin-bottom: 1.5rem;
62
+ padding-bottom: 0.5rem;
63
+ border-bottom: 2px solid var(--color-primary);
64
+ }
65
+
66
+ .report-section h3 {
67
+ font-family: var(--font-heading);
68
+ font-size: 1.25rem;
69
+ font-weight: 600;
70
+ color: var(--color-foreground);
71
+ margin-bottom: 1rem;
72
+ }
73
+
74
+ /* Exhibit */
75
+ .exhibit {
76
+ background: var(--color-background-secondary);
77
+ border: 1px solid var(--color-border);
78
+ border-radius: 0.5rem;
79
+ padding: 1.5rem;
80
+ margin: 1.5rem 0;
81
+ }
82
+ .exhibit-header {
83
+ display: flex;
84
+ justify-content: space-between;
85
+ align-items: baseline;
86
+ margin-bottom: 1rem;
87
+ padding-bottom: 0.5rem;
88
+ border-bottom: 1px solid var(--color-border-subtle);
89
+ }
90
+ .exhibit-number {
91
+ font-family: var(--font-sans);
92
+ font-weight: 600;
93
+ color: var(--color-primary);
94
+ font-size: 0.875rem;
95
+ text-transform: uppercase;
96
+ letter-spacing: 0.1em;
97
+ }
98
+ .exhibit-title {
99
+ font-family: var(--font-heading);
100
+ font-weight: 600;
101
+ color: var(--color-foreground);
102
+ }
103
+
104
+ /* Callout */
105
+ .callout {
106
+ background: var(--color-callout);
107
+ border-left: 4px solid var(--color-primary);
108
+ padding: 1.25rem 1.5rem;
109
+ margin: 1.5rem 0;
110
+ border-radius: 0 0.5rem 0.5rem 0;
111
+ }
112
+ .callout-label {
113
+ font-family: var(--font-sans);
114
+ font-weight: 600;
115
+ color: var(--color-primary);
116
+ font-size: 0.75rem;
117
+ text-transform: uppercase;
118
+ letter-spacing: 0.1em;
119
+ margin-bottom: 0.5rem;
120
+ }
121
+ .callout-content {
122
+ font-size: 1.125rem;
123
+ font-weight: 500;
124
+ color: var(--color-foreground);
125
+ }
126
+
127
+ /* Quote block */
128
+ .quote-block {
129
+ position: relative;
130
+ padding: 1.5rem 2rem;
131
+ margin: 1.5rem 0;
132
+ background: var(--color-background-secondary);
133
+ border-radius: 0.5rem;
134
+ border: 1px solid var(--color-border-subtle);
135
+ }
136
+ .quote-block::before {
137
+ content: "\201C";
138
+ position: absolute;
139
+ top: 0.5rem;
140
+ left: 0.75rem;
141
+ font-size: 3rem;
142
+ color: var(--color-primary);
143
+ opacity: 0.5;
144
+ font-family: Georgia, serif;
145
+ line-height: 1;
146
+ }
147
+ .quote-text {
148
+ font-style: italic;
149
+ color: var(--color-foreground);
150
+ font-size: 1.0625rem;
151
+ line-height: 1.7;
152
+ }
153
+ .quote-attribution {
154
+ margin-top: 0.75rem;
155
+ font-size: 0.875rem;
156
+ color: var(--color-muted);
157
+ }
158
+
159
+ /* Severity badges */
160
+ .severity-badge {
161
+ display: inline-flex;
162
+ align-items: center;
163
+ padding: 0.25rem 0.75rem;
164
+ border-radius: 9999px;
165
+ font-family: var(--font-sans);
166
+ font-size: 0.75rem;
167
+ font-weight: 600;
168
+ text-transform: uppercase;
169
+ letter-spacing: 0.05em;
170
+ }
171
+ .severity-critical {
172
+ background: rgba(220, 38, 38, 0.1);
173
+ color: var(--color-destructive);
174
+ border: 1px solid rgba(220, 38, 38, 0.3);
175
+ }
176
+ .severity-high {
177
+ background: rgba(234, 88, 12, 0.1);
178
+ color: #ea580c;
179
+ border: 1px solid rgba(234, 88, 12, 0.3);
180
+ }
181
+ .severity-medium {
182
+ background: rgba(217, 119, 6, 0.1);
183
+ color: var(--color-warning);
184
+ border: 1px solid rgba(217, 119, 6, 0.3);
185
+ }
186
+ .severity-low {
187
+ background: rgba(22, 163, 74, 0.1);
188
+ color: var(--color-success);
189
+ border: 1px solid rgba(22, 163, 74, 0.3);
190
+ }
191
+
192
+ /* Finding card */
193
+ .finding-card {
194
+ background: var(--color-background-secondary);
195
+ border: 1px solid var(--color-border);
196
+ border-radius: 0.5rem;
197
+ padding: 1.5rem;
198
+ margin-bottom: 1rem;
199
+ }
200
+ .finding-header {
201
+ display: flex;
202
+ justify-content: space-between;
203
+ align-items: flex-start;
204
+ margin-bottom: 0.75rem;
205
+ }
206
+ .finding-title {
207
+ font-family: var(--font-heading);
208
+ font-weight: 600;
209
+ color: var(--color-foreground);
210
+ font-size: 1.0625rem;
211
+ }
212
+ .finding-evidence {
213
+ font-size: 0.9375rem;
214
+ color: var(--color-muted);
215
+ margin-top: 0.5rem;
216
+ }
217
+
218
+ /* Timeline */
219
+ .timeline {
220
+ position: relative;
221
+ padding-left: 2rem;
222
+ }
223
+ .timeline::before {
224
+ content: "";
225
+ position: absolute;
226
+ left: 0.5rem;
227
+ top: 0;
228
+ bottom: 0;
229
+ width: 2px;
230
+ background: linear-gradient(180deg, var(--color-primary) 0%, var(--color-accent) 100%);
231
+ }
232
+ .timeline-item {
233
+ position: relative;
234
+ padding-bottom: 1.5rem;
235
+ }
236
+ .timeline-item::before {
237
+ content: "";
238
+ position: absolute;
239
+ /* Center dot on the vertical line: line is at left:0.5rem (8px) +1px,
240
+ timeline-item starts at padding 2rem (32px). Dot half-width 6px → place
241
+ left at -1.8125rem so dot center lands at 9px from .timeline left. */
242
+ left: -1.8125rem;
243
+ top: 0.4rem;
244
+ width: 0.75rem;
245
+ height: 0.75rem;
246
+ border-radius: 50%;
247
+ background: var(--color-primary);
248
+ }
249
+ .timeline-phase {
250
+ font-family: var(--font-sans);
251
+ font-weight: 600;
252
+ color: var(--color-primary);
253
+ font-size: 0.875rem;
254
+ text-transform: uppercase;
255
+ letter-spacing: 0.1em;
256
+ }
257
+ .timeline-title {
258
+ font-family: var(--font-heading);
259
+ font-weight: 600;
260
+ color: var(--color-foreground);
261
+ margin-top: 0.25rem;
262
+ }
263
+ .timeline-description {
264
+ color: var(--color-muted);
265
+ font-size: 0.9375rem;
266
+ margin-top: 0.25rem;
267
+ }
268
+
269
+ /* Cover page */
270
+ .cover-page {
271
+ min-height: 100vh;
272
+ display: flex;
273
+ flex-direction: column;
274
+ justify-content: center;
275
+ padding: 4rem;
276
+ page-break-after: always;
277
+ background: linear-gradient(180deg, var(--color-background) 0%, var(--color-background-secondary) 100%);
278
+ }
279
+ .cover-classification {
280
+ font-family: var(--font-sans);
281
+ font-size: 0.875rem;
282
+ font-weight: 600;
283
+ color: var(--color-destructive);
284
+ text-transform: uppercase;
285
+ letter-spacing: 0.15em;
286
+ margin-bottom: 4rem;
287
+ }
288
+ .cover-title {
289
+ font-family: var(--font-heading);
290
+ font-size: 3rem;
291
+ font-weight: 600;
292
+ color: var(--color-foreground);
293
+ line-height: 1.2;
294
+ margin-bottom: 1rem;
295
+ letter-spacing: -0.02em;
296
+ }
297
+ .cover-subtitle {
298
+ font-family: var(--font-heading);
299
+ font-size: 1.5rem;
300
+ color: var(--color-muted);
301
+ margin-bottom: 4rem;
302
+ font-weight: 400;
303
+ }
304
+ .cover-meta {
305
+ margin-top: auto;
306
+ padding-top: 1.5rem;
307
+ border-top: 1px solid var(--color-border);
308
+ }
309
+ .cover-date {
310
+ font-family: var(--font-sans);
311
+ font-size: 1rem;
312
+ color: var(--color-muted);
313
+ }
314
+
315
+ /* Print styles — what Playwright sees */
316
+ @media print {
317
+ body {
318
+ font-size: 11pt;
319
+ }
320
+ .report-container {
321
+ max-width: none;
322
+ padding: 0;
323
+ }
324
+ .report-section,
325
+ .callout,
326
+ .exhibit,
327
+ .finding-card,
328
+ .quote-block {
329
+ break-inside: avoid;
330
+ }
331
+ .cover-page {
332
+ page-break-after: always;
333
+ }
334
+ a {
335
+ text-decoration: none;
336
+ color: var(--color-foreground);
337
+ }
338
+ }
339
+
340
+ /* Page setup for PDF */
341
+ @page {
342
+ size: A4;
343
+ margin: 18mm 16mm;
344
+ }
@@ -0,0 +1,32 @@
1
+ import type { Metadata } from "next";
2
+ import { Inter, Source_Serif_4 } from "next/font/google";
3
+ import "./globals.css";
4
+
5
+ const inter = Inter({
6
+ subsets: ["latin"],
7
+ variable: "--font-inter",
8
+ display: "swap",
9
+ });
10
+
11
+ const sourceSerif = Source_Serif_4({
12
+ subsets: ["latin"],
13
+ variable: "--font-source-serif",
14
+ display: "swap",
15
+ });
16
+
17
+ export const metadata: Metadata = {
18
+ title: "Consulting Report",
19
+ description: "Strategic assessment and recommendations.",
20
+ };
21
+
22
+ export default function RootLayout({
23
+ children,
24
+ }: Readonly<{ children: React.ReactNode }>) {
25
+ return (
26
+ <html lang="en" className={`${inter.variable} ${sourceSerif.variable}`}>
27
+ <body className="bg-background font-body text-foreground antialiased">
28
+ {children}
29
+ </body>
30
+ </html>
31
+ );
32
+ }