gp-dimm-city 1.0.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 (58) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/LICENSE +32 -0
  3. package/README.md +165 -0
  4. package/components.yaml +832 -0
  5. package/fonts/lixdu/LICENSE.txt +34 -0
  6. package/fonts/lixdu/lixdu.woff +0 -0
  7. package/fonts/titillium-web/OFL.txt +93 -0
  8. package/fonts/titillium-web/titillium-web-400-italic.ttf +0 -0
  9. package/fonts/titillium-web/titillium-web-400.ttf +0 -0
  10. package/fonts/titillium-web/titillium-web-600-italic.ttf +0 -0
  11. package/fonts/titillium-web/titillium-web-600.ttf +0 -0
  12. package/fonts/titillium-web/titillium-web-700-italic.ttf +0 -0
  13. package/fonts/titillium-web/titillium-web-700.ttf +0 -0
  14. package/fonts/tomorrow/OFL.txt +93 -0
  15. package/fonts/tomorrow/tomorrow-400-italic.ttf +0 -0
  16. package/fonts/tomorrow/tomorrow-400.ttf +0 -0
  17. package/fonts/tomorrow/tomorrow-500-italic.ttf +0 -0
  18. package/fonts/tomorrow/tomorrow-500.ttf +0 -0
  19. package/fonts/tomorrow/tomorrow-700-italic.ttf +0 -0
  20. package/fonts/tomorrow/tomorrow-700.ttf +0 -0
  21. package/images/brick-bg-01.png +0 -0
  22. package/package.json +78 -0
  23. package/plugin.js +2131 -0
  24. package/snippets/alert.md +2 -0
  25. package/snippets/block.md +5 -0
  26. package/snippets/callout.md +5 -0
  27. package/snippets/card.md +11 -0
  28. package/snippets/chapter-start-page.md +11 -0
  29. package/snippets/credits-page.md +13 -0
  30. package/snippets/definition.md +7 -0
  31. package/snippets/dm-note.md +5 -0
  32. package/snippets/gear.md +9 -0
  33. package/snippets/learning-path.md +10 -0
  34. package/snippets/lede.md +5 -0
  35. package/snippets/outcome.md +8 -0
  36. package/snippets/procedure.md +7 -0
  37. package/snippets/sidebar.md +7 -0
  38. package/snippets/skill.md +9 -0
  39. package/snippets/specialty-art.md +5 -0
  40. package/snippets/specialty-card.md +5 -0
  41. package/snippets/specialty.md +11 -0
  42. package/snippets/toc-page.md +15 -0
  43. package/styles/components/callouts.css +227 -0
  44. package/styles/components/cards.css +487 -0
  45. package/styles/components/chrome.css +483 -0
  46. package/styles/components/data.css +1026 -0
  47. package/styles/components/images.css +215 -0
  48. package/styles/components/section.css +1074 -0
  49. package/styles/components/specialty-identity.css +315 -0
  50. package/styles/components/specialty.css +273 -0
  51. package/styles/dc-component-defaults.css +214 -0
  52. package/styles/dc-core.css +268 -0
  53. package/styles/dc-fonts.css +107 -0
  54. package/styles/dc-identity.css +66 -0
  55. package/styles/dc-native.css +330 -0
  56. package/styles/dc-palette.css +198 -0
  57. package/styles/page-rules.css +207 -0
  58. package/styles/page-templates.css +636 -0
@@ -0,0 +1,330 @@
1
+ /* =============================================================================
2
+ DC-NATIVE.CSS — engine-specific page chrome
3
+ =============================================================================
4
+ The LAST entry in package.json `gutterpress.styles`, and deliberately
5
+ unlayered, so it beats every layered sheet in this package and in the
6
+ book. A book's own unlayered sheet listed after the extension still wins
7
+ over it — that is the one hook a book has above this file.
8
+
9
+ Mechanics, each measured against Chromium 151 (gutterpress ENGINE.md §5/§8):
10
+ - ONE `@page { background }` rule paints the brick wall across the whole
11
+ sheet: the content box, and every margin box that carries no content of
12
+ its own shows it through. The old two-layer paint (`html { background }`
13
+ for the content area + 14 hand-fed margin boxes + 6 refills in §4) is
14
+ gone — one origin for the wall instead of twenty-one.
15
+ - Margin boxes support background/border/counter()/fit-content; they do
16
+ NOT support transform: rotate() or box-shadow — the sticker chrome is
17
+ square and unshadowed.
18
+ - Any box past the page content box (or the sheet, on reduced-margin
19
+ pages) triggers whole-document print shrink-to-fit. Nothing in this
20
+ file may protrude; the frontmatter template zeroes only the SIDE
21
+ margins so the vertical arithmetic of the margined design is untouched.
22
+
23
+ The chip CONTENT (folio / chapter strings) comes from page-rules.css's
24
+ @page :left/:right rules — standard CSS, engine-agnostic. This file adds
25
+ visual chrome only.
26
+ ─────────────────────────────────────────────────────────────────────────── */
27
+
28
+ /* ── 1. THE BRICK WALL — one rule, whole sheet ──────────────────────────────
29
+ A margin box with no content of its own shows the page background through,
30
+ so this single rule paints the content box AND the margin band. It replaces
31
+ the old `html { background }` content-area layer, the 14 hand-fed empty
32
+ margin boxes, and §4's six refills — 21 tiling origins became one, so the
33
+ wall is seamless: no phase break at a box edge, and no flat --bg patch in
34
+ the bottom band beside the chips. */
35
+ @page {
36
+ background: var(--bg) url("../images/brick-bg-01.png") repeat;
37
+ background-size: 1.5in auto;
38
+ background-blend-mode: multiply;
39
+ }
40
+
41
+ /* ── 3. FOLIO + CHAPTER STICKERS ────────────────────────────────────────────
42
+ Chrome for the chip content page-rules.css declares on @bottom-left /
43
+ @bottom-right. Sticker identity swaps by spread side in page-rules.css's
44
+ content rules (folio outside, chapter tag inside); the chrome swaps the
45
+ same way.
46
+
47
+ BOTH axes must be fit-content. A margin box defaults to the size of its
48
+ SLOT, and the slot is big: per marginBoxRectPt (gutterpress
49
+ engine/shared/margin-box-support.ts) `@bottom-left` is a third of the
50
+ content width by the whole bottom margin — 174 x 54pt on this book's page.
51
+ `width: fit-content` alone tightened only the inline axis, so the stickers
52
+ printed as FULL-HEIGHT RECTANGLES filling the margin band rather than as
53
+ pills.
54
+
55
+ MEASURED, field-guide p10/p11 rasterised at 150dpi and profiled through
56
+ each chip's interior:
57
+
58
+ folio (paper-cream + ink border) 52.3pt tall -> 14.9pt
59
+ chapter (paper-aged + dashed rule) 53.3pt tall -> 14.4pt
60
+
61
+ against a 53.8pt band. Both chips' widths and column spans are unchanged
62
+ (folio 71-77px, chapter 78px at 150dpi; folio left / chapter right on the
63
+ verso, mirrored on the recto), so this is a block-axis change only and the
64
+ recto/verso mirroring is untouched. NOTE for the design pass: a shrunk
65
+ margin box stays anchored at its slot's START edge, so the chips now sit
66
+ at the TOP of the bottom-margin band, tucked under the text block, rather
67
+ than centred in it.
68
+
69
+ Shrinking the box no longer punches a hole in the margin band: §1's
70
+ `@page` background paints underneath, so the wall shows through the rest
71
+ of the slot on its own. */
72
+ @page :left {
73
+ @bottom-left {
74
+ /* folio sticker — civic register */
75
+ width: fit-content;
76
+ height: fit-content;
77
+ font-family: var(--font-mono);
78
+ font-size: 9pt;
79
+ font-weight: 700;
80
+ letter-spacing: 0.1em;
81
+ text-transform: uppercase;
82
+ padding: 3px 9px;
83
+ color: var(--ink-dark);
84
+ background: var(--paper-cream);
85
+ border: 1px solid var(--ink-dark);
86
+ }
87
+ @bottom-right {
88
+ /* chapter sticker — stamped coupon */
89
+ width: fit-content;
90
+ height: fit-content;
91
+ font-family: var(--font-display);
92
+ font-size: 9pt;
93
+ font-weight: 700;
94
+ letter-spacing: 0.06em;
95
+ text-transform: uppercase;
96
+ padding: 2.5px 8px;
97
+ color: var(--blood);
98
+ background: var(--paper-aged);
99
+ border: 1.5px dashed var(--hud-magenta);
100
+ }
101
+ }
102
+
103
+ @page :right {
104
+ @bottom-left {
105
+ /* chapter sticker — stamped coupon */
106
+ width: fit-content;
107
+ height: fit-content;
108
+ font-family: var(--font-display);
109
+ font-size: 9pt;
110
+ font-weight: 700;
111
+ letter-spacing: 0.06em;
112
+ text-transform: uppercase;
113
+ padding: 2.5px 8px;
114
+ color: var(--blood);
115
+ background: var(--paper-aged);
116
+ border: 1.5px dashed var(--hud-magenta);
117
+ }
118
+ @bottom-right {
119
+ /* folio sticker — civic register */
120
+ width: fit-content;
121
+ height: fit-content;
122
+ font-family: var(--font-mono);
123
+ font-size: 9pt;
124
+ font-weight: 700;
125
+ letter-spacing: 0.1em;
126
+ text-transform: uppercase;
127
+ padding: 3px 9px;
128
+ color: var(--ink-dark);
129
+ background: var(--paper-cream);
130
+ border: 1px solid var(--ink-dark);
131
+ }
132
+ }
133
+
134
+ /* ── 4. STICKER SUPPRESSION on chrome-free named pages ──────────────────────
135
+ §1's `@page` background paints through a box that generates nothing, so
136
+ suppression is just clearing the chip's content — no brick refill needed,
137
+ which makes page-rules.css's own `@page chapter-start` / `@page clean`
138
+ `content: none` blocks sufficient on their own; only `:blank` has no
139
+ counterpart there, so only `:blank` is restated here. */
140
+ @page :blank {
141
+ @bottom-left { content: none; }
142
+ @bottom-right { content: none; }
143
+ }
144
+
145
+ /* ── 5. FRONTMATTER (TOC + Credits): full-bleed composite under native ──────
146
+ Target: masthead band edge-to-edge including its own rows, wall behind,
147
+ plate at the sheet bottom of the credits. Native print clips painting at
148
+ the content box and punishes any box past it with whole-document
149
+ shrink-to-fit, so the page SHAPE changes instead of the paint overflowing:
150
+
151
+ - side margins 0 and bottom margin 0 on the front-matter template — the
152
+ content box spans the full sheet width and reaches the sheet bottom,
153
+ so the h1's side pulls and the plate's bottom seat are VISIBLE paint
154
+ inside the content box, never overflow (verified clean with
155
+ no-founders in the side-0 variant; the bottom-0 extends the same
156
+ principle);
157
+ - the top margin (0.5in) stays, painted ink-dark by the top margin
158
+ boxes, so the band runs from the sheet top edge through the h1's own
159
+ rows;
160
+ - text re-insets itself via page padding. */
161
+ @page front-matter {
162
+ margin: 0.5in 0 0 0;
163
+ @top-left-corner { content: ""; background: var(--ink-dark); }
164
+ @top-left { content: ""; background: var(--ink-dark); }
165
+ @top-center { content: ""; background: var(--ink-dark); }
166
+ @top-right { content: ""; background: var(--ink-dark); }
167
+ @top-right-corner { content: ""; background: var(--ink-dark); }
168
+ }
169
+ @page front-matter:left { margin: 0.5in 0 0 0; }
170
+ @page front-matter:right { margin: 0.5in 0 0 0; }
171
+ .page.page-toc,
172
+ .page.page-credits {
173
+ box-sizing: border-box;
174
+ padding: 0 0.625in;
175
+ margin-top: 0;
176
+ }
177
+ .page.page-toc {
178
+ /* breathing room between the TOC card and the sheet bottom */
179
+ padding-bottom: 0.75in;
180
+ }
181
+ /* Credits page as a full-height flex column so a pinned founders plate
182
+ (`.gp-pin .gp-bottom .gp-full`) seats on the sheet edge. Exact `height`
183
+ rather than core's `min-height` cushion so the pin's containing block ends
184
+ exactly on the sheet edge. Carried from the field guide's native sheet in
185
+ 1.0.0: every Dimm City book writes this page. */
186
+ .page.page-credits {
187
+ display: flex;
188
+ flex-direction: column;
189
+ height: var(--gp-content-h);
190
+ padding-bottom: 0;
191
+ }
192
+ .page.page-credits .section.credits-colophon {
193
+ flex: 1 1 auto;
194
+ min-height: 0;
195
+ display: flex;
196
+ flex-direction: column;
197
+ margin-bottom: 0;
198
+ }
199
+ /* The masthead escapes the padding back to the sheet edges — visible paint
200
+ inside the full-width content box. `margin-top: 0` is deliberate: a
201
+ negative top pull here drags a band fragment onto the previous page
202
+ (measured). The dark strip above is margin-box paint. */
203
+ .page.page-toc h1.dc-chevron,
204
+ .page.page-credits h1.dc-chevron {
205
+ margin-top: 0;
206
+ margin-left: -0.625in;
207
+ margin-right: -0.625in;
208
+ width: calc(100% + 1.25in);
209
+ box-sizing: border-box;
210
+ }
211
+
212
+ /* In-flow art must never be sliced across a page boundary. */
213
+ p.dc-img-wrapper,
214
+ figure {
215
+ break-inside: avoid;
216
+ }
217
+ /* Full-bleed plates fill their margin-0 page exactly; sub-pixel rounding
218
+ was slicing the last rows of the image onto the next page. */
219
+ .dc-full-page {
220
+ overflow: clip;
221
+ }
222
+
223
+ /* ── 10. MULTI-COLUMN SECTIONS must fragment naturally ──────────────────────
224
+ `.section` carries `break-inside: avoid` from THIS BOOK's own
225
+ components/*.css (core no longer ships that default, but the book still
226
+ sets it). Measured DOM shape: `.gp-columns-2` is a WRAPPER div (the multicol
227
+ container, columns:2) and the `.section` blocks sit INSIDE it. A section
228
+ taller than one column can then never split, so Chromium drops it whole
229
+ into one column fragment and the facing column dies — the dead-column
230
+ collapse. Removing this override cost 3 pages of pagination churn when
231
+ measured (302pp vs 299pp), so it is load-bearing, not legacy.
232
+
233
+ Keys on the COUNT class, not `.dc-column-panel`: this is about multicol
234
+ fragmentation, and the wrapper shape is often a `@block` or `@page` that
235
+ never carries the panel chrome at all. */
236
+ .gp-columns-2 .section,
237
+ .gp-columns-3 .section {
238
+ break-inside: auto;
239
+ }
240
+
241
+ /* ── 10b. COLUMN-FILL is a per-shape decision, and it lives HERE ────────────
242
+ (10b, not 11: a §11 was deleted from this file before this block existed,
243
+ and §13 below still cross-references that old §11. Taking the number would
244
+ silently redirect a live reference at the wrong rules.)
245
+ Core deliberately ships no `column-fill` on `.gp-columns-*` (the right
246
+ value depends on whether the run fragments, and only the author knows).
247
+ page-templates.css used to answer `balance` for the whole book; under
248
+ native print the wrapper fragments across pages, and Chromium's
249
+ balance-in-fragmentation leaves every non-final fragment with a dead right
250
+ column (measured: proof17 p12/p13). Sequential fill packs both columns per
251
+ page — the behavior the engine's multicol fixture verified. */
252
+ .gp-columns-2,
253
+ .gp-columns-3 {
254
+ column-fill: auto;
255
+ }
256
+ /* Per the measured rule (docs/native-engine-styling-guide.md §5): balance is
257
+ correct for single-page multicol, auto only for FRAGMENTING multicol.
258
+ The general `.gp-columns-2`/`.gp-columns-3` rule above stays `auto` — it is
259
+ load-bearing for the WRAPPER shape (a plain div around several `.section`
260
+ children, e.g. p12/p13's "THE PACK SHOULD BE WEIRD" walkthrough, and
261
+ p243's CORE ELEMENTS section, where the dc-alert callout is itself taller
262
+ than a column and MUST be allowed to fragment; see §13 below). A
263
+ `.section` that is ITSELF the multicol container is NOT reliably short —
264
+ CORE ELEMENTS is that same DOM shape (`.section.gp-columns-2`) and needs
265
+ `auto`, so shape alone can't tell "fits on one page" from "runs long".
266
+
267
+ Two exceptions, both scoped so they cannot catch the fragmenting case:
268
+
269
+ (a) p7's "Image Is Everything" aside — a short paragraph + a short callout,
270
+ nothing left to balance — scoped to its own authored classes rather than
271
+ promoted to a general `.section.gp-columns-2` rule that would also catch,
272
+ and break, CORE ELEMENTS. If a future page reuses
273
+ `.dc-citizen-walkthrough.gp-columns-2` with long enough content to actually
274
+ fragment, the compiler's own multicol-fragmentation check flags it and
275
+ tells the author to add column-fill: auto locally — not a silent trap.
276
+
277
+ (b) a PAGE that is itself the multicol container. A `.page` is one sheet by
278
+ construction, so its run does not fragment and balance is the correct
279
+ value. This carries forward the `.page.two-column { column-fill: balance }`
280
+ that page-templates.css used to win with on specificity alone (0-2-0 over
281
+ this file's 0-1-0); stating it here puts it next to the reasoning and the
282
+ measurements instead of leaving it to load order. Live user:
283
+ `@page .dc-citizen-file-page .gp-columns-2` in the design guide. */
284
+ .dc-citizen-walkthrough.gp-columns-2,
285
+ .page.gp-columns-2 {
286
+ column-fill: balance;
287
+ }
288
+
289
+ /* ── 12. WALL ART placement is the markdown's, via core's gp-* classes ──────
290
+ Do not add a position/float/margin declaration to a `.fg-art-*` class that
291
+ the markdown also pins. A `.fg-art-*` class beats `.gp-pin` at equal
292
+ specificity — the book's sheets load after GUTTERPRESS_CSS — so such a rule
293
+ silently DE-PINS whatever the author asked for. Measured on blue-bot
294
+ (chapter-01 "At a Glance"), which the markdown authors
295
+ `.gp-pin .gp-bottom .gp-left`. */
296
+
297
+ /* ── 13. NO EMPTY FIRST FRAGMENTS on boxed callouts ─────────────────────────
298
+ §11's break-after: avoid keeps a heading with the box that follows, but
299
+ the box itself can still emit a contentless first fragment (top border +
300
+ padding only) at a page bottom — measured: CORE ELEMENTS, p244. Gluing
301
+ the box's first child to the box start moves the whole start (and, via
302
+ §11, the heading) to the next page. break-inside: avoid is NOT usable
303
+ here: these callouts routinely run taller than a page. */
304
+ .dc-dm-note > :first-child,
305
+ .dc-callout > :first-child {
306
+ break-before: avoid;
307
+ }
308
+
309
+ /* Measured (p243, DOM-inspected): the CORE ELEMENTS heading is a full-width
310
+ spanner inside a .gp-columns-2 section, followed by a dc-alert callout
311
+ whose break-inside: avoid is UNENFORCEABLE (the card is taller than a
312
+ column). Chromium then emits an empty card fragment under the spanner —
313
+ header stranded, content headerless on the next page. A card that may
314
+ fragment starts filling right under its header instead. Scoped to
315
+ multicol sections only; standalone cards keep their avoid. */
316
+ .gp-columns-2 .dc-alert,
317
+ .gp-columns-3 .dc-alert {
318
+ break-inside: auto;
319
+ }
320
+
321
+ /* Skill-card tabs (MNEMONIC PLAGUE, p114): the .dc-card-tab chip is a
322
+ separate block from its .dc-card-body, so a page break can land between
323
+ them, stranding the tab alone at a page bottom. Glue tab to body, and the
324
+ body's first child to the body start. */
325
+ .dc-card-tab {
326
+ break-after: avoid;
327
+ }
328
+ .dc-card-body > :first-child {
329
+ break-before: avoid;
330
+ }
@@ -0,0 +1,198 @@
1
+ @layer dc.tokens {
2
+
3
+ /* ── DESIGN TOKENS ────────────────────────────────────────────────────────── */
4
+ :root {
5
+
6
+ /* ── Page & Paper ─────────────────────────────────────────────────────── */
7
+ /* Paper substrate shifted from warm cream/manila to neutral-cool light
8
+ greys (2026-05-24). The previous warm-cream register read vintage /
9
+ fantasy-coded against the urban-concrete brick-wall background and
10
+ made the book feel less Dimm-City than it should. Greys read as
11
+ "industrial flyer paper / printer stock" — closer to the actual
12
+ real-world surface posters get pasted on in a creaturepunk city. */
13
+ --bg: #c8c5bf; /* ash-concrete — the brick wall (page background, L*~70) */
14
+ --concrete-pale: #dcdad5; /* pale concrete swatch — light cool grey lifted from the wall; substrate for lede/intro panels that should read cold-grey, not paper-cream */
15
+ --paper-cream: #f0eee9; /* light industrial flyer-stock — brighter than wall, more poster-vs-wall delta (L*~93) */
16
+ --paper-light: #e2ded7; /* slightly darker grey alternate surface — for layered paper / secondary panels */
17
+ --paper-aged: #c8c2b8; /* weathered grey — decay register, dust + age */
18
+ --paper-stain: #b0a89c; /* deep stain — dark inset wells, smoke-grey */
19
+ /* Poster-wall shadow — hard offset, no blur. Pins paper-register
20
+ components to the wall as physical objects. Applied to specialty
21
+ cards, skill cards, sections, paper-variant callouts, NPC stat
22
+ blocks, citizen file — anything that should read as "stuck on
23
+ the wall" rather than "embedded in the page." */
24
+ --shadow-poster: 2pt 3pt 0 rgba(0, 0, 0, 0.28);
25
+
26
+ /* ── Ink & Text — warm sepia drift, not neutral gray ─────────────────── */
27
+ --ink: #1a1512; /* near-black with red bias — riso warm black */
28
+ --ink-dark: #2b231d; /* warmer secondary heading weight */
29
+ --ink-smoke: #4d4339; /* sepia mid-tone — body emphasis */
30
+ --ink-mid: #594f43; /* between smoke and dust — secondary card text */
31
+ --ink-dust: #665b4e; /* darkened (was #756a5c) — 4.58:1 on new lighter paper-cream #f0eee9 */
32
+
33
+ /* ── Accents — creaturepunk fire + blood ─────────────────────────────── */
34
+ --crimson: #e1261c; /* PMS Red 032 — CMYK 0 95 90 0; survives POD */
35
+ --blood: #901a12; /* oxidised arterial — 5.2:1 on paper-cream */
36
+ --orange: #d4500a; /* burnt circuit-board — heat-damaged, not friendly cone */
37
+ --orange-deep: #a03808; /* burnt fire-deep — paper-cream 5.25:1 (deeper variant for small-text-on-fill contexts) */
38
+ --rust: #b23a12; /* burnt rebar edge */
39
+ --amber: #7a5a20; /* sulfur-scorched brass — contaminated, not generic earth */
40
+ --deep-rust: #6a1a08; /* shadow rust — deepest warm dark */
41
+ --amber-dark: #5c3c10; /* charred amber — follows amber down */
42
+
43
+ /* ── Brand Signature Layer — print-safe analogs of dimm.city web palette
44
+ These three are the source of truth for "the dimm.city signature in print."
45
+ Values are SWOP/substrate-corrected from the website's pure-RGB tokens
46
+ (#d946ef / #00ffff / #ffd700) so they survive POD press without muddying.
47
+ HUD + signal tokens below alias these — touch the brand layer first. */
48
+ --brand-magenta: #c026d3; /* dimm.city cyber-magenta, SWOP-corrected from web #d946ef */
49
+ --brand-magenta-deep: #8a0a9a; /* jewel-deep cyber-magenta — paper-cream 6.21:1 (small-text-on-fill safe) */
50
+ --brand-cyan: #00bcd4; /* dimm.city neon-cyan, paper-contrast-tuned from web #00ffff */
51
+ --brand-yellow: #ffd700; /* dimm.city brand-yellow — survives press unchanged */
52
+ --brand-violet: #7030b8; /* dimm.city cyber-violet, SWOP-corrected from web #a020f0 */
53
+
54
+ /* ── HUD Colors — digital neon chrome ────────────────────────────────── */
55
+ --hud-blue: #1f6f94; /* teal-cyan mid HUD — CMYK 85 45 25 10 */
56
+ --hud-blue-dark: #14516e; /* deep teal for borders/rules/H2 text */
57
+ --hud-blue-bright: var(--brand-cyan); /* alias — substrate-safe neon-cyan accent; 5 consumers — see audit 2026-05-27 */
58
+ --hud-blue-dim: #7ab8d0; /* visible-on-cream panel tint (was #b8d8e8 — invisible at L*84) */
59
+ --hud-magenta: var(--brand-magenta); /* alias — brand-signature cyber-magenta; 29 consumers — see audit 2026-05-27 */
60
+ --hud-panel: #eeece8; /* neutral light cream — callouts, note bars */
61
+
62
+ /* ── Surface Tints ────────────────────────────────────────────────────── */
63
+ --surface-tint-3: #f2f0ec; /* public token: consumed by the Dimm City design guide's own sheet (palette swatches), not by this package */
64
+ --surface-orange-tint: #d8cfb4; /* warmer gold tint on aged paper */
65
+
66
+ /* ── Borders ──────────────────────────────────────────────────────────── */
67
+ --border-hairline: #c8b898; /* warmer/darker hairline on aged paper */
68
+ --bw-thin: 1px;
69
+ --callout-border-width-small: 2px;
70
+
71
+ /* ── Shadow color tint ────────────────────────────────────────────────── */
72
+ --shadow-tint: #b0a898; /* hex color used as shadow tint — this is a color, not a shadow shorthand */
73
+
74
+ /* ── Type Families ────────────────────────────────────────────────────── */
75
+ --font-display: 'lixdu', 'Tomorrow', sans-serif;
76
+ --font-tab: 'Tomorrow', 'lixdu', sans-serif;
77
+ --font-body: 'Titillium Web', Georgia, sans-serif;
78
+ --font-sans: 'Titillium Web', 'Inter', system-ui, sans-serif;
79
+ --font-mono: 'Tomorrow', 'Titillium Web', ui-monospace, monospace;
80
+ --font-quote: 'Titillium Web', 'Tomorrow', serif;
81
+
82
+ /* ── Type Scale — modular ~1.23× ratio, 12pt body anchor ──────────────
83
+ h1/h2: 1.30× h2/h3: 1.25× h3/h4: 1.23× h4/h5: 1.18× h5/h6: 1.22×
84
+ H5 == body-sm: display font + caps + tracking provide differentiation.
85
+ H6 below body: metadata-only; display font keeps it legible.
86
+ ────────────────────────────────────────────────────────────────────── */
87
+ --fs-body: 12pt;
88
+ --fs-body-sm: 11pt; /* design floor — never below this for prose */
89
+ --fs-body-xs: 11.5pt; /* between sm and body */
90
+ --fs-sm: 11pt; /* small body — aligns to --fs-body-sm */
91
+ --fs-h1: 26pt; /* anchor — chapter/page-level titles */
92
+ --fs-h2: 20pt; /* section headers; 1.30× below h1 */
93
+ --fs-h3: 16pt; /* sub-section, gear card titles; 1.25× below h2 */
94
+ --fs-h4: 13pt; /* skill card names, stat block NPC names; 1.23× below h3 */
95
+ --fs-h5: 11pt; /* field labels, stat-block sublabels; 1.18× below h4 */
96
+ --fs-h6: 9pt; /* metadata only; 1.22× below h5 */
97
+ --fs-chapter: 26pt; /* chapter openers — matches h1 */
98
+
99
+ --fw-bold: 700;
100
+
101
+ --lh-tight: 1.35;
102
+ --lh-normal: 1.5;
103
+
104
+ --ls-display: 0.1em;
105
+ --ls-heading: 0.08em;
106
+ --ls-cap-sm: 3px; /* mono micro-caps */
107
+
108
+ /* ── Spacing — print units ────────────────────────────────────────────── */
109
+ --space-xs: 0.05in; /* ~3.6pt — tighter than --space-sm */
110
+ --space-sm: 0.08in; /* ~6pt */
111
+ --space-md: 0.12in; /* ~9pt */
112
+ --space-lg: 0.15in; /* ~11pt */
113
+ --space-xl: 0.20in; /* ~14pt */
114
+
115
+ /* Vertical breathing room between stacked card components (skill cards,
116
+ learning-path shells, specialty cards). This is the
117
+ VISIBLE gap the reader sees. Components whose chrome paints OUTSIDE
118
+ their border-box (filter: drop-shadow / box-shadow) add their own bleed
119
+ compensation on top of this value — margin is layout space, but a shadow
120
+ paints past the box without affecting layout, so a margin sized only for
121
+ the box model gets visually eaten. See .dc-skill-card in components.
122
+ Retune card spacing across the whole book by changing THIS ONE value. */
123
+ --dc-card-gap: 0.15in; /* ~11pt */
124
+
125
+ --gutter: 0.15in; /* two-column structural gutter */
126
+ --page-margin: 0.5in;
127
+ --outer-margin: 0.625in; /* outer (non-binding) page margin */
128
+ --sidebar-width: 3.05in;
129
+
130
+ /* Inset-sidebar right column. `.dc-sidebar.inset` is a full-height rail
131
+ pinned to the page's right edge, so the page must RESERVE this column or
132
+ the rail paints on top of the body text (it did, until 2026-08-22).
133
+ --dc-sidebar-inset-column is the rail's OUTER width (it is border-box);
134
+ the gutter is the gap between body text and the rail. page-templates.css
135
+ turns the pair into the hosting page's padding-right. */
136
+ --dc-sidebar-inset-column: 3.4in;
137
+ --dc-sidebar-inset-gutter: 0.2in;
138
+
139
+ /* ── Page Geometry ────────────────────────────────────────────────────── */
140
+ --page-width: 8.625in;
141
+ --page-height: 11.25in;
142
+ --binding-margin: 0.75in;
143
+
144
+ /* ── Shapes ───────────────────────────────────────────────────────────── */
145
+ /* Chevron banner / section right-edge inset. Used by --clip-banner, by
146
+ the chapter-opener intro section's clip-path + padding-right, and by
147
+ the chapter-opener h1's negative margin-right. */
148
+ --clip-tail: 22px;
149
+ --clip-banner: polygon(0 0, 100% 0, calc(100% - var(--clip-tail)) 100%, 0 100%);
150
+
151
+ /* ── Chapter-opener composite (components/*.css consumes these) ──────
152
+ Token contract — override at the chapter id scope to customise a
153
+ specific chapter's opener without affecting any other chapter:
154
+ #ch-chapter-2 .chapter {
155
+ --dc-chapter-opener-accent: var(--augmerc-deep);
156
+ --dc-chapter-opener-clip-tail: 32px;
157
+ } */
158
+ --dc-chapter-opener-accent: var(--brand-magenta-deep);
159
+ --dc-chapter-opener-clip-tail: 22px;
160
+ --dc-chapter-opener-bg: var(--paper-cream);
161
+ --dc-chapter-opener-pad-top: var(--space-md);
162
+ --dc-chapter-opener-pad-side: var(--space-lg);
163
+ /* Right-side padding is independent from --clip-tail. The clip-tail is
164
+ the *visual* right inset (where the chevron's tail and the section
165
+ substrate end). The pad-right is the *content* right inset (where
166
+ body text ends). Pad-right > clip-tail gives body text breathing
167
+ room inside the visible substrate instead of running flush to the
168
+ clipped edge. */
169
+ --dc-chapter-opener-pad-right: calc(var(--dc-chapter-opener-clip-tail) + var(--space-md));
170
+ /* Cohesive drop shadow for the chapter-opener composite. Hard offset
171
+ (no blur) matches the "poster pinned to a wall" aesthetic used by
172
+ the existing --shadow-poster token. Applied via filter:drop-shadow
173
+ on the chapter-opener page so it follows the union silhouette
174
+ (badge + tapered chevron + section substrate) as a single shape. */
175
+ --dc-chapter-opener-shadow: 3px 4px 0 rgba(0, 0, 0, 0.28);
176
+
177
+ /* ── Fluorescent Fungi Pillar (creaturepunk: bioluminescent organic) ─────
178
+ The 4th creaturepunk register: spore-light, lichen-glow, UV-reactive
179
+ bio-organic green family. Distinct from the gutter pillar (rust/blood)
180
+ and the neon pillar (brand-magenta/cyan/yellow) — this is "alive and
181
+ glowing" rather than "signal" or "decay". CMYK-safe:
182
+ fungi-glow ≈ C30/M0/Y90/K0 = 120%
183
+ fungi-rot ≈ C50/M30/Y100/K60 = 240% (large fills only) */
184
+ --fungi-glow: #c8e040; /* bioluminescent yellow-green — UV spore-light (consumed: .dc-outcome-row.hit, --gutterdruid-accent) */
185
+ --fungi-rot: #2a4015; /* deep moldering green — rot in dark places (consumed: .dc-outcome-row.fail; large-fill only — TAC 176%) */
186
+
187
+ /* ── Ancient Crystal Pillar (creaturepunk: faceted mineral refraction) ───
188
+ The mineral-magic register: amethyst and aquamarine — geometric and
189
+ refractive. Distinct from brand-violet (signal-saturated) and the warm
190
+ gold of brand-yellow (electric). CMYK-safe:
191
+ crystal-amethyst ≈ C50/M65/Y0/K35 = 150%
192
+ crystal-aqua ≈ C70/M28/Y28/K20 = 146% */
193
+ --crystal-amethyst: #6a3a8a; /* deep mineral violet — refractive arcane (consumed: --generalist-accent) */
194
+ --crystal-aqua: #4a98a8; /* pale crystalline aquamarine (consumed: --dualist-accent) */
195
+
196
+ }
197
+
198
+ }