@lukeashford/aurelius 4.9.0 → 4.10.1

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.
@@ -2,14 +2,33 @@
2
2
  *
3
3
  * Each visual class is defined as a Tailwind v4 `@utility` so the design-system
4
4
  * ESLint rule recognises them. The same DOM serves both the on-screen view
5
- * and the PDF print path; `@page` and `@media print` rules below replace the
6
- * dark theme with a print-friendly version (black on white, page-sized
7
- * sections, no actions). The accent color is a CSS variable scoped to the
8
- * deliverable root and falls back to the design-system gold.
5
+ * and the PDF print path. The screen path is the cinematic dark theme; the
6
+ * print path under `@media print` is its paper-friendly counterpart high
7
+ * contrast on white, editorial type pairing, gold rule above every section
8
+ * as a recurring chapter mark.
9
+ *
10
+ * Document-level levers (set per-section by the agent via the spec):
11
+ * - `theme` enum → `.deliverable-theme-*` class on the root, overrides
12
+ * a small bundle of CSS variables (accent, cover surface, rule weight,
13
+ * heading + body font families) so the same DOM reads as a different
14
+ * document. The cover surface swap shows on screen too, but the body
15
+ * chrome stays cinematic-dark on screen — themes only fully bloom in
16
+ * print, where the body flips to obsidian-on-white. Aurelius is
17
+ * dark-mode-only on screen by design. See `DeliverableSpec.theme`
18
+ * in hypocaust for the agent-facing description of each theme.
19
+ * - `accentColor` (hex) → `--deliverable-accent`, used for headings, rules,
20
+ * swatch surrounds. Set per-document on the React root.
21
+ * - Image grid `aspectRatio` enum → utility on the grid container.
22
+ * - Spotlight `variant` enum → utility on the spotlight section.
9
23
  */
10
24
 
11
25
  @utility deliverable {
12
26
  --deliverable-accent: var(--color-gold);
27
+ --deliverable-cover-bg: var(--color-obsidian);
28
+ --deliverable-cover-ink: var(--color-white);
29
+ --deliverable-rule-weight: 1.2pt;
30
+ --deliverable-font-heading: var(--font-heading);
31
+ --deliverable-font-body: var(--font-body);
13
32
 
14
33
  display: flex;
15
34
  flex-direction: column;
@@ -20,7 +39,34 @@
20
39
  padding-inline: var(--spacing-6);
21
40
  padding-block: var(--spacing-12);
22
41
  color: var(--color-white);
23
- font-family: var(--font-body);
42
+ font-family: var(--deliverable-font-body, var(--font-body));
43
+ }
44
+
45
+ @utility deliverable-theme-editorial {
46
+ --deliverable-accent: var(--color-obsidian);
47
+ --deliverable-cover-bg: var(--color-white);
48
+ --deliverable-cover-ink: var(--color-obsidian);
49
+ --deliverable-rule-weight: 2.4pt;
50
+ --deliverable-font-heading: "Lora", "Marcellus", serif;
51
+ --deliverable-font-body: "Inter", "Raleway", system-ui, sans-serif;
52
+ }
53
+
54
+ @utility deliverable-theme-minimal {
55
+ --deliverable-accent: var(--color-zinc);
56
+ --deliverable-cover-bg: var(--color-white);
57
+ --deliverable-cover-ink: var(--color-obsidian);
58
+ --deliverable-rule-weight: 0.6pt;
59
+ --deliverable-font-heading: "Inter", "Raleway", system-ui, sans-serif;
60
+ --deliverable-font-body: "Inter", "Raleway", system-ui, sans-serif;
61
+ }
62
+
63
+ @utility deliverable-theme-playful {
64
+ --deliverable-accent: var(--color-gold);
65
+ --deliverable-cover-bg: var(--color-white);
66
+ --deliverable-cover-ink: var(--color-obsidian);
67
+ --deliverable-rule-weight: 1.6pt;
68
+ --deliverable-font-heading: "Comic Neue", system-ui, sans-serif;
69
+ --deliverable-font-body: "Inter", "Raleway", system-ui, sans-serif;
24
70
  }
25
71
 
26
72
  @utility deliverable-page {
@@ -28,7 +74,7 @@
28
74
  }
29
75
 
30
76
  @utility deliverable-heading {
31
- font-family: var(--font-heading);
77
+ font-family: var(--deliverable-font-heading, var(--font-heading));
32
78
  font-size: var(--text-3xl);
33
79
  line-height: var(--text-3xl--line-height);
34
80
  color: var(--deliverable-accent);
@@ -45,7 +91,8 @@
45
91
  justify-content: center;
46
92
  text-align: center;
47
93
  border: 1px solid color-mix(in oklab, var(--deliverable-accent) 30%, transparent);
48
- background-color: var(--color-charcoal);
94
+ background-color: var(--deliverable-cover-bg);
95
+ color: var(--deliverable-cover-ink);
49
96
  padding: var(--spacing-16);
50
97
  }
51
98
 
@@ -59,12 +106,19 @@
59
106
  @utility deliverable-cover-eyebrow {
60
107
  text-transform: uppercase;
61
108
  letter-spacing: var(--letter-spacing-widest);
62
- color: var(--color-silver);
109
+ color: color-mix(in oklab, var(--deliverable-cover-ink) 55%, transparent);
63
110
  font-size: var(--text-xs);
64
111
  }
65
112
 
113
+ @utility deliverable-cover-rule {
114
+ height: var(--deliverable-rule-weight);
115
+ width: 6rem;
116
+ background-color: var(--deliverable-accent);
117
+ align-self: center;
118
+ }
119
+
66
120
  @utility deliverable-cover-title {
67
- font-family: var(--font-heading);
121
+ font-family: var(--deliverable-font-heading, var(--font-heading));
68
122
  font-size: var(--text-6xl);
69
123
  line-height: var(--text-6xl--line-height);
70
124
  color: var(--deliverable-accent);
@@ -74,7 +128,7 @@
74
128
  @utility deliverable-cover-subtitle {
75
129
  font-size: var(--text-xl);
76
130
  line-height: var(--text-xl--line-height);
77
- color: var(--color-silver);
131
+ color: color-mix(in oklab, var(--deliverable-cover-ink) 65%, transparent);
78
132
  }
79
133
 
80
134
  @utility deliverable-cover-client {
@@ -82,15 +136,18 @@
82
136
  font-size: var(--text-sm);
83
137
  letter-spacing: var(--letter-spacing-wider);
84
138
  text-transform: uppercase;
85
- color: var(--color-silver);
139
+ color: color-mix(in oklab, var(--deliverable-cover-ink) 55%, transparent);
86
140
  }
87
141
 
88
142
  @utility deliverable-cover-client-name {
89
- color: var(--color-white);
143
+ color: var(--deliverable-cover-ink);
90
144
  font-weight: var(--font-weight-semibold);
91
145
  }
92
146
 
93
- /* === Image grid === */
147
+ /* === Image grid ===
148
+ * The renderer always applies one of the four `aspect-ratio` utilities, so
149
+ * the base img/missing utilities don't need a fallback ratio of their own.
150
+ */
94
151
 
95
152
  @utility deliverable-image-grid {
96
153
  display: grid;
@@ -119,14 +176,40 @@
119
176
  @utility deliverable-image-img {
120
177
  width: 100%;
121
178
  height: 100%;
122
- aspect-ratio: 4 / 3;
123
179
  object-fit: cover;
124
180
  background-color: var(--color-graphite);
125
181
  border: 1px solid var(--color-ash);
126
182
  }
127
183
 
184
+ @utility deliverable-image-grid-aspect-landscape {
185
+ & .deliverable-image-img,
186
+ & .deliverable-image-missing {
187
+ aspect-ratio: 4 / 3;
188
+ }
189
+ }
190
+
191
+ @utility deliverable-image-grid-aspect-portrait {
192
+ & .deliverable-image-img,
193
+ & .deliverable-image-missing {
194
+ aspect-ratio: 3 / 4;
195
+ }
196
+ }
197
+
198
+ @utility deliverable-image-grid-aspect-square {
199
+ & .deliverable-image-img,
200
+ & .deliverable-image-missing {
201
+ aspect-ratio: 1 / 1;
202
+ }
203
+ }
204
+
205
+ @utility deliverable-image-grid-aspect-wide {
206
+ & .deliverable-image-img,
207
+ & .deliverable-image-missing {
208
+ aspect-ratio: 16 / 9;
209
+ }
210
+ }
211
+
128
212
  @utility deliverable-image-missing {
129
- aspect-ratio: 4 / 3;
130
213
  display: flex;
131
214
  align-items: center;
132
215
  justify-content: center;
@@ -141,7 +224,11 @@
141
224
  line-height: var(--line-height-snug);
142
225
  }
143
226
 
144
- /* === Spotlight === */
227
+ /* === Spotlight ===
228
+ * `framed` is the default — image above, body below.
229
+ * `full_bleed` claims the page edge-to-edge in print and a tall hero on screen.
230
+ * `side_by_side` lays image and body alongside each other (image left).
231
+ */
145
232
 
146
233
  @utility deliverable-spotlight-media {
147
234
  margin-bottom: var(--spacing-6);
@@ -171,6 +258,48 @@
171
258
  line-height: var(--line-height-relaxed);
172
259
  }
173
260
 
261
+ /* `framed` is the default and inherits the base spotlight layout — no
262
+ separate utility class is applied. */
263
+
264
+ @utility deliverable-spotlight-variant-full-bleed {
265
+ & .deliverable-spotlight-img {
266
+ max-height: 85vh;
267
+ width: 100%;
268
+ object-fit: cover;
269
+ border: none;
270
+ }
271
+ & .deliverable-spotlight-missing {
272
+ height: 70vh;
273
+ }
274
+ }
275
+
276
+ @utility deliverable-spotlight-variant-side-by-side {
277
+ display: grid;
278
+ grid-template-columns: 5fr 4fr;
279
+ grid-template-areas:
280
+ "heading heading"
281
+ "media body";
282
+ gap: var(--spacing-8);
283
+ align-items: start;
284
+
285
+ & .deliverable-heading {
286
+ grid-area: heading;
287
+ }
288
+ & .deliverable-spotlight-media {
289
+ grid-area: media;
290
+ margin-bottom: 0;
291
+ }
292
+ & .deliverable-spotlight-body {
293
+ grid-area: body;
294
+ align-self: center;
295
+ }
296
+ & .deliverable-spotlight-img {
297
+ max-height: none;
298
+ aspect-ratio: 4 / 5;
299
+ object-fit: cover;
300
+ }
301
+ }
302
+
174
303
  /* === Text block === */
175
304
 
176
305
  @utility deliverable-text-block {
@@ -206,12 +335,14 @@
206
335
  font-size: var(--text-sm);
207
336
  color: var(--color-white);
208
337
  font-weight: var(--font-weight-medium);
338
+ margin-top: var(--spacing-2);
209
339
  }
210
340
 
211
341
  @utility deliverable-palette-hex {
212
342
  font-family: var(--font-mono);
213
343
  font-size: var(--text-xs);
214
344
  color: var(--color-silver);
345
+ letter-spacing: var(--letter-spacing-wide);
215
346
  }
216
347
 
217
348
  /* === Quote === */
@@ -225,7 +356,7 @@
225
356
 
226
357
  @utility deliverable-quote-body {
227
358
  max-width: 64ch;
228
- font-family: var(--font-heading);
359
+ font-family: var(--deliverable-font-heading, var(--font-heading));
229
360
  text-align: center;
230
361
  }
231
362
 
@@ -237,7 +368,7 @@
237
368
 
238
369
  @utility deliverable-quote-attribution {
239
370
  margin-top: var(--spacing-6);
240
- font-family: var(--font-body);
371
+ font-family: var(--deliverable-font-body, var(--font-body));
241
372
  font-size: var(--text-sm);
242
373
  color: var(--color-silver);
243
374
  letter-spacing: var(--letter-spacing-wider);
@@ -265,6 +396,9 @@
265
396
  * to the full presentation.
266
397
  */
267
398
 
399
+ /* The compact card lives outside the print path and is always shown in
400
+ the cinematic chrome of the surrounding chat UI — it doesn't carry the
401
+ document's `theme`. The accent is pinned to gold here for that reason. */
268
402
  @utility deliverable-card {
269
403
  --deliverable-accent: var(--color-gold);
270
404
  display: flex;
@@ -311,28 +445,40 @@
311
445
  }
312
446
 
313
447
  /* === Print path ===
314
- * Same React tree, different paint. The strategy:
315
- * - Cover gets its own named page (`@page cover`) with no margins so it
316
- * prints full-bleed, with the body running on default pages with
317
- * normal margins.
318
- * - Body sections flow naturally only the cover forces a page break.
319
- * `break-inside: avoid` on each block keeps headings with their content
320
- * and stops grids from splitting awkwardly.
321
- * - The palette and quote no longer claim a full page each — they were
322
- * web-mode treatments, not print.
323
- * - Running footer carries page numbers; the cover suppresses it via
324
- * `@page :first`.
448
+ * Same React tree, paper-friendly paint. The strategy:
449
+ * - Cover is a full-bleed dark hero on its own page (`@page cover`,
450
+ * zero margins). All other pages run on the default A4 page with
451
+ * editorial margins and a page counter.
452
+ * - Body sections are obsidian-on-white. Each heading carries a thin
453
+ * gold rule above it as a recurring chapter mark — the same accent
454
+ * that anchors the cover, repeating to give the document rhythm.
455
+ * - Captions use Raleway italic for editorial weight, tight under the
456
+ * image.
457
+ * - Full-bleed spotlight variants get their own `@page bleed` so the
458
+ * image escapes the page margins; side-by-side variants reuse the
459
+ * screen-side grid.
460
+ * - `print-color-adjust: exact` is set once at the `.deliverable` root
461
+ * and inherited by every descendant, keeping Chromium from
462
+ * economising authored backgrounds (cover obsidian, palette chips,
463
+ * gold rules) into white.
325
464
  */
326
465
 
327
466
  @page {
328
467
  size: A4;
329
- margin: 18mm 18mm 22mm;
468
+ margin: 20mm 22mm 22mm;
330
469
  @bottom-right {
331
470
  content: counter(page);
332
471
  font-family: var(--font-body);
333
472
  font-size: 9pt;
334
473
  color: var(--color-slate);
335
474
  }
475
+ @top-left {
476
+ content: "—";
477
+ font-family: var(--font-body);
478
+ font-size: 9pt;
479
+ color: var(--color-gold);
480
+ letter-spacing: var(--letter-spacing-widest);
481
+ }
336
482
  }
337
483
 
338
484
  @page :first {
@@ -340,9 +486,27 @@
340
486
  @bottom-right {
341
487
  content: none;
342
488
  }
489
+ @top-left {
490
+ content: none;
491
+ }
492
+ }
493
+
494
+ @page bleed {
495
+ size: A4;
496
+ margin: 0;
497
+ @bottom-right {
498
+ content: none;
499
+ }
500
+ @top-left {
501
+ content: none;
502
+ }
343
503
  }
344
504
 
345
505
  @media print {
506
+ /* `print-color-adjust: exact` is inherited per the CSS Color Adjustment
507
+ spec, so setting it once at the root keeps Chromium from economising
508
+ authored backgrounds (cover obsidian, palette chips, the gold rule
509
+ ::before pseudos) into white. No need to repeat per element. */
346
510
  .deliverable {
347
511
  color: var(--color-obsidian);
348
512
  padding: 0;
@@ -351,35 +515,58 @@
351
515
  gap: 0;
352
516
  font-size: 10.5pt;
353
517
  line-height: var(--line-height-relaxed);
518
+ print-color-adjust: exact;
519
+ -webkit-print-color-adjust: exact;
354
520
  }
355
521
 
356
522
  .deliverable-page {
357
- /* Sections flow; break only when content needs more room. Avoid
358
- splitting any single block across pages. */
359
523
  page-break-inside: avoid;
360
524
  break-inside: avoid;
361
- margin-bottom: 14mm;
525
+ margin-bottom: 16mm;
362
526
  }
363
527
 
364
528
  .deliverable-page + .deliverable-page {
365
529
  margin-top: 0;
366
530
  }
367
531
 
532
+ /* Section heading: a small gold rule above the headline acts as a
533
+ recurring chapter mark, tying body sections back to the cover. */
368
534
  .deliverable-heading {
369
535
  page-break-after: avoid;
370
536
  break-after: avoid;
537
+ font-size: 22pt;
538
+ line-height: 1.15;
539
+ margin-bottom: 6mm;
540
+ color: var(--color-obsidian);
541
+ letter-spacing: var(--letter-spacing-tight);
542
+ position: relative;
543
+ padding-top: 5mm;
544
+ }
545
+
546
+ .deliverable-heading::before {
547
+ content: "";
548
+ position: absolute;
549
+ top: 0;
550
+ left: 0;
551
+ width: 14mm;
552
+ height: var(--deliverable-rule-weight);
553
+ background-color: var(--deliverable-accent);
554
+ }
555
+
556
+ /* `minimal` theme drops the chapter mark — the calmness is the message. */
557
+ .deliverable-theme-minimal .deliverable-heading::before {
558
+ display: none;
371
559
  }
372
560
 
373
561
  /* === Cover ===
374
- * Full-bleed first page. The cover is always the first section, so
375
- * `@page :first { margin: 0 }` lets it bleed; we still pad the content
376
- * inside the cover so the type doesn't sit on the page edge.
377
- */
562
+ * Full-bleed first page. Surface and ink come from the theme bundle,
563
+ * with type bottom-anchored so the page reads like a poster rather
564
+ * than centred boilerplate. */
378
565
  .deliverable-cover {
379
566
  page-break-after: always;
380
567
  break-after: page;
381
- background-color: var(--color-obsidian);
382
- color: var(--color-white);
568
+ background-color: var(--deliverable-cover-bg);
569
+ color: var(--deliverable-cover-ink);
383
570
  min-height: 297mm;
384
571
  width: 210mm;
385
572
  border: none;
@@ -392,57 +579,77 @@
392
579
  .deliverable-cover-inner {
393
580
  grid-row: 2;
394
581
  align-self: end;
395
- max-width: 28em;
582
+ max-width: 30em;
583
+ gap: 4mm;
584
+ align-items: flex-start;
396
585
  }
397
586
 
398
587
  .deliverable-cover-eyebrow {
399
588
  color: var(--deliverable-accent);
400
589
  font-size: 9pt;
590
+ margin-bottom: 2mm;
591
+ }
592
+
593
+ .deliverable-cover-rule {
594
+ width: 18mm;
595
+ height: var(--deliverable-rule-weight);
596
+ background-color: var(--deliverable-accent);
597
+ align-self: flex-start;
598
+ margin-bottom: 4mm;
401
599
  }
402
600
 
403
601
  .deliverable-cover-title {
404
- font-size: 44pt;
405
- line-height: 1.05;
406
- color: var(--color-white);
602
+ font-size: 48pt;
603
+ line-height: 1.02;
604
+ color: var(--deliverable-cover-ink);
605
+ letter-spacing: var(--letter-spacing-tight);
407
606
  }
408
607
 
409
608
  .deliverable-cover-subtitle {
410
609
  font-size: 13pt;
411
- color: var(--color-silver);
412
- margin-top: 2mm;
610
+ color: color-mix(in oklab, var(--deliverable-cover-ink) 65%, transparent);
611
+ margin-top: 3mm;
612
+ max-width: 28em;
613
+ font-style: italic;
413
614
  }
414
615
 
415
616
  .deliverable-cover-client {
416
617
  grid-row: 3;
417
618
  margin-top: 0;
418
- color: var(--color-silver);
619
+ color: color-mix(in oklab, var(--deliverable-cover-ink) 65%, transparent);
620
+ font-size: 9pt;
419
621
  }
420
622
 
421
623
  .deliverable-cover-client-name {
422
- color: var(--color-white);
423
- }
424
-
425
- /* === Body typography === */
426
- .deliverable-heading {
427
- font-size: 20pt;
428
- margin-bottom: 4mm;
429
- color: var(--deliverable-accent);
624
+ color: var(--deliverable-cover-ink);
430
625
  }
431
626
 
627
+ /* === Body typography ===
628
+ * The aurelius `prose` styles target dark-mode reading by default, with
629
+ * `--tw-prose-bold` set to white. On a paper-white print page that
630
+ * disappears, so override the prose tokens here for any markdown body
631
+ * the deliverable renders. */
432
632
  .deliverable-text-block,
433
633
  .deliverable-spotlight-body {
434
- font-size: 11pt;
435
- line-height: 1.55;
436
- max-width: 36em;
634
+ font-size: 10.5pt;
635
+ line-height: 1.6;
636
+ max-width: 34em;
437
637
  color: var(--color-obsidian);
638
+ --tw-prose-body: var(--color-obsidian);
639
+ --tw-prose-bold: var(--color-obsidian);
640
+ --tw-prose-headings: var(--color-obsidian);
641
+ --tw-prose-links: var(--deliverable-accent);
642
+ --tw-prose-quotes: var(--color-slate);
643
+ --tw-prose-quote-borders: var(--deliverable-accent);
644
+ --tw-prose-captions: var(--color-slate);
438
645
  }
439
646
 
440
647
  /* === Image grid ===
441
- * Tighter than on screen. Each item stays atomic; the grid can break
442
- * between rows but not mid-cell.
443
- */
648
+ * Tighter than on screen. Aspect-ratio rules live on the screen
649
+ * `@utility deliverable-image-grid-aspect-*` blocks and apply on every
650
+ * medium — no print duplicates needed. */
444
651
  .deliverable-image-grid {
445
- gap: 4mm;
652
+ gap: 5mm;
446
653
  }
447
654
 
448
655
  .deliverable-image-item {
@@ -451,14 +658,19 @@
451
658
  }
452
659
 
453
660
  .deliverable-image-img {
454
- aspect-ratio: 4 / 3;
455
661
  border: none;
456
662
  }
457
663
 
664
+ /* Captions in italic Raleway sit tight under the image, with a hairline
665
+ accent rule on the left coupling caption to image. */
458
666
  .deliverable-image-caption {
459
667
  color: var(--color-slate);
460
668
  font-size: 9pt;
461
- margin-top: 1.5mm;
669
+ line-height: 1.4;
670
+ font-style: italic;
671
+ margin-top: 2mm;
672
+ padding-left: 3mm;
673
+ border-left: 1px solid color-mix(in oklab, var(--deliverable-accent) 50%, transparent);
462
674
  }
463
675
 
464
676
  /* === Spotlight === */
@@ -469,28 +681,92 @@
469
681
  }
470
682
 
471
683
  .deliverable-spotlight-media {
472
- margin-bottom: 4mm;
684
+ margin-bottom: 5mm;
685
+ }
686
+
687
+ /* Full-bleed: the section claims its own zero-margin page (`@page bleed`)
688
+ and the image alone carries it. Heading and body are suppressed so the
689
+ image is the statement — author with that in mind. */
690
+ .deliverable-spotlight-variant-full-bleed {
691
+ page: bleed;
692
+ page-break-before: always;
693
+ break-before: page;
694
+ page-break-after: always;
695
+ break-after: page;
696
+ margin: 0;
697
+ padding: 0;
698
+ }
699
+
700
+ .deliverable-spotlight-variant-full-bleed .deliverable-spotlight-media {
701
+ margin: 0;
702
+ }
703
+
704
+ .deliverable-spotlight-variant-full-bleed .deliverable-spotlight-img {
705
+ width: 210mm;
706
+ height: 297mm;
707
+ max-height: none;
708
+ object-fit: cover;
709
+ border: none;
710
+ }
711
+
712
+ .deliverable-spotlight-variant-full-bleed .deliverable-heading,
713
+ .deliverable-spotlight-variant-full-bleed .deliverable-spotlight-body {
714
+ display: none;
715
+ }
716
+
717
+ /* Side-by-side: image left, body right, on the same page. Heading
718
+ spans both columns. */
719
+ .deliverable-spotlight-variant-side-by-side {
720
+ display: grid;
721
+ grid-template-columns: 95mm 1fr;
722
+ grid-template-areas:
723
+ "heading heading"
724
+ "media body";
725
+ column-gap: 8mm;
726
+ row-gap: 0;
727
+ align-items: start;
728
+ }
729
+
730
+ .deliverable-spotlight-variant-side-by-side .deliverable-heading {
731
+ grid-area: heading;
732
+ }
733
+ .deliverable-spotlight-variant-side-by-side .deliverable-spotlight-media {
734
+ grid-area: media;
735
+ margin-bottom: 0;
736
+ }
737
+ .deliverable-spotlight-variant-side-by-side .deliverable-spotlight-body {
738
+ grid-area: body;
739
+ max-width: none;
740
+ align-self: center;
741
+ }
742
+ .deliverable-spotlight-variant-side-by-side .deliverable-spotlight-img {
743
+ width: 100%;
744
+ max-height: none;
745
+ aspect-ratio: 4 / 5;
746
+ object-fit: cover;
473
747
  }
474
748
 
475
749
  /* === Palette ===
476
- * Inline strip at body width — not a full-page chart. Smaller chips,
477
- * label and hex below.
478
- */
750
+ * Inline strip at body width — not a full-page chart. */
479
751
  .deliverable-palette {
480
752
  grid-template-columns: repeat(auto-fit, minmax(28mm, 1fr));
481
- gap: 4mm;
753
+ gap: 5mm;
482
754
  max-width: 160mm;
483
755
  }
484
756
 
757
+ .deliverable-palette-item {
758
+ text-align: left;
759
+ }
760
+
485
761
  .deliverable-palette-chip {
486
762
  aspect-ratio: 1 / 1;
487
- border: 1px solid var(--color-slate);
763
+ border: 1px solid color-mix(in oklab, var(--color-obsidian) 12%, transparent);
488
764
  }
489
765
 
490
766
  .deliverable-palette-label {
491
767
  font-size: 10pt;
492
768
  color: var(--color-obsidian);
493
- margin-top: 2mm;
769
+ margin-top: 2.5mm;
494
770
  }
495
771
 
496
772
  .deliverable-palette-hex {
@@ -500,11 +776,20 @@
500
776
 
501
777
  /* === Quote ===
502
778
  * Editorial pull-quote, not a full page. Generous margins, no min-height
503
- * heroics.
779
+ * heroics. Hairline rule above signals the cadence break.
504
780
  */
505
781
  .deliverable-quote {
506
782
  min-height: 0;
507
- padding: 6mm 0 8mm;
783
+ padding: 8mm 0 10mm;
784
+ flex-direction: column;
785
+ }
786
+
787
+ .deliverable-quote::before {
788
+ content: "";
789
+ width: 14mm;
790
+ height: 1.2pt;
791
+ background-color: var(--deliverable-accent);
792
+ margin-bottom: 6mm;
508
793
  }
509
794
 
510
795
  .deliverable-quote-body {