@hed-hog/core 0.0.329 → 0.0.330

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 (103) hide show
  1. package/dist/ai/ai.service.d.ts +1 -1
  2. package/dist/auth/auth.controller.d.ts +23 -23
  3. package/dist/auth/auth.service.d.ts +41 -41
  4. package/dist/challenge/challenge.service.d.ts +14 -14
  5. package/dist/core/system.controller.d.ts +2 -2
  6. package/dist/core/system.service.d.ts +2 -2
  7. package/dist/core.module.d.ts.map +1 -1
  8. package/dist/core.module.js +7 -4
  9. package/dist/core.module.js.map +1 -1
  10. package/dist/dashboard/dashboard/dashboard.controller.d.ts +87 -87
  11. package/dist/dashboard/dashboard/dashboard.service.d.ts +87 -87
  12. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +33 -33
  13. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +33 -33
  14. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +42 -42
  15. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +42 -42
  16. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +12 -12
  17. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +12 -12
  18. package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +7 -7
  19. package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +7 -7
  20. package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +33 -33
  21. package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +33 -33
  22. package/dist/dashboard/dashboard-user/dashboard-user.controller.d.ts +3 -3
  23. package/dist/dashboard/dashboard-user/dashboard-user.service.d.ts +3 -3
  24. package/dist/file/file.controller.d.ts +8 -8
  25. package/dist/file/file.service.d.ts +18 -18
  26. package/dist/index.d.ts +8 -6
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +8 -6
  29. package/dist/index.js.map +1 -1
  30. package/dist/mail/mail.controller.d.ts +15 -15
  31. package/dist/mail/mail.service.d.ts +15 -15
  32. package/dist/mail-profile/mail-profile.controller.d.ts +9 -9
  33. package/dist/mail-profile/mail-profile.service.d.ts +9 -9
  34. package/dist/mail-sent/mail-sent.controller.d.ts +17 -17
  35. package/dist/mail-sent/mail-sent.service.d.ts +17 -17
  36. package/dist/mcp-chat/mcp-chat.controller.d.ts +10 -10
  37. package/dist/mcp-chat/mcp-chat.service.d.ts +10 -10
  38. package/dist/menu/menu.controller.d.ts +11 -11
  39. package/dist/menu/menu.service.d.ts +11 -11
  40. package/dist/oauth/oauth.service.js +1 -1
  41. package/dist/oauth/oauth.service.js.map +1 -1
  42. package/dist/pdf/components/index.d.ts +57 -0
  43. package/dist/pdf/components/index.d.ts.map +1 -0
  44. package/dist/pdf/components/index.js +258 -0
  45. package/dist/pdf/components/index.js.map +1 -0
  46. package/dist/pdf/dto/generate-pdf.dto.d.ts +5 -0
  47. package/dist/pdf/dto/generate-pdf.dto.d.ts.map +1 -0
  48. package/dist/pdf/dto/generate-pdf.dto.js +27 -0
  49. package/dist/pdf/dto/generate-pdf.dto.js.map +1 -0
  50. package/dist/pdf/interfaces/pdf-theme-config.interface.d.ts +10 -0
  51. package/dist/pdf/interfaces/pdf-theme-config.interface.d.ts.map +1 -0
  52. package/dist/pdf/interfaces/pdf-theme-config.interface.js +3 -0
  53. package/dist/pdf/interfaces/pdf-theme-config.interface.js.map +1 -0
  54. package/dist/pdf/pdf.controller.d.ts +16 -0
  55. package/dist/pdf/pdf.controller.d.ts.map +1 -0
  56. package/dist/pdf/pdf.controller.js +100 -0
  57. package/dist/pdf/pdf.controller.js.map +1 -0
  58. package/dist/pdf/pdf.module.d.ts +3 -0
  59. package/dist/pdf/pdf.module.d.ts.map +1 -0
  60. package/dist/pdf/pdf.module.js +29 -0
  61. package/dist/pdf/pdf.module.js.map +1 -0
  62. package/dist/pdf/pdf.service.d.ts +44 -0
  63. package/dist/pdf/pdf.service.d.ts.map +1 -0
  64. package/dist/pdf/pdf.service.js +185 -0
  65. package/dist/pdf/pdf.service.js.map +1 -0
  66. package/dist/pdf/templates/hcode-institutional.template.d.ts +36 -0
  67. package/dist/pdf/templates/hcode-institutional.template.d.ts.map +1 -0
  68. package/dist/pdf/templates/hcode-institutional.template.js +67 -0
  69. package/dist/pdf/templates/hcode-institutional.template.js.map +1 -0
  70. package/dist/pdf/themes/hcode.theme.d.ts +25 -0
  71. package/dist/pdf/themes/hcode.theme.d.ts.map +1 -0
  72. package/dist/pdf/themes/hcode.theme.js +504 -0
  73. package/dist/pdf/themes/hcode.theme.js.map +1 -0
  74. package/dist/profile/profile.controller.d.ts +17 -17
  75. package/dist/profile/profile.service.d.ts +17 -17
  76. package/dist/role/role.controller.d.ts +12 -12
  77. package/dist/role/role.service.d.ts +12 -12
  78. package/dist/screen/screen.controller.d.ts +3 -3
  79. package/dist/screen/screen.service.d.ts +3 -3
  80. package/dist/session/session.controller.d.ts +4 -4
  81. package/dist/session/session.service.d.ts +12 -12
  82. package/dist/setting/setting.controller.d.ts +13 -13
  83. package/dist/setting/setting.service.d.ts +13 -13
  84. package/dist/user/user.controller.d.ts +24 -24
  85. package/dist/user/user.service.d.ts +55 -55
  86. package/hedhog/data/route.yaml +8 -0
  87. package/hedhog/data/setting_group.yaml +60 -0
  88. package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +574 -574
  89. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +5 -9
  90. package/hedhog/frontend/messages/en.json +2 -0
  91. package/hedhog/frontend/messages/pt.json +2 -0
  92. package/package.json +4 -4
  93. package/src/core.module.ts +7 -4
  94. package/src/index.ts +9 -6
  95. package/src/oauth/oauth.service.ts +12 -12
  96. package/src/pdf/components/index.ts +316 -0
  97. package/src/pdf/dto/generate-pdf.dto.ts +11 -0
  98. package/src/pdf/interfaces/pdf-theme-config.interface.ts +10 -0
  99. package/src/pdf/pdf.controller.ts +86 -0
  100. package/src/pdf/pdf.module.ts +17 -0
  101. package/src/pdf/pdf.service.ts +229 -0
  102. package/src/pdf/templates/hcode-institutional.template.ts +122 -0
  103. package/src/pdf/themes/hcode.theme.ts +515 -0
@@ -0,0 +1,515 @@
1
+ import { PdfAreaType, PdfThemeConfig } from '../interfaces/pdf-theme-config.interface';
2
+
3
+ // ─────────────────────────────────────────────────────────────────────────────
4
+ // Design System v1.0 – April 2026 – hardcoded defaults
5
+ // Overrides loaded from SettingService at runtime (see PdfService.loadThemeConfig)
6
+ // ─────────────────────────────────────────────────────────────────────────────
7
+
8
+ export interface AreaDefaults {
9
+ primary: string;
10
+ dark: string;
11
+ light: string;
12
+ }
13
+
14
+ /** Per-area color tokens — Design System v1.0 */
15
+ export const HCODE_DEFAULTS: Record<PdfAreaType, AreaDefaults> = {
16
+ // Blue 600 / Blue 800 / Blue 50
17
+ consulting: { primary: '#2D669E', dark: '#1F4A75', light: '#EAF1F8' },
18
+ // Orange 500 / Orange 700 / Orange 50
19
+ training: { primary: '#FF760C', dark: '#C45400', light: '#FFF0E2' },
20
+ // Violet 600 / Violet 800 / Violet 50
21
+ research: { primary: '#9400B5', dark: '#6A0083', light: '#F6E6FB' },
22
+ };
23
+
24
+ /** Neutral tokens — shared across all areas */
25
+ export const HCODE_NEUTRALS = {
26
+ ink1: '#101010', // body text
27
+ ink2: '#5D5D5D',
28
+ ink3: '#79756C',
29
+ line: '#ECECEC',
30
+ surface: '#FFFFFF',
31
+ surface2: '#F8F8F8',
32
+ } as const;
33
+
34
+ // ─────────────────────────────────────────────────────────────────────────────
35
+ // CSS builders
36
+ // ─────────────────────────────────────────────────────────────────────────────
37
+
38
+ /** Google Fonts import for Inter, Roboto and JetBrains Mono */
39
+ export function buildFontImport(): string {
40
+ return `<link rel="preconnect" href="https://fonts.googleapis.com">
41
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
42
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;600;700&family=Roboto:wght@400;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">`;
43
+ }
44
+
45
+ /**
46
+ * Generates the <style> block with all Design System CSS variables and rules.
47
+ * Typography scale is calibrated for A4 PDF (794 px viewport).
48
+ */
49
+ export function buildThemeCss(config: PdfThemeConfig): string {
50
+ return `<style>
51
+ /* ── CSS Variables ─────────────────────────────────────── */
52
+ :root {
53
+ /* Area accent */
54
+ --primary: ${config.primaryColor};
55
+ --dark: ${config.darkColor};
56
+ --light: ${config.lightColor};
57
+
58
+ /* Neutrals */
59
+ --ink-1: ${HCODE_NEUTRALS.ink1};
60
+ --ink-2: ${HCODE_NEUTRALS.ink2};
61
+ --ink-3: ${HCODE_NEUTRALS.ink3};
62
+ --line: ${HCODE_NEUTRALS.line};
63
+ --surface: ${HCODE_NEUTRALS.surface};
64
+ --surface-2:${HCODE_NEUTRALS.surface2};
65
+
66
+ /* Fonts */
67
+ --font-main: 'Inter', sans-serif;
68
+ --font-micro: 'Roboto', sans-serif;
69
+ --font-meta: 'JetBrains Mono', monospace;
70
+ }
71
+
72
+ /* ── Reset ─────────────────────────────────────────────── */
73
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
74
+
75
+ html, body {
76
+ font-family: var(--font-main);
77
+ font-size: 13px;
78
+ color: var(--ink-1);
79
+ background: var(--surface);
80
+ -webkit-print-color-adjust: exact;
81
+ print-color-adjust: exact;
82
+ }
83
+
84
+ /* ── Type Scale (A4-calibrated, DS v1.0 proportions) ───── */
85
+ /* Display / 80 → Inter 200, tracking -0.03em */
86
+ .t-display {
87
+ font-family: var(--font-main);
88
+ font-weight: 200;
89
+ font-size: 52px;
90
+ line-height: 1.05;
91
+ letter-spacing: -0.03em;
92
+ color: var(--ink-1);
93
+ }
94
+ /* H1 / 56 → Inter 300, tracking -0.02em */
95
+ .t-h1 {
96
+ font-family: var(--font-main);
97
+ font-weight: 300;
98
+ font-size: 36px;
99
+ line-height: 1.1;
100
+ letter-spacing: -0.02em;
101
+ color: var(--ink-1);
102
+ }
103
+ /* H2 / 36 → Inter 400 */
104
+ .t-h2 {
105
+ font-family: var(--font-main);
106
+ font-weight: 400;
107
+ font-size: 24px;
108
+ line-height: 1.15;
109
+ color: var(--ink-1);
110
+ }
111
+ /* H3 / 26 → Inter 600 */
112
+ .t-h3 {
113
+ font-family: var(--font-main);
114
+ font-weight: 600;
115
+ font-size: 17px;
116
+ line-height: 1.2;
117
+ color: var(--ink-1);
118
+ }
119
+ /* Eyebrow / 22 → Inter 400, tracking 0.36em, uppercase */
120
+ .t-eyebrow {
121
+ font-family: var(--font-main);
122
+ font-weight: 400;
123
+ font-size: 9px;
124
+ line-height: 1.4;
125
+ letter-spacing: 0.36em;
126
+ text-transform: uppercase;
127
+ color: var(--ink-3);
128
+ }
129
+ /* Body / 22 → Inter 300 */
130
+ .t-body {
131
+ font-family: var(--font-main);
132
+ font-weight: 300;
133
+ font-size: 13px;
134
+ line-height: 1.65;
135
+ color: var(--ink-2);
136
+ }
137
+ /* Meta / 14 → JetBrains Mono 500, tracking 0.18em */
138
+ .t-meta {
139
+ font-family: var(--font-meta);
140
+ font-weight: 500;
141
+ font-size: 8px;
142
+ line-height: 1.4;
143
+ letter-spacing: 0.18em;
144
+ text-transform: uppercase;
145
+ color: var(--ink-3);
146
+ }
147
+ /* Micro → Roboto 400 (rodapés, créditos) */
148
+ .t-micro {
149
+ font-family: var(--font-micro);
150
+ font-weight: 400;
151
+ font-size: 8px;
152
+ line-height: 1.4;
153
+ color: var(--ink-3);
154
+ }
155
+
156
+ /* ── Color utilities ────────────────────────────────────── */
157
+ .color-primary { color: var(--primary) !important; }
158
+ .bg-primary { background-color: var(--primary) !important; }
159
+ .bg-light { background-color: var(--light) !important; }
160
+ .bg-surface2 { background-color: var(--surface-2) !important; }
161
+
162
+ /* ── Page layout ────────────────────────────────────────── */
163
+ @page { size: A4; margin: 0; }
164
+
165
+ .page-content {
166
+ padding: 32px 48px 80px;
167
+ }
168
+
169
+ /* Page break utilities */
170
+ .break-before { page-break-before: always; break-before: page; }
171
+ .break-after { page-break-after: always; break-after: page; }
172
+ .no-break { page-break-inside: avoid; break-inside: avoid; }
173
+
174
+ /* ── Cover page ─────────────────────────────────────────── */
175
+ /* Two-column grid: left=white 55%, right=primary 45% */
176
+ .cover {
177
+ display: grid;
178
+ grid-template-columns: 55% 45%;
179
+ min-height: 297mm;
180
+ page-break-after: always;
181
+ break-after: page;
182
+ }
183
+ .cover-left {
184
+ background: var(--surface);
185
+ padding: 56px 40px 40px;
186
+ display: flex;
187
+ flex-direction: column;
188
+ justify-content: space-between;
189
+ }
190
+ .cover-right {
191
+ background: var(--primary);
192
+ padding: 40px 32px;
193
+ display: flex;
194
+ flex-direction: column;
195
+ align-items: flex-start;
196
+ justify-content: flex-end;
197
+ position: relative;
198
+ overflow: hidden;
199
+ }
200
+ .cover-right-glyph {
201
+ position: absolute;
202
+ top: -40px;
203
+ right: -20px;
204
+ font-family: var(--font-main);
205
+ font-weight: 300;
206
+ font-size: 280px;
207
+ color: rgba(255,255,255,0.10);
208
+ line-height: 1;
209
+ letter-spacing: -0.01em;
210
+ user-select: none;
211
+ pointer-events: none;
212
+ }
213
+ .cover-right-areas {
214
+ list-style: none;
215
+ width: 100%;
216
+ border-top: 1px solid rgba(255,255,255,0.25);
217
+ position: relative;
218
+ z-index: 1;
219
+ }
220
+ .cover-right-areas li {
221
+ font-family: var(--font-main);
222
+ font-weight: 400;
223
+ font-size: 9px;
224
+ letter-spacing: 0.30em;
225
+ text-transform: uppercase;
226
+ color: rgba(255,255,255,0.90);
227
+ padding: 10px 0;
228
+ border-bottom: 1px solid rgba(255,255,255,0.15);
229
+ display: flex;
230
+ align-items: center;
231
+ gap: 10px;
232
+ }
233
+ .cover-right-areas li .num {
234
+ font-family: var(--font-meta);
235
+ font-size: 7px;
236
+ opacity: 0.55;
237
+ }
238
+ .cover-system-label {
239
+ font-family: var(--font-meta);
240
+ font-size: 7px;
241
+ letter-spacing: 0.18em;
242
+ color: rgba(255,255,255,0.55);
243
+ position: absolute;
244
+ top: 16px;
245
+ left: 32px;
246
+ }
247
+ .cover-release-label {
248
+ font-family: var(--font-meta);
249
+ font-size: 7px;
250
+ letter-spacing: 0.18em;
251
+ color: rgba(255,255,255,0.55);
252
+ position: absolute;
253
+ top: 16px;
254
+ right: 32px;
255
+ display: flex;
256
+ align-items: center;
257
+ gap: 6px;
258
+ }
259
+ .cover-release-label::before {
260
+ content: '';
261
+ width: 6px;
262
+ height: 6px;
263
+ border-radius: 50%;
264
+ background: rgba(255,255,255,0.70);
265
+ }
266
+
267
+ /* ── Wordmark lockup ────────────────────────────────────── */
268
+ .lockup { display: flex; flex-direction: column; gap: 3px; }
269
+ .lockup-wordmark {
270
+ font-family: var(--font-main);
271
+ font-weight: 300;
272
+ font-size: 32px;
273
+ letter-spacing: -0.01em;
274
+ line-height: 1;
275
+ }
276
+ .lockup-wordmark .glyph { color: var(--primary); }
277
+ .lockup-wordmark .wordmark { color: var(--ink-3); }
278
+ .lockup-area {
279
+ font-family: var(--font-main);
280
+ font-weight: 400;
281
+ font-size: 9px;
282
+ letter-spacing: 0.30em;
283
+ text-transform: uppercase;
284
+ color: var(--primary);
285
+ }
286
+
287
+ /* ── Accent bar — fixed at top of EVERY page (cover included) ── */
288
+ .page-accent-bar {
289
+ position: fixed;
290
+ top: 0;
291
+ left: 0;
292
+ right: 0;
293
+ height: 6px;
294
+ background: var(--primary);
295
+ z-index: 999;
296
+ }
297
+
298
+ /* ── Page header (logo + page title) ───────────────────── */
299
+ .page-header {
300
+ display: flex;
301
+ align-items: center;
302
+ justify-content: space-between;
303
+ padding: 18px 48px 14px;
304
+ border-bottom: 1px solid var(--line);
305
+ }
306
+
307
+ /* ── Section header: eyebrow + title + left accent bar ─── */
308
+ .section-header {
309
+ display: flex;
310
+ flex-direction: column;
311
+ gap: 6px;
312
+ margin-bottom: 24px;
313
+ padding-left: 14px;
314
+ border-left: 3.5px solid var(--primary);
315
+ }
316
+
317
+ /* ── Purpose block (colored background) ─────────────────── */
318
+ .purpose-block {
319
+ background: var(--primary);
320
+ border-radius: 14px;
321
+ padding: 28px 32px;
322
+ margin-bottom: 28px;
323
+ page-break-inside: avoid;
324
+ break-inside: avoid;
325
+ }
326
+ .purpose-block .t-eyebrow { color: rgba(255,255,255,0.65); margin-bottom: 8px; }
327
+ .purpose-block .t-h3 { color: #ffffff; margin-bottom: 12px; font-size: 18px; font-weight: 600; }
328
+ .purpose-block .t-body { color: rgba(255,255,255,0.85); font-size: 12px; }
329
+
330
+ /* ── Feature cards (3-column grid) ─────────────────────── */
331
+ .feature-cards {
332
+ display: grid;
333
+ grid-template-columns: repeat(3, 1fr);
334
+ gap: 14px;
335
+ margin-bottom: 28px;
336
+ }
337
+ .feature-card {
338
+ border: 1px solid var(--line);
339
+ border-radius: 12px;
340
+ padding: 18px 14px;
341
+ background: var(--surface);
342
+ page-break-inside: avoid;
343
+ break-inside: avoid;
344
+ }
345
+ .feature-card-icon {
346
+ width: 38px;
347
+ height: 32px;
348
+ border: 1.5px solid var(--line);
349
+ border-radius: 8px;
350
+ display: flex;
351
+ align-items: center;
352
+ justify-content: center;
353
+ margin-bottom: 10px;
354
+ color: var(--primary);
355
+ }
356
+ .feature-card-title {
357
+ font-family: var(--font-main);
358
+ font-weight: 600;
359
+ font-size: 12px;
360
+ color: var(--primary);
361
+ margin-bottom: 5px;
362
+ letter-spacing: -0.01em;
363
+ }
364
+ .feature-card-desc {
365
+ font-family: var(--font-main);
366
+ font-weight: 300;
367
+ font-size: 10px;
368
+ line-height: 1.55;
369
+ color: var(--ink-2);
370
+ }
371
+
372
+ /* ── Chip ─────────────────────────────────────────────── */
373
+ .chip {
374
+ display: inline-flex;
375
+ align-items: center;
376
+ gap: 5px;
377
+ padding: 3px 10px;
378
+ border-radius: 999px;
379
+ background: var(--light);
380
+ font-family: var(--font-main);
381
+ font-weight: 400;
382
+ font-size: 9px;
383
+ color: var(--primary);
384
+ letter-spacing: 0.01em;
385
+ }
386
+ .chip::before {
387
+ content: '';
388
+ width: 5px;
389
+ height: 5px;
390
+ border-radius: 50%;
391
+ background: var(--primary);
392
+ flex-shrink: 0;
393
+ }
394
+
395
+ /* ── Data table ──────────────────────────────────────── */
396
+ .data-table {
397
+ width: 100%;
398
+ border-collapse: collapse;
399
+ margin-bottom: 28px;
400
+ }
401
+ .data-table thead tr { background: var(--light); }
402
+ .data-table th {
403
+ font-family: var(--font-meta);
404
+ font-weight: 500;
405
+ font-size: 8px;
406
+ letter-spacing: 0.18em;
407
+ text-transform: uppercase;
408
+ color: var(--primary);
409
+ padding: 9px 13px;
410
+ text-align: left;
411
+ border-bottom: 1.5px solid var(--primary);
412
+ }
413
+ .data-table td {
414
+ font-family: var(--font-main);
415
+ font-weight: 300;
416
+ font-size: 10px;
417
+ color: var(--ink-2);
418
+ padding: 9px 13px;
419
+ border-bottom: 1px solid var(--line);
420
+ }
421
+ .data-table tbody tr { page-break-inside: avoid; break-inside: avoid; }
422
+ .data-table tbody tr:nth-child(even) td { background: var(--surface-2); }
423
+
424
+ /* ── Metadata block ──────────────────────────────────── */
425
+ .metadata-block {
426
+ display: grid;
427
+ grid-template-columns: repeat(4, 1fr);
428
+ gap: 0;
429
+ border: 1px solid var(--line);
430
+ border-radius: 12px;
431
+ overflow: hidden;
432
+ margin-bottom: 28px;
433
+ page-break-inside: avoid;
434
+ break-inside: avoid;
435
+ }
436
+ .metadata-item {
437
+ padding: 14px 16px;
438
+ border-right: 1px solid var(--line);
439
+ background: var(--surface);
440
+ }
441
+ .metadata-item:nth-child(4n) { border-right: none; }
442
+ .metadata-item:nth-child(4n+4) { border-right: none; }
443
+ .metadata-item:nth-child(n+5) { border-top: 1px solid var(--line); }
444
+ .metadata-label {
445
+ font-family: var(--font-meta);
446
+ font-weight: 500;
447
+ font-size: 7px;
448
+ letter-spacing: 0.18em;
449
+ text-transform: uppercase;
450
+ color: var(--ink-3);
451
+ margin-bottom: 4px;
452
+ }
453
+ .metadata-value {
454
+ font-family: var(--font-main);
455
+ font-weight: 400;
456
+ font-size: 11px;
457
+ color: var(--ink-1);
458
+ }
459
+
460
+ /* ── Signature area ──────────────────────────────────── */
461
+ .signature-area {
462
+ display: grid;
463
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
464
+ gap: 24px;
465
+ margin-top: 28px;
466
+ page-break-inside: avoid;
467
+ break-inside: avoid;
468
+ }
469
+ .signature-item { display: flex; flex-direction: column; gap: 6px; }
470
+ .signature-line {
471
+ width: 100%;
472
+ height: 1px;
473
+ background: var(--ink-1);
474
+ margin-bottom: 5px;
475
+ }
476
+ .signature-label {
477
+ font-family: var(--font-micro);
478
+ font-size: 8px;
479
+ color: var(--ink-3);
480
+ }
481
+ .signature-name {
482
+ font-family: var(--font-main);
483
+ font-weight: 400;
484
+ font-size: 10px;
485
+ color: var(--ink-2);
486
+ }
487
+
488
+ /* ── Fixed footer (repeats on every page) ───────────── */
489
+ .pdf-footer {
490
+ position: fixed;
491
+ bottom: 0;
492
+ left: 0;
493
+ right: 0;
494
+ height: 40px;
495
+ display: flex;
496
+ align-items: center;
497
+ justify-content: space-between;
498
+ padding: 0 48px;
499
+ border-top: 1px solid var(--line);
500
+ background: var(--surface);
501
+ }
502
+ /* CSS counter for page numbering */
503
+ @page { counter-increment: page; }
504
+ .pdf-footer-page::after {
505
+ content: counter(page);
506
+ font-family: var(--font-meta);
507
+ font-size: 8px;
508
+ letter-spacing: 0.18em;
509
+ color: var(--ink-3);
510
+ }
511
+
512
+ /* Padding to avoid content overlapping the fixed header bar and footer */
513
+ body { padding-top: 6px; padding-bottom: 48px; }
514
+ </style>`;
515
+ }