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,487 @@
1
+ @layer dc.components {
2
+
3
+ /* ═══ CARD SYSTEM ═══ */
4
+
5
+ /* Token contract for .dc-skill-card:
6
+ --dc-card-accent → tab border + body accent rule (default --ink)
7
+ --dc-card-surface → card body background (default --paper-cream)
8
+ --dc-card-tab-bg → tab background (default --ink-dark)
9
+ --dc-card-tab-title-color → tab title text color (default --paper-cream)
10
+ --dc-card-tier-color → tier-badge fill (default --hud-magenta)
11
+ --dc-card-tier-border → tier-badge border (default --hud-magenta)
12
+ --dc-card-body-mark → decorative ::before mark color (default --crimson)
13
+ Specialty themes override these via .dc-specialty.<name> .dc-skill-card { }.
14
+ Adding a new specialty: copy a sibling block (.dc-specialty.augmerc .dc-skill-card)
15
+ and replace token values with the new specialty's --<name>-* aliases. */
16
+
17
+ /* ── Skill card shell ─────────────────────────────────────────────────── */
18
+ /* Token defaults for .dc-skill-card are declared in :root in dc-component-defaults.css.
19
+ Specialty contexts override via .dc-specialty.<name> .dc-skill-card { } below. */
20
+ .dc-skill-card {
21
+ position: relative;
22
+ /* The card's chrome — poster shadow, ink outline, surface — is three
23
+ pseudos at negative z-index (below). isolation: isolate is the stacking
24
+ context that keeps them behind THIS card's content rather than escaping
25
+ to the nearest context above and painting behind the page; `.section`
26
+ declares it for the same reason. The drop-shadow filter that used to sit
27
+ here supplied that context implicitly (every filter creates one). */
28
+ isolation: isolate;
29
+ /* A filter's shadow was ink — it never counted as overflow. A positioned
30
+ pseudo is a box, and a box past the page content box makes Chromium
31
+ print shrink-to-fit scale the WHOLE book (the engine's width guard
32
+ measured this card's shadow at 713px against a 708px content box and
33
+ refused the build). Clipping the card's own horizontal overflow contains
34
+ it: the guard and Chromium both treat clipped overflow as contained
35
+ (build.ts, findWidthOffenders). It changes nothing visible on a card
36
+ that spans the page content box — the page already clipped the filter's
37
+ rim and shadow at exactly these two edges, so the printed card has never
38
+ had chrome on its left or right; a narrower card would lose its side
39
+ chrome to this clip. Only x: the bottom shadow and the outlines above
40
+ and below stay. */
41
+ overflow-x: clip;
42
+ break-inside: avoid;
43
+ /* --dc-card-gap is the VISIBLE gap; the +6px clears chrome bleed on top of
44
+ it. Margin is layout space, but the shadow and outline pseudos paint
45
+ outside the border-box without affecting it: this card's hard poster
46
+ shadow (2pt 3pt offset = 4px down) reaches 4px past its own bottom edge,
47
+ and the NEXT card's top ink-outline reaches 2px past its top edge. 4 + 2 =
48
+ 6px. The old margin-bottom was exactly 6px, so it was entirely consumed
49
+ and consecutive cards rendered touching (screenshot-confirmed on the
50
+ Augmerc BODYCOVER/BLITZ seam). Same class of fix as .fg-art-portrait's
51
+ margin-bottom in the book's own sheet (`@layer book`). */
52
+ margin-bottom: calc(var(--dc-card-gap) + 6px);
53
+ max-width: 100%;
54
+ /* 4-way ink outline (2px on each side) + HARD offset poster shadow. The
55
+ hard shadow (2pt 3pt 0, no blur) pins the card to the brick wall as a
56
+ physical object; it replaced a soft 8px-blur drop shadow that read as
57
+ web-UI floating, not poster-on-wall stuck-on. Both used to be a five-stop
58
+ `filter: drop-shadow()` chain on this element. They are now the clipped
59
+ vector pseudos on .dc-card-tab, .dc-card-body and .dc-card-inner below
60
+ (dc#28): a filter makes Chromium rasterize the whole subtree into a
61
+ 300 DPI bitmap at print — 166 cards were most of the field guide's build
62
+ time and turned every card's text into pixels — where a clipped pseudo
63
+ filled with the shadow colour is pure vector, the technique `.section`
64
+ already uses. */
65
+ }
66
+
67
+ /* ── Continuation markers ─────────────────────────────────────────────── */
68
+ /* REMOVED 2026-07-25: .dc-card-cont-marker / .dc-card-fwd-marker.
69
+ Nothing ever emitted those nodes. They were injected only by
70
+ plugins/dimm-city-runtime.js, which was never loaded — print-md has no
71
+ script-injection hook (no manifest `scripts` key, no plugin `scripts`
72
+ export, and assemble.ts's <head> template is fixed), so the file was dead
73
+ and has been deleted. Split-card continuation markers are therefore an
74
+ UNIMPLEMENTED feature; docs that describe them (04-components.md,
75
+ 09-component-gallery.md, docs/components-and-palette-reference.md) are
76
+ stale. Wiring this up requires a script hook in print-md itself. */
77
+
78
+ /* ── Card tab ─────────────────────────────────────────────────────────── */
79
+ .dc-card-tab {
80
+ display: inline-flex;
81
+ align-items: center;
82
+ gap: 12px;
83
+ padding: 3px 18px 3px 8px;
84
+ background: var(--dc-card-tab-bg);
85
+ border: 2px solid var(--dc-card-accent);
86
+ border-bottom: 0;
87
+ margin-left: 10px;
88
+ margin-bottom: -2px;
89
+ position: relative;
90
+ z-index: 2;
91
+ max-width: calc(100% - 28px);
92
+ box-sizing: border-box;
93
+ clip-path: var(--dc-skill-tab-shape);
94
+ /* Token surface — future-tech-high specialties opt into LED-rim inset
95
+ highlight via --dc-card-tab-shadow. Default none (paper-poster register). */
96
+ box-shadow: var(--dc-card-tab-shadow);
97
+ }
98
+
99
+ /* ── Skill-card tab chrome as vector layers (dc#28) ───────────────────── */
100
+ /* Inside a skill card the tab's surface, accent border and clip move onto
101
+ ::before, and ::after adds the 2px ink outline the card-level drop-shadow
102
+ filter used to draw around the tab's silhouette. The element keeps its box
103
+ (the transparent 2px border preserves the metrics) but no longer clips:
104
+ an element with clip-path clips its own pseudos, which is the whole reason
105
+ the outline has to be a sibling layer and the clip has to move down one
106
+ level. Scoped to .dc-skill-card — `.dc-card-tab` is also the tab of the
107
+ `@section .dc-tabbed` silhouette, which never had the filter or the outline. */
108
+ .dc-skill-card > .dc-card-tab {
109
+ background: transparent;
110
+ border-color: transparent;
111
+ clip-path: none;
112
+ box-shadow: none;
113
+ }
114
+
115
+ /* Surface + accent border, clipped to the tab shape. Inset by the negative
116
+ border width so this box coincides with the tab's border box — an absolute
117
+ child is positioned against the padding box, which sits 2px inside it. */
118
+ .dc-skill-card > .dc-card-tab::before {
119
+ content: '';
120
+ position: absolute;
121
+ top: -2px;
122
+ right: -2px;
123
+ bottom: 0;
124
+ left: -2px;
125
+ background: var(--dc-card-tab-bg);
126
+ border: 2px solid var(--dc-card-accent);
127
+ border-bottom: 0;
128
+ box-sizing: border-box;
129
+ clip-path: var(--dc-skill-tab-shape);
130
+ box-shadow: var(--dc-card-tab-shadow);
131
+ z-index: -1;
132
+ }
133
+
134
+ /* 2px ink outline: the same shape on a box 2px larger on the top and both
135
+ sides, filled with ink, one layer further back. Not extended below — the
136
+ tab's bottom edge merges into the card body (margin-bottom: -2px), and the
137
+ filter never drew a line there either. */
138
+ .dc-skill-card > .dc-card-tab::after {
139
+ content: '';
140
+ position: absolute;
141
+ top: -4px;
142
+ right: -4px;
143
+ bottom: 0;
144
+ left: -4px;
145
+ background: var(--ink);
146
+ clip-path: var(--dc-skill-tab-shape);
147
+ z-index: -2;
148
+ }
149
+
150
+ .dc-tab-title {
151
+ font-family: var(--font-tab);
152
+ /* Bumped 13px → 15px per user feedback: "The tab headings on skill
153
+ cards are a little too small." Stays under 16pt to keep the tab
154
+ chrome compact. */
155
+ font-size: 15px;
156
+ /* Default to paper-cream so reverse-out text on the saturated tab fill
157
+ always passes WCAG. Specialty contexts re-affirm the same color via
158
+ their --dc-card-tab-title-color token. Without this fallback, the
159
+ title rendered as default body color (near-black) over a saturated
160
+ magenta fill — 2.95:1 contrast, fails WCAG at all sizes. */
161
+ color: var(--dc-card-tab-title-color);
162
+ text-transform: uppercase;
163
+ letter-spacing: 0.05em;
164
+ line-height: 1.2;
165
+ word-break: break-word;
166
+ }
167
+
168
+ .dc-tab-tier {
169
+ display: inline-flex;
170
+ align-items: center;
171
+ justify-content: center;
172
+ height: 1.25rem;
173
+ padding: 1px 5px;
174
+ border-radius: 100px;
175
+ font-family: var(--font-mono);
176
+ font-size: 9px;
177
+ font-weight: 700;
178
+ line-height: 1;
179
+ background-color: var(--tier-bronze);
180
+ color: var(--paper-cream);
181
+ letter-spacing: 0;
182
+ white-space: nowrap;
183
+ flex-shrink: 0;
184
+ }
185
+
186
+ /* Tier 2 (mid-level specialties): gold badges with dark text for WCAG AA contrast */
187
+ .dc-specialty.streetwarden .dc-tab-tier,
188
+ .dc-specialty.cybersurgeon .dc-tab-tier,
189
+ .dc-specialty.technosorcerer .dc-tab-tier {
190
+ background-color: var(--tier-gold);
191
+ color: var(--ink);
192
+ }
193
+
194
+ /* Tier 3 (advanced specialties): silver badges with dark text for WCAG AA contrast */
195
+ .dc-specialty.gutterdruid .dc-tab-tier,
196
+ .dc-specialty.etherlock .dc-tab-tier {
197
+ background-color: var(--tier-silver);
198
+ color: var(--ink);
199
+ }
200
+
201
+ /* ── Path block (structural section hook) ─────────────────────────────── */
202
+ .dc-path-block {
203
+ position: relative;
204
+ }
205
+
206
+ /* ── Card body + decorative mark ──────────────────────────────────────── */
207
+ .dc-card-body {
208
+ background: var(--dc-card-surface);
209
+ /* Tightened from 12px 14px 20px — saves ~10pt of vertical per card
210
+ so 2 cards fit per page more reliably. Bottom kept at 16px (down
211
+ from 20px) so the clip-path corner cut remains uncrowded by text. */
212
+ padding: 8px 12px 16px;
213
+ position: relative;
214
+ clip-path: var(--dc-skill-body-shape);
215
+ }
216
+
217
+ /* ── Skill-card body chrome as vector layers (dc#28) ──────────────────── */
218
+ /* Inside a skill card the body is a bare positioned box: its surface and clip
219
+ move down onto .dc-card-inner::after, its ::after carries the ink outline,
220
+ and its ::before keeps the decorative mark (below). The padding moves onto
221
+ .dc-card-inner with the surface, so the inner's box IS the body's box and
222
+ every layer aligns with `inset: 0` — no layer needs to know the padding.
223
+ Scoped to .dc-skill-card: the unscoped rule above also styles the @card
224
+ primitive's body. */
225
+ .dc-skill-card > .dc-card-body {
226
+ background: transparent;
227
+ clip-path: none;
228
+ padding: 0;
229
+ }
230
+
231
+ .dc-skill-card > .dc-card-body > .dc-card-inner {
232
+ padding: 8px 12px 16px;
233
+ /* Not a stacking context here (the unscoped rule below lifts it to 1): the
234
+ surface and shadow are this element's pseudos and must paint behind the
235
+ outline, which is the body's pseudo — that order only exists while all
236
+ three share the card's context. Nothing inside card content sits at a
237
+ negative z-index, so nothing else changes place. */
238
+ z-index: auto;
239
+ }
240
+
241
+ /* Hard poster shadow: the outlined silhouette (2px beyond the surface on
242
+ every side) shifted 2pt right and 3pt down, in the --shadow-poster colour.
243
+ Same offset and colour the filter's last stop used. */
244
+ .dc-skill-card > .dc-card-body > .dc-card-inner::before {
245
+ content: '';
246
+ position: absolute;
247
+ top: calc(3pt - 2px);
248
+ right: calc(-2pt - 2px);
249
+ bottom: calc(-3pt - 2px);
250
+ left: calc(2pt - 2px);
251
+ background: rgba(0, 0, 0, 0.28);
252
+ clip-path: var(--dc-skill-body-shape);
253
+ z-index: -4;
254
+ }
255
+
256
+ /* 2px ink outline: the surface shape on a box 2px larger on every side,
257
+ filled with ink, between the surface and the shadow. */
258
+ .dc-skill-card > .dc-card-body::after {
259
+ content: '';
260
+ position: absolute;
261
+ inset: -2px;
262
+ background: var(--ink);
263
+ clip-path: var(--dc-skill-body-shape);
264
+ z-index: -3;
265
+ }
266
+
267
+ /* Card surface: the body's former background + clip, on the same box. */
268
+ .dc-skill-card > .dc-card-body > .dc-card-inner::after {
269
+ content: '';
270
+ position: absolute;
271
+ inset: 0;
272
+ background: var(--dc-card-surface);
273
+ clip-path: var(--dc-skill-body-shape);
274
+ z-index: -2;
275
+ }
276
+
277
+ /* Two-column body variant for short skill cards. Applied via
278
+ `@skill {.dc-two-col}` in markdown. The .dc-card-inner content flows in
279
+ 2 columns so a 4in single-column skill becomes ~2in tall, doubling
280
+ horizontal packing density. Suitable for skills with shorter mechanics
281
+ text (no large tables, no outcomes ladder). */
282
+ .dc-skill-card.dc-two-col .dc-card-inner {
283
+ /* column-count/gap/fill owned by page-templates.css */
284
+ }
285
+
286
+ /* `.section.dc-rules-definition` (this file's columns block + the chrome/
287
+ tokens/doc block in components/*.css) and `.two-column-list` (both here
288
+ and its two tombstone bodies in components/*.css) were here and are
289
+ DELETED (2026-09-02): zero uses of either in any book's rendered HTML,
290
+ zero emissions from the Dimm City plugin. */
291
+
292
+ /* ── SKILL-CARD TWO-COLUMN BODY ────────────────────────────────────────────── */
293
+ /* Two-column body variant for short skill cards. Applied via
294
+ `@skill {.dc-two-col}` in markdown. The .dc-card-inner content flows in
295
+ 2 columns so a 4in single-column skill becomes ~2in tall, doubling
296
+ horizontal packing density. Column authority lives here; the card's
297
+ column-span and break rules stay in components/*.css. */
298
+ .dc-skill-card.dc-two-col .dc-card-inner {
299
+ column-count: 2;
300
+ column-gap: 12px;
301
+ column-fill: balance;
302
+ }
303
+
304
+ /* Inside 2-col body, force outcome tables and full-width elements to span
305
+ both columns so the visual chrome doesn't break across the gap. */
306
+ .dc-skill-card.dc-two-col .dc-card-inner .dc-outcome-table,
307
+ .dc-skill-card.dc-two-col .dc-card-inner table,
308
+ .dc-skill-card.dc-two-col .dc-card-inner h5 {
309
+ column-span: all;
310
+ }
311
+
312
+ /* AP/numbered list items must stay whole — splitting "Bullet to Blood"
313
+ across columns reads as sloppy. break-inside: avoid keeps each <li>
314
+ together in a single column even when the column boundary lands in
315
+ the middle of one. Paragraphs immediately following list items also
316
+ stay glued so their text doesn't strand from its anchor item. */
317
+ .dc-skill-card.dc-two-col .dc-card-inner ol > li,
318
+ .dc-skill-card.dc-two-col .dc-card-inner ul > li,
319
+ .dc-skill-card.dc-two-col .dc-card-inner p {
320
+ break-inside: avoid;
321
+ page-break-inside: avoid;
322
+ }
323
+
324
+ /* Horizontal skill placement — not currently attempted. `.dc-specialty
325
+ .skill-grid { columns: 2 }` and `display: grid` are both worth testing
326
+ before more work goes into the alternatives: the per-skill `.dc-two-col` body
327
+ variant (above), which shrinks each card vertically so 2 fit per page, or
328
+ cutting skill body text length at the markdown level. */
329
+
330
+ .dc-card-body::before {
331
+ content: '';
332
+ position: absolute;
333
+ top: 10px;
334
+ right: 16px;
335
+ width: 28px;
336
+ height: 2px;
337
+ background: var(--dc-card-body-mark);
338
+ opacity: 0.15;
339
+ transform: rotate(-3deg);
340
+ z-index: 2;
341
+ }
342
+
343
+ .dc-card-inner {
344
+ position: relative;
345
+ z-index: 1;
346
+ }
347
+
348
+ /* ── Highlight variant — featured skill card (| highlight suffix in title) */
349
+ /* On ::before because that is where the tab's clip lives now (dc#28); the
350
+ ring sits entirely outside the clipped box, as it did on the element. */
351
+ .dc-skill-card.dc-highlight .dc-card-tab::before {
352
+ box-shadow: 0 0 0 3px var(--crimson);
353
+ }
354
+
355
+ /* The crimson wash must sit OVER the light card substrate, not replace it.
356
+ The previous single-value `background: linear-gradient(... transparent ...)`
357
+ dropped the --dc-card-surface (--paper-cream) fill entirely, leaving the
358
+ lower 60% of the body transparent — dark ink text then rendered against the
359
+ bare (dark) page backdrop and read as illegible. Layering the gradient on
360
+ top of an explicit --dc-card-surface base keeps the body light end-to-end
361
+ while preserving the featured crimson accent at the top edge. Text color is
362
+ pinned to --ink for a guaranteed legible value. The surface is the
363
+ .dc-card-inner::after layer (dc#28), so the wash goes there. */
364
+ .dc-skill-card.dc-highlight .dc-highlight-body {
365
+ color: var(--ink);
366
+ }
367
+
368
+ .dc-skill-card.dc-highlight .dc-highlight-body > .dc-card-inner::after {
369
+ background:
370
+ linear-gradient(to bottom, rgba(180, 40, 40, 0.10) 0%, rgba(180, 40, 40, 0) 45%),
371
+ var(--dc-card-surface);
372
+ }
373
+
374
+ /* ── Continuation card variants ───────────────────────────────────────── */
375
+ .dc-skill-card-cont {
376
+ margin-top: 0;
377
+ }
378
+
379
+ .dc-card-tab-cont {
380
+ border-top-style: dashed;
381
+ border-top-color: var(--hud-blue);
382
+ }
383
+
384
+ /* Inside a skill card the tab's border paints on ::before (tab chrome rules
385
+ above), so the continuation dash goes there too. */
386
+ .dc-skill-card > .dc-card-tab-cont::before {
387
+ border-top-style: dashed;
388
+ border-top-color: var(--hud-blue);
389
+ }
390
+
391
+
392
+ /* ═══ ABILITY ROW + AP SYSTEM ═══ */
393
+
394
+ /* ── Ability row + ability text ───────────────────────────────────────── */
395
+ .dc-ability {
396
+ display: flex;
397
+ gap: 12px;
398
+ margin-bottom: 6px;
399
+ align-items: flex-start;
400
+ }
401
+
402
+ .dc-ability:last-child {
403
+ margin-bottom: 0;
404
+ }
405
+
406
+ .dc-ability-text {
407
+ font-family: var(--font-body);
408
+ font-size: var(--fs-body);
409
+ line-height: 1.5;
410
+ color: var(--ink);
411
+ }
412
+
413
+ .dc-ability-text strong {
414
+ /* --crimson on paper-cream = 4.03 (fails AA); --blood = 7.73:1 */
415
+ color: var(--blood);
416
+ font-weight: 600;
417
+ }
418
+
419
+ /* ROLL THE DIE! emphasis span — token: --dc-roll-the-die-color (default --blood)
420
+ --crimson default failed at 2.64:1 on the skill-card paper-aged substrate;
421
+ --blood is 5.07:1 there. Per-component overrides via the token are unchanged. */
422
+ .dc-roll-the-die {
423
+ font-family: var(--font-display);
424
+ font-size: 8pt;
425
+ font-weight: 700;
426
+ color: var(--dc-roll-the-die-color);
427
+ letter-spacing: 0.05em;
428
+ text-transform: uppercase;
429
+ display: inline-block;
430
+ vertical-align: middle;
431
+ background-color: var(--paper-aged);
432
+ padding: 0.5em;
433
+ box-shadow: var(--shadow-tint);
434
+ border: 2px dashed var(--dc-roll-the-die-border);
435
+ }
436
+
437
+ /* ── AP base + author-facing variants ─────────────────────────────────── */
438
+ /* Token defaults for .dc-ap (--dc-ap-bg/-fg/-border) are declared in :root
439
+ in dc-component-defaults.css — cream on --hud-blue = 4.45:1 borderline; on the
440
+ gradient mid-tone it measured 3.95 in real preview, so the default is
441
+ --hud-blue-dark at 7.45:1, safe. Author-facing variants below override
442
+ via .dc-ap.<variant> { }, same convention as every other component. */
443
+ .dc-ap {
444
+ font-family: var(--font-mono);
445
+ font-size: 10px;
446
+ font-weight: 600;
447
+ padding: 3px 6px;
448
+ min-width: 38px;
449
+ text-align: center;
450
+ /* Inner ink-density gradient + top-highlight — same pattern as
451
+ .dc-outcome-key. The chip reads as "stamped/printed" rather than a flat
452
+ CSS rectangle. */
453
+ background:
454
+ linear-gradient(180deg,
455
+ color-mix(in srgb, var(--dc-ap-bg) 90%, #fff 10%) 0%, /* PDF/X-1a: pre-composite to ~90% bg + 10% white; e.g. on --crimson (#e1261c) → #e64030; on Ingram submission replace with static opaque value in dc-tokens-print.css */
456
+ var(--dc-ap-bg) 50%,
457
+ color-mix(in srgb, var(--dc-ap-bg) 94%, #000 6%) 100%); /* PDF/X-1a: pre-composite to ~94% bg + 6% black; e.g. on --crimson (#e1261c) → #d42419; on Ingram submission replace with static opaque value in dc-tokens-print.css */
458
+ color: var(--dc-ap-fg);
459
+ /* 1pt ink-dark hairline gives registration grip — without it, adjacent
460
+ red-family AP chips (free/var/increased) merge under CMYK dot gain
461
+ at chip scale (38px wide, ~0.5in on press). */
462
+ border: 1px solid var(--dc-ap-border);
463
+ transform: rotate(-1deg);
464
+ /* Layered shadow — tight close shadow + soft far shadow. Single flat shadow
465
+ is the #2 amateur tell after flat fills. The layered version gives depth
466
+ that reads as "card lifted off page". */
467
+ box-shadow:
468
+ inset 0 1px 0 rgba(255, 255, 255, 0.15),
469
+ 2px 2px 0 rgba(0, 0, 0, 0.10),
470
+ 3px 3px 6px rgba(0, 0, 0, 0.08);
471
+ text-shadow: 0 1px 0 rgba(0, 0, 0, 0.20);
472
+ letter-spacing: 1px;
473
+ flex-shrink: 0;
474
+ align-self: flex-start;
475
+ margin-top: 1px;
476
+ }
477
+
478
+ .dc-ap.free {
479
+ /* cream on --crimson = 4.03:1 (fails AA). --blood = 7.73:1. */
480
+ --dc-ap-bg: var(--blood);
481
+ }
482
+
483
+ .dc-ap.var {
484
+ --dc-ap-bg: var(--hud-magenta);
485
+ }
486
+
487
+ }