gp-dimm-city 1.1.1 → 1.1.3

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,113 @@ cut a version that has no `## [X.Y.Z]` heading below.
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.1.3] - 2026-10-09
11
+
12
+ ### Removed
13
+
14
+ - Distance tags: the plugin no longer turns a `Distance` table inside a skill
15
+ into pills (`buildDistanceTags`); it now renders as a plain table. Also
16
+ removed `.dc-distance-tags`, `.dc-dist-tag`, `.dc-dist-ap`, `.dc-dist-name`
17
+ and the `--dc-dist-*` tokens. No book had such a table.
18
+ - Unused combinations: `.dc-flush` on `.dc-intro`, `.dc-sub-header` and
19
+ `.dc-steps`; `.dc-intro + .dc-alert`; `.dc-card-grid > h1/h2/.dc-intro`
20
+ (put headings and ledes outside the grid); `.section > h2.dc-h3:not(:first-child)`;
21
+ `.dc-toc ol > li > strong`.
22
+
23
+ ## [1.1.2] - 2026-10-08
24
+
25
+ **Notes for books upgrading from 1.1.1:**
26
+
27
+ - Build on gutterpress 0.11.15 or later and drop `@page .dc-printer-page`
28
+ and your own `print.signature`: the `dtrpg` preset now does both.
29
+ - Field Guide classes that moved into the package: `.fg-snug` becomes
30
+ `.dc-snug`, and the book-wide two-column skill cards become
31
+ `.dc-cards-two-col` on the specialty markers.
32
+ - Section panels, padding and splitting are tokens now. A book that
33
+ restyled `.section` chrome by overriding properties should set the
34
+ tokens instead (see the palette reference's Section table).
35
+
36
+ ### Added
37
+
38
+ - **`.dc-cards-two-col`**: on any ancestor (`@specialty`, `@chapter`,
39
+ `@page`, `@section`), every skill card inside gets a two-column body.
40
+ This is the Field Guide's book-wide form as an opt-in. A card's own
41
+ `.dc-two-col`, or `.dc-allow-split`, keeps its own form.
42
+ - **`.dc-snug`**: tighter paragraph and list-item spacing on a section or
43
+ page, for one that would otherwise overflow by a line or two (from the
44
+ Field Guide's `.fg-snug`).
45
+ - **Split skill cards keep their lead-ins with what follows.**
46
+ `.dc-specialty .dc-skill-card.dc-allow-split` keeps its tab, first
47
+ blocks and lead-in paragraphs with the next block (from the Field
48
+ Guide's own sheet).
49
+ - **Section tokens.** A section's panel, shadow and padding now come from
50
+ tokens (`--dc-section-surface`, `--dc-section-shadow`,
51
+ `--dc-section-pad-*`), as does whether a box may split
52
+ (`--dc-section-break-inside`, `--dc-alert-break-inside`). Variants and
53
+ page templates set tokens instead of cancelling properties.
54
+ - **`test/integrity.test.js`**, which checks that:
55
+ - every class the books use is styled;
56
+ - every token that is read, or that the palette reference documents,
57
+ is declared;
58
+ - each stylesheet keeps its stated contract.
59
+
60
+ ### Changed
61
+
62
+ - **Tested against gutterpress 0.11.15** (stable; was 0.11.15-alpha.1).
63
+ - **CSS quick wins from an architecture review.**
64
+ - New tokens: `--shadow-ink` (the opaque wall-shadow colour, written
65
+ out five times before) and four exact-value `--tint-*` mix sources
66
+ for the literal `rgb()` colours inside `color-mix()`.
67
+ - `--dc-section-tab-overlap` and `--dc-section-tab-indent` are now
68
+ public `:root` tokens.
69
+ - The TOC/credits masthead `h1` is now one rule instead of two.
70
+ - Dead declarations are gone: the `--shadow-poster` layer a specialty
71
+ card's own `clip-path` clipped away, `page-break-inside`, an empty
72
+ rule, a no-op height reset, three `opacity: 1`, and the
73
+ `break-before: always` Chromium ignores on learning paths.
74
+ - `dc-native.css` loses its tombstones and is renumbered §1–8.
75
+ - Pixel-identical in both books, except the even specialty cards,
76
+ whose left border is now `1.5pt` like the rest (was `1.5px`).
77
+
78
+ - **Section styling is opt-in per variant, not cancelled by a central list.**
79
+ - `.dc-plain`, `.dc-tabbed`, `.dc-column-panel` and `.dc-card-grid` set
80
+ the section tokens.
81
+ - The header bar's negative margins are derived from the padding.
82
+ - The shared page templates (intro, credits, chapter opener) own their
83
+ styling in `page-templates.css`; the chapter opener moves there from
84
+ `section.css`.
85
+ - Pixel-identical in both books.
86
+ - **The credits colophon shows its 4px front-matter rail again.** A rule in
87
+ `dc-native.css` had overridden it. This is the one visible change, on
88
+ each book's credits page.
89
+ - **Box splitting is decided in one place.**
90
+ - Multi-column runs and `.dc-allow-split` set the break-inside tokens.
91
+ - This replaces an avoid → auto → avoid override chain.
92
+
93
+ ### Removed
94
+
95
+ - **`.dc-printer-page` and its `@page printer-blank`** (deprecated in
96
+ 1.1.1). gutterpress 0.11.15's `dtrpg` preset pads the interior to the
97
+ 4-page signature and reserves the blank last page itself, so a book
98
+ needs neither the marker nor its own `print.signature`. The Field
99
+ Guide, built on 0.11.15 without either, keeps its 232 pages
100
+ pixel-identical and still ends on four blank pages.
101
+ - `--shadow-tint`, and `.dc-roll-the-die`'s `box-shadow: var(--shadow-tint)`:
102
+ a bare colour is not a valid shadow, so it never rendered.
103
+ - `.dc-suppress-footer` and its `@page clean` (and the design guide's
104
+ mirror of it): no book used footer suppression.
105
+ - The design guide's dual specialist and generalist skill-tree specimens
106
+ (Variant Gallery; The Specialty System's "One source" section, now
107
+ "eight shapes"). Those two specialties take their skills from the other
108
+ eight and have no trees of their own, so the specimens printed a
109
+ generic `PATH1` sticker for something that cannot exist.
110
+
111
+ ### Fixed
112
+
113
+ - The catalog's glossary entries: a glossary item is a plain paragraph
114
+ inside `@glossary`, and no doc or gallery page writes `.dc-terms-item`
115
+ any more, so `glossary-item-authored` is retired.
116
+
10
117
  ## [1.1.1] - 2026-10-08
11
118
 
12
119
  **Notes for books upgrading from 1.1.0:**
package/components.yaml CHANGED
@@ -234,11 +234,11 @@ components:
234
234
  - name: glossary
235
235
  status: live
236
236
  origin: plugin
237
- recipe: "@glossary … @end-glossary (the macro is used by neither book; the raw <div class=\"dc-terms\"> wrapper is)"
237
+ recipe: "@glossary … @end-glossary (items are plain `**term** — gloss` paragraphs)"
238
238
  emits: div.dc-terms
239
239
  css: styles/components/images.css
240
240
  breaks: "break-inside: avoid"
241
- notes: "CSS styles the children as .dc-terms .dc-item (see glossary-item); the docs and gallery author .dc-terms-item instead (see glossary-item-authored)."
241
+ notes: "Used by the design guide (06-panels-and-cards). Items take no class of their own; the old item classes are retired (glossary-item, glossary-item-authored)."
242
242
 
243
243
  - name: outcome
244
244
  status: live
@@ -397,21 +397,6 @@ components:
397
397
  breaks: none
398
398
  notes: "The plugin emits `variable`; the CSS styles both `.variable` and the raw spelling `.var`. `.standard/.reduced/.increased/.special` (specialty-identity.css) are never emitted, only authored raw — shown in the design guide's Variant Gallery."
399
399
 
400
- - name: distance-tags
401
- status: unused
402
- origin: plugin
403
- recipe: "| Distance | AP | table inside a skill card"
404
- emits: div.dc-sub-header + div.dc-distance-tags > span.dc-dist-tag > span.dc-dist-ap + span.dc-dist-name
405
- css: styles/components/data.css
406
- tokens: [--dc-dist-tag-surface, --dc-dist-tag-border, --dc-dist-ap-color, --dc-dist-name-color]
407
- usage: ["| Distance | AP |"]
408
- breaks: none
409
- notes: "Emission path exists and is styled; no skill in either book writes a
410
- Distance/AP table. The usage literal carries the AP column deliberately: the
411
- plugin only transforms a Distance table that sits inside a skill card, and
412
- field-guide chapter-05's Schraphose damage table is a four-column Distance
413
- table in body prose. A bare '| Distance |' literal counted that as a use."
414
-
415
400
  - name: roll-the-die
416
401
  status: live
417
402
  origin: plugin
@@ -602,8 +587,8 @@ components:
602
587
  origin: author
603
588
  recipe: "@skill {.dc-allow-split} or @section .dc-allow-split"
604
589
  emits: .dc-allow-split (on the skill card or section it is written on)
605
- css: styles/components/section.css
606
- breaks: "break-inside: auto — opts a section or skill card out of the default avoid"
590
+ css: [styles/components/section.css, styles/components/cards.css]
591
+ breaks: "break-inside: auto — opts a section or skill card out of the default avoid. A split specialty card also keeps its first two blocks, and any lead-in (ability row, bold-only line, paragraph before a list or table), with what follows (break-after: avoid)"
607
592
  notes: "The plugin reads this class (to drop data-break-inside=avoid) but never adds it."
608
593
 
609
594
  - name: two-col
@@ -614,6 +599,22 @@ components:
614
599
  css: styles/components/cards.css
615
600
  breaks: "list items and paragraphs break-inside: avoid within the columns"
616
601
 
602
+ - name: cards-two-col
603
+ status: live
604
+ origin: author
605
+ recipe: "@specialty .augmerc .dc-cards-two-col (or on @chapter / @page / @section)"
606
+ emits: .dc-cards-two-col (on the ancestor it is written on; styles the .dc-skill-card inside it)
607
+ css: styles/components/cards.css
608
+ breaks: "list items break-inside: avoid; a paragraph may break between columns. Flavor line, ability rows, tables, sub-heads and rules span both columns. A card with .dc-allow-split stays single-column; a card with its own .dc-two-col keeps the per-card form"
609
+
610
+ - name: snug
611
+ status: live
612
+ origin: author
613
+ recipe: "@section .dc-snug / @page .dc-snug"
614
+ emits: .dc-snug (on the section or page it is written on)
615
+ css: styles/page-templates.css
616
+ notes: "Paragraph and list-item margin-bottom drops to 0.04in so a section or page that overflows by a line or two fits. Type size and leading are untouched."
617
+
617
618
  - name: plain
618
619
  status: live
619
620
  origin: author
@@ -631,15 +632,6 @@ components:
631
632
  breaks: "break-before: page; page: full"
632
633
  notes: "Used by SysOps (chapter-00); the design guide documents it in a fenced example (08-page-templates)."
633
634
 
634
- - name: printer-page
635
- status: live
636
- origin: author
637
- recipe: "@page .dc-printer-page (the last marker of a book's last chapter)"
638
- emits: div.page.dc-printer-page
639
- css: [styles/page-rules.css, styles/dc-native.css]
640
- breaks: "page: printer-blank; break-before: page"
641
- notes: "DEPRECATED in 1.1.1: gutterpress 0.11.15+ reserves the blank last page itself (dtrpg preset, `print.reserveLastPage`). A completely blank final page — no wall, no footer — kept so books that still use it build unchanged. The Field Guide still ends with it (chapter-05) until it builds on a stable gutterpress 0.11.15; drop it then."
642
-
643
635
  - name: img-float
644
636
  status: live
645
637
  origin: author
@@ -655,9 +647,9 @@ components:
655
647
  recipe: "@section (bare; core markers.js emits the wrapper)"
656
648
  emits: div.section
657
649
  css: styles/components/section.css
658
- tokens: [--dc-section-bg, --dc-section-accent]
650
+ tokens: [--dc-section-bg, --dc-section-accent, --dc-section-surface, --dc-section-shadow, --dc-section-pad-top, --dc-section-pad-right, --dc-section-pad-bottom, --dc-section-pad-left]
659
651
  breaks: "break-inside: avoid (core MARKER_CSS)"
660
- notes: "The panel chrome is opt-out; .dc-plain is the escape."
652
+ notes: "Panel chrome is token-driven: variants and templates set --dc-section-surface/-shadow/-pad-* on their own rule; .dc-plain turns both layers off."
661
653
 
662
654
  - name: chapter-opener
663
655
  status: live
@@ -675,16 +667,28 @@ components:
675
667
  - --dc-chapter-opener-pad-right
676
668
  notes: "There is no @chapter-opener macro."
677
669
 
678
- # ── Author classes currently unused by the books ──────────────────────────────
670
+ # ── Retired: no CSS, no emission, no use (tombstone comments only) ─────
671
+ - name: distance-tags
672
+ status: retired
673
+ origin: plugin
674
+ recipe: "| Distance | AP | table inside a skill card"
675
+ emits: div.dc-sub-header + div.dc-distance-tags > span.dc-dist-tag > span.dc-dist-ap + span.dc-dist-name
676
+ notes: "Removed 2026-10-09 (plugin.js buildDistanceTags, data.css, --dc-dist-* tokens): no book had an AP-by-distance table. A Distance table inside a skill now renders as a plain table."
677
+
678
+ - name: printer-page
679
+ status: retired
680
+ origin: author
681
+ recipe: "@page .dc-printer-page (the last marker of a book's last chapter)"
682
+ emits: div.page.dc-printer-page
683
+ notes: "Removed in 1.1.2 with its @page printer-blank: gutterpress 0.11.15's dtrpg preset pads to the 4-page signature and reserves the blank last page itself (print.reserveLastPage)."
684
+
679
685
  - name: suppress-footer
680
- status: unused
686
+ status: retired
681
687
  origin: author
682
688
  recipe: "@page .dc-suppress-footer"
683
689
  emits: div.page.dc-suppress-footer
684
- css: styles/page-rules.css
685
- breaks: "page: clean"
690
+ notes: "Removed 2026-10-08 with its `@page clean` (page-rules.css, and the design guide's mirror): no book used it."
686
691
 
687
- # ── Retired: no CSS, no emission, no use (tombstone comments only) ─────
688
692
  - name: cover-page
689
693
  status: retired
690
694
  origin: author
@@ -813,6 +817,13 @@ components:
813
817
  emits: [.dc-gear-entry, div.section.dc-gear-list]
814
818
  notes: "Removed 2026-08-21 (data.css GEAR ENTRY tombstone); neither could ever match what @gear emits."
815
819
 
820
+ - name: glossary-item-authored
821
+ status: retired
822
+ origin: author
823
+ recipe: "raw <div class=\"dc-terms-item\"> inside .dc-terms"
824
+ emits: div.dc-terms-item
825
+ notes: "Never styled, and no doc or gallery page writes it any more (2026-10-08): a glossary item is a plain paragraph inside @glossary."
826
+
816
827
  # ── Unimplemented: documented or authored, never built ────────────────
817
828
  - name: skill-card-continuation-marker
818
829
  status: unimplemented
@@ -821,11 +832,4 @@ components:
821
832
  emits: [.dc-card-cont-marker, .dc-card-fwd-marker]
822
833
  notes: "Nothing ever emitted these; they needed a runtime script hook gutterpress does not have (cards.css comment, removed 2026-07-25). The docs describing them are stale."
823
834
 
824
- - name: glossary-item-authored
825
- status: unimplemented
826
- origin: author
827
- recipe: "raw <div class=\"dc-terms-item\"> inside .dc-terms (as the docs and gallery write it)"
828
- emits: div.dc-terms-item
829
- notes: "No CSS has ever styled .dc-terms-item — images.css styles .dc-terms .dc-item. The gallery specimen renders unstyled. Resolve by renaming one side; a separate decision."
830
-
831
835
  # Classes a book uses that are not components.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gp-dimm-city",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Dimm City design system for Gutterpress: the markdown-it macros (@skill, @specialty, @learning-path, @callout, …), print stylesheets, design tokens, fonts and page templates the Dimm City TTRPG books are set in.",
5
5
  "type": "module",
6
6
  "main": "plugin.js",
@@ -68,7 +68,7 @@
68
68
  "pack:check": "npm pack --dry-run"
69
69
  },
70
70
  "devDependencies": {
71
- "gutterpress": "0.11.15-alpha.1",
71
+ "gutterpress": "0.11.15",
72
72
  "markdown-it": "^14.1.0"
73
73
  },
74
74
  "peerDependencies": {
package/plugin.js CHANGED
@@ -363,9 +363,6 @@ function classifyTable(headers) {
363
363
  if (headers.includes('roll') && headers.includes('outcome')) {
364
364
  return 'outcomes';
365
365
  }
366
- if (headers.includes('distance')) {
367
- return 'distance';
368
- }
369
366
  return '';
370
367
  }
371
368
 
@@ -423,29 +420,6 @@ function buildOutcomesBlock(rows, md, needsAvoid = true) {
423
420
  return html;
424
421
  }
425
422
 
426
- function buildDistanceTags(rows, md) {
427
- let html = '<div class="dc-sub-header">AP Cost × Distance</div>\n';
428
- html += '<div class="dc-distance-tags">\n';
429
-
430
- rows.forEach(row => {
431
- if (row.length < 2) return;
432
- const distance = row[0].trim();
433
- const cost = row[1].trim();
434
-
435
- // Render markdown inline content
436
- const renderedDistance = md.renderInline(distance);
437
- const renderedCost = md.renderInline(cost);
438
-
439
- html += ' <span class="dc-dist-tag">\n';
440
- html += ' <span class="dc-dist-ap">' + renderedCost + '</span>\n';
441
- html += ' <span class="dc-dist-name">' + renderedDistance + '</span>\n';
442
- html += ' </span>\n';
443
- });
444
-
445
- html += '</div>\n';
446
- return html;
447
- }
448
-
449
423
  function buildTable(tableTokens, tableClass, md, needsAvoid = true) {
450
424
  const rows = [];
451
425
  let currentRow = [];
@@ -467,10 +441,7 @@ function buildTable(tableTokens, tableClass, md, needsAvoid = true) {
467
441
  }
468
442
  }
469
443
 
470
- if (tableClass === 'outcomes') {
471
- return buildOutcomesBlock(rows, md, needsAvoid);
472
- }
473
- return buildDistanceTags(rows, md);
444
+ return buildOutcomesBlock(rows, md, needsAvoid);
474
445
  }
475
446
 
476
447
  // Parse ability from list item - handles rendered HTML: "<strong>0 AP</strong> <em>Name:</em> Description"
@@ -2057,7 +2028,7 @@ export default function dimmCityPlugin(md, options = {}) {
2057
2028
  continue;
2058
2029
  }
2059
2030
 
2060
- // Table = Outcomes or Distance
2031
+ // Table = Outcomes
2061
2032
  if (tok.type === 'table_open' && inSkillCard) {
2062
2033
  const tableTokens = collectTableTokens(tokens, i);
2063
2034
  const headers = getTableHeaders(tableTokens);
@@ -100,7 +100,7 @@
100
100
  line-height: var(--lh-normal);
101
101
  padding: var(--space-lg) var(--space-xl);
102
102
  margin-top: var(--dc-alert-margin-top);
103
- break-inside: avoid;
103
+ break-inside: var(--dc-alert-break-inside);
104
104
  /* Alerts are full-width callouts that interrupt the reading flow; they
105
105
  should NEVER overlap a preceding right-floated image (observed 2026-05-25
106
106
  with the portrait in the citizen-file intro). Block elements don't wrap
@@ -7,8 +7,6 @@
7
7
  --dc-card-surface → card body background (default --paper-cream)
8
8
  --dc-card-tab-bg → tab background (default --ink-dark)
9
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
10
  --dc-card-body-mark → decorative ::before mark color (default --crimson)
13
11
  Specialty themes override these via .dc-specialty.<name> .dc-skill-card { }.
14
12
  Adding a new specialty: copy a sibling block (.dc-specialty.augmerc .dc-skill-card)
@@ -258,7 +256,7 @@
258
256
  right: calc(-2pt - 2px);
259
257
  bottom: calc(-3pt - 2px);
260
258
  left: calc(2pt - 2px);
261
- background: color-mix(in srgb, #000 28%, var(--wall-tone));
259
+ background: var(--shadow-ink);
262
260
  clip-path: var(--dc-skill-body-shape);
263
261
  z-index: -4;
264
262
  }
@@ -284,15 +282,6 @@
284
282
  z-index: -2;
285
283
  }
286
284
 
287
- /* Two-column body variant for short skill cards. Applied via
288
- `@skill {.dc-two-col}` in markdown. The .dc-card-inner content flows in
289
- 2 columns so a 4in single-column skill becomes ~2in tall, doubling
290
- horizontal packing density. Suitable for skills with shorter mechanics
291
- text (no large tables, no outcomes ladder). */
292
- .dc-skill-card.dc-two-col .dc-card-inner {
293
- /* column-count/gap/fill owned by page-templates.css */
294
- }
295
-
296
285
  /* `.section.dc-rules-definition` (this file's columns block + the chrome/
297
286
  tokens/doc block in components/*.css) and `.two-column-list` (both here
298
287
  and its two tombstone bodies in components/*.css) were here and are
@@ -325,7 +314,71 @@
325
314
  .dc-skill-card.dc-two-col .dc-card-inner ul > li,
326
315
  .dc-skill-card.dc-two-col .dc-card-inner p {
327
316
  break-inside: avoid;
328
- page-break-inside: avoid;
317
+ }
318
+
319
+ /* ── SKILL-CARD TWO-COLUMN FORM, BY ANCESTOR ───────────────────────────────── */
320
+ /* `.dc-cards-two-col` on ANY ancestor of skill cards (a `@specialty` marker,
321
+ a `@chapter`/`@page`, a `@section`) makes every skill card inside it
322
+ two-column: `@specialty .augmerc .dc-cards-two-col`. It is the book-wide
323
+ counterpart of the per-card `.dc-two-col` above, and the two differ on
324
+ purpose. Here only running text (paragraphs and lists) flows in the two
325
+ columns, a paragraph MAY break between them so the columns balance, and a
326
+ list item stays whole. Everything else spans the card: the flavor line,
327
+ ability rows (AP pill + text: in a column they ran taller than the whole
328
+ card and could not balance), tables, outcome ladders, alerts, sub-heads
329
+ and rules. Per-card `.dc-two-col` instead keeps every paragraph whole and
330
+ spans only tables.
331
+ A card with its own `.dc-two-col` keeps the per-card form entirely: every
332
+ rule below excludes it, so its own, stricter form wins over the inherited
333
+ one. A card marked `.dc-allow-split` stays single-column: a balanced
334
+ multicol that fragments across pages leaves the first fragment's right
335
+ column empty.
336
+ Column authority for both forms is this file (COLUMNS_ALLOWLIST in
337
+ test/integrity.test.js): this is component-internal layout of the card
338
+ body, not a page or section template. */
339
+ .dc-cards-two-col .dc-skill-card:not(.dc-two-col, .dc-allow-split) > .dc-card-body > .dc-card-inner {
340
+ column-count: 2;
341
+ column-gap: 16px;
342
+ }
343
+
344
+ /* The second selector: a text block left alone between two spanning pieces
345
+ (or at either end) cannot balance and would leave a column empty. */
346
+ .dc-cards-two-col .dc-skill-card:not(.dc-two-col, .dc-allow-split) .dc-card-inner > :not(ul, ol, p:not(.dc-flavor)),
347
+ .dc-cards-two-col .dc-skill-card:not(.dc-two-col, .dc-allow-split) .dc-card-inner > :is(:first-child, :not(ul, ol, p:not(.dc-flavor)) + *):is(:last-child, :has(+ :not(ul, ol, p))) {
348
+ column-span: all;
349
+ }
350
+
351
+ .dc-cards-two-col .dc-skill-card:not(.dc-two-col, .dc-allow-split) .dc-card-inner li {
352
+ break-inside: avoid;
353
+ }
354
+
355
+ /* An ability row under text that runs in the two columns sat flush on its
356
+ last line: the column row drops that text's bottom margin at the
357
+ spanning row. The row is moved down, not given a margin: a 0.08in margin
358
+ cost two pages in the Field Guide and split a card across a page turn, and
359
+ 0.04in cost one page (measured). */
360
+ .dc-cards-two-col .dc-skill-card:not(.dc-two-col, .dc-allow-split) .dc-card-inner > :is(p:not(.dc-flavor), ul, ol) + :is(p:not(.dc-flavor), ul, ol) + .dc-ability {
361
+ position: relative;
362
+ top: 0.06in;
363
+ }
364
+
365
+ /* A split card (`.dc-allow-split`) never opens with just its tab and a line
366
+ or two at a page foot: its first two blocks (the flavor line and a
367
+ possibly one-line ability) stay with the first two lines of what follows,
368
+ or the card moves to the next page. */
369
+ .dc-specialty .dc-skill-card.dc-allow-split .dc-card-inner > :nth-child(-n+2) {
370
+ break-after: avoid;
371
+ }
372
+
373
+ /* In a split card a lead-in stays with what it introduces: an ability row
374
+ with its first lines, a bold-only pseudo-heading with the paragraph under
375
+ it, a paragraph with the list or table it opens. CSS cannot see text
376
+ nodes, so `strong:only-child` also takes a paragraph whose only markup is
377
+ one bold run. A last child is left out: its break-after would pass up to
378
+ the card and glue the next path banner to it. */
379
+ .dc-specialty .dc-skill-card.dc-allow-split .dc-card-inner > :is(.dc-ability, p:has(> strong:only-child)):not(:last-child),
380
+ .dc-specialty .dc-skill-card.dc-allow-split .dc-card-inner > p:has(+ :is(ul, ol, table)) {
381
+ break-after: avoid;
329
382
  }
330
383
 
331
384
  /* Horizontal skill placement — not currently attempted. `.dc-specialty
@@ -373,7 +426,7 @@
373
426
 
374
427
  .dc-skill-card.dc-highlight .dc-highlight-body > .dc-card-inner::after {
375
428
  background:
376
- linear-gradient(to bottom, color-mix(in srgb, rgb(180 40 40) 10%, var(--dc-card-surface)) 0%, var(--dc-card-surface) 45%),
429
+ linear-gradient(to bottom, color-mix(in srgb, var(--tint-brick-red) 10%, var(--dc-card-surface)) 0%, var(--dc-card-surface) 45%),
377
430
  var(--dc-card-surface);
378
431
  }
379
432
 
@@ -436,7 +489,6 @@
436
489
  vertical-align: middle;
437
490
  background-color: var(--paper-aged);
438
491
  padding: 0.5em;
439
- box-shadow: var(--shadow-tint);
440
492
  border: 2px dashed var(--dc-roll-the-die-border);
441
493
  }
442
494
 
@@ -62,14 +62,6 @@
62
62
  cannot silently beat an `A + B` gap rule if there is no gap rule.
63
63
  Iter-8 (2026-05-25). */
64
64
 
65
- /* When a .dc-intro lede is followed by an alert/callout (the common
66
- "lede + supporting note" pattern from How Abilities Work), tighten the
67
- gap so they read as a connected pair. (@callout emits .dc-alert — the
68
- former .dc-callout adjacency rule was dead and was removed 2026-06-21.) */
69
- .dc-intro + .dc-alert {
70
- margin-top: 6pt;
71
- }
72
-
73
65
  /* Adjacent callouts/alerts (e.g. Cybersuck followed by SysFAIL after
74
66
  the Ego Points table) read as a CONNECTED PAIR rather than two
75
67
  independent floating boxes. Per user feedback: "design elements just
@@ -445,17 +437,10 @@ hr {
445
437
 
446
438
  /* ── Modifier variants — .dc-flush removes margin ─────────────────────────── */
447
439
  .dc-stickers.dc-flush,
448
- .dc-intro.dc-flush,
449
440
  .dc-tape.dc-flush {
450
441
  margin: 0;
451
442
  }
452
443
 
453
- .dc-sub-header.dc-flush {
454
- margin: 0;
455
- padding-top: 0;
456
- border-top: 0;
457
- }
458
-
459
444
  .dc-spec-tweak.dc-no-top {
460
445
  margin-top: 0;
461
446
  }
@@ -140,7 +140,6 @@
140
140
  bottom: 0;
141
141
  height: 3px;
142
142
  background: var(--hud-magenta);
143
- opacity: 1;
144
143
  width: auto;
145
144
  }
146
145
 
@@ -152,7 +151,7 @@
152
151
  padding-bottom: 6px;
153
152
  }
154
153
 
155
- /* ═══ OUTCOMES + STEPS + DISTANCE ═══ */
154
+ /* ═══ OUTCOMES + STEPS ═══ */
156
155
 
157
156
  /* ── Procedure / numbered steps ───────────────────────────────────────── */
158
157
  .dc-steps {
@@ -300,7 +299,6 @@
300
299
  font-weight: 700;
301
300
  letter-spacing: 0.03em;
302
301
  color: var(--dc-outcome-key-color);
303
- opacity: 1;
304
302
  display: block;
305
303
  line-height: 1;
306
304
  white-space: nowrap;
@@ -360,47 +358,6 @@
360
358
  --row-color: var(--fungi-rot);
361
359
  }
362
360
 
363
- /* ── Distance tags (AP cost × distance block) ─────────────────────────── */
364
- .dc-distance-tags {
365
- display: flex;
366
- flex-wrap: wrap;
367
- gap: 6px;
368
- margin: 10px 0;
369
- }
370
-
371
- /* Token contract for distance-tag pills:
372
- --dc-dist-tag-surface → cell bg (default --paper-light)
373
- --dc-dist-tag-border → cell border color (default --hud-blue-dim)
374
- --dc-dist-ap-color → AP-cost number color (default --ink)
375
- --dc-dist-name-color → distance-name caption color (default --hud-blue)
376
- */
377
- .dc-dist-tag {
378
- display: inline-flex;
379
- flex-direction: column;
380
- align-items: center;
381
- background: var(--dc-dist-tag-surface);
382
- border: 1px solid var(--dc-dist-tag-border);
383
- padding: 6px 10px;
384
- min-width: 52px;
385
- }
386
-
387
- .dc-dist-ap {
388
- font-family: var(--font-display);
389
- font-size: 14px;
390
- font-weight: 700;
391
- color: var(--dc-dist-ap-color);
392
- line-height: 1;
393
- }
394
-
395
- .dc-dist-name {
396
- font-family: var(--font-mono);
397
- font-size: 8px;
398
- letter-spacing: 0.12em;
399
- text-transform: uppercase;
400
- color: var(--dc-dist-name-color);
401
- margin-top: 3px;
402
- }
403
-
404
361
  /* ───────── PULL-QUOTE ───────── */
405
362
  .dc-pullquote {
406
363
  background: var(--dc-pullquote-bg);
@@ -726,10 +683,6 @@
726
683
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 4px), calc(100% - 6px) 100%, 0 100%);
727
684
  }
728
685
 
729
- .dc-toc ol>li>strong {
730
- color: var(--hud-blue-dark);
731
- }
732
-
733
686
  .dc-toc ol>li>a {
734
687
  font-size: 15pt;
735
688
  font-weight: 700;
@@ -753,7 +706,6 @@
753
706
  }
754
707
 
755
708
  .dc-stat.dc-flush,
756
- .dc-steps.dc-flush,
757
709
  .dc-outcomes.dc-flush,
758
710
  .dc-pullquote.dc-flush {
759
711
  margin: 0;
@@ -781,13 +733,6 @@
781
733
  max-width: 7.25in;
782
734
  }
783
735
 
784
- /* Universal card layout fixes — apply to any book using dc-skill-card. */
785
-
786
- :is(.dc-skill-card, .dc-skill-card .dc-card-body) {
787
- height: auto;
788
- min-height: 0;
789
- }
790
-
791
736
  /* `.two-column-list` (this tombstone + the base one below + both real
792
737
  rules in page-templates.css) is DELETED (2026-09-02) — 0 uses, 0
793
738
  emissions; see page-templates.css's note at its old location. */