gutterpress 0.11.16-alpha.6 → 0.11.16

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/dist/api/index.js CHANGED
@@ -131,7 +131,7 @@ import {
131
131
  testRemoteAccess,
132
132
  updateExtensions,
133
133
  validateProjectExtensions
134
- } from "../index-ss8dv3zf.js";
134
+ } from "../index-40achhs8.js";
135
135
  import {
136
136
  BuildError
137
137
  } from "../index-ee7wp8q3.js";
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  runBuild,
3
3
  splitOutPath
4
- } from "./cli-ac7zs8sp.js";
4
+ } from "./cli-ev175hx9.js";
5
5
  import {
6
6
  log
7
- } from "./cli-n9e1mzb7.js";
7
+ } from "./cli-0prrt9e4.js";
8
8
  import {
9
9
  UsageError,
10
10
  parseFormat,
11
11
  parsePdfxFlavor,
12
12
  rejectExtraPositionals,
13
13
  rejectUnknownFlags
14
- } from "./cli-nzzsyw1e.js";
14
+ } from "./cli-182j48xc.js";
15
15
  import"./cli-wqy8hnnh.js";
16
16
  import {
17
17
  BuildError
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  package_default
3
- } from "./cli-nzzsyw1e.js";
3
+ } from "./cli-182j48xc.js";
4
4
  import {
5
5
  execCapture,
6
6
  findTool,
@@ -4,7 +4,7 @@ import {
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "gutterpress",
7
- version: "0.11.16-alpha.6",
7
+ version: "0.11.16",
8
8
  description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
9
9
  author: "itlackey",
10
10
  license: "MPL-2.0",
@@ -13,12 +13,12 @@ import {
13
13
  stampCreator,
14
14
  stripAnnotations,
15
15
  warn
16
- } from "./cli-n9e1mzb7.js";
16
+ } from "./cli-0prrt9e4.js";
17
17
  import {
18
18
  DEBOUNCE,
19
19
  UsageError,
20
20
  resolvePort
21
- } from "./cli-nzzsyw1e.js";
21
+ } from "./cli-182j48xc.js";
22
22
  import {
23
23
  MARGIN_BOX_IGNORED_PROPERTIES,
24
24
  getAssetPath,
@@ -1181,16 +1181,23 @@ function resolveMarkerDeclaration(name, rawDecl, rawRegistry, originOf) {
1181
1181
  }
1182
1182
  return { name, baseKind: name, ...resolveContainerShape(name, pluginName, rawDecl) };
1183
1183
  }
1184
+ var CORE_MARKER_OWNER = "Gutterpress";
1185
+ var CORE_DECLARED_MARKERS = {
1186
+ columns: {
1187
+ class: "gp-columns",
1188
+ variants: { 1: "gp-columns-1", 2: "gp-columns-2", 3: "gp-columns-3", 4: "gp-columns-4", 5: "gp-columns-5" }
1189
+ }
1190
+ };
1184
1191
  function buildDeclaredMarkerRegistry(sources) {
1185
1192
  const rawRegistry = new Map;
1186
1193
  const originOf = new Map;
1187
- for (const { pluginName, markers } of sources) {
1194
+ for (const { pluginName, markers } of [{ pluginName: CORE_MARKER_OWNER, markers: CORE_DECLARED_MARKERS }, ...sources]) {
1188
1195
  if (!markers)
1189
1196
  continue;
1190
1197
  for (const [name, rawDecl] of Object.entries(markers)) {
1191
1198
  validateDeclaredMarkerName(name, pluginName);
1192
- if (KNOWN_KINDS.includes(name)) {
1193
- throw new Error(`Plugin "${pluginName}" declares marker "@${name}", which is a core Gutterpress marker name ` + `(${KNOWN_KINDS.map((k) => `@${k}`).join(", ")}). Core marker names cannot be shadowed — ` + `rename the plugin's marker.`);
1199
+ if (KNOWN_KINDS.includes(name) || pluginName !== CORE_MARKER_OWNER && name in CORE_DECLARED_MARKERS) {
1200
+ throw new Error(`Plugin "${pluginName}" declares marker "@${name}", which is a core Gutterpress marker name ` + `(${[...KNOWN_KINDS, ...Object.keys(CORE_DECLARED_MARKERS)].map((k) => `@${k}`).join(", ")}). ` + `Core marker names cannot be shadowed — ` + `rename the plugin's marker.`);
1194
1201
  }
1195
1202
  if (rawRegistry.has(name)) {
1196
1203
  throw new Error(`Marker "@${name}" is declared by both plugin "${originOf.get(name)}" and plugin "${pluginName}". ` + `Declared marker names must be unique across every loaded plugin — rename one of them.`);
@@ -1273,7 +1280,7 @@ function plugin(md, pluginOptions = {}) {
1273
1280
  preferPagesInSpreads: false,
1274
1281
  ...pluginOptions
1275
1282
  };
1276
- const declaredMarkers = options.declaredMarkers instanceof Map && options.declaredMarkers.size > 0 ? options.declaredMarkers : null;
1283
+ const declaredMarkers = options.declaredMarkers instanceof Map && options.declaredMarkers.size > 0 ? options.declaredMarkers : buildDeclaredMarkerRegistry([]);
1277
1284
  const declaredWords = declaredKindWords(declaredMarkers);
1278
1285
  function markerBlock(state, startLine, endLine, silent) {
1279
1286
  const pos = state.bMarks[startLine] + state.tShift[startLine];
@@ -1832,9 +1839,19 @@ var GUTTERPRESS_CSS = `
1832
1839
  NOT set, because the correct value depends on whether the run fragments
1833
1840
  across pages (auto packs each page's columns; the CSS initial balance is
1834
1841
  right for a run that fits on one page) and only the author knows which.
1835
- --gp-column-gap is author-settable. */
1836
- .gp-columns-2 { columns: 2; column-gap: var(--gp-column-gap, 1.5em); }
1837
- .gp-columns-3 { columns: 3; column-gap: var(--gp-column-gap, 1.5em); }
1842
+ --gp-column-gap is author-settable.
1843
+ .gp-columns is what the core @columns marker emits (markers.js); on its
1844
+ own it is two columns, and @columns 1 to 5 add the matching count, which
1845
+ wins because it comes later at the same specificity. */
1846
+ .gp-columns, .gp-columns-1, .gp-columns-2, .gp-columns-3, .gp-columns-4, .gp-columns-5 {
1847
+ column-gap: var(--gp-column-gap, 1.5em);
1848
+ }
1849
+ .gp-columns { columns: 2; }
1850
+ .gp-columns-1 { columns: 1; }
1851
+ .gp-columns-2 { columns: 2; }
1852
+ .gp-columns-3 { columns: 3; }
1853
+ .gp-columns-4 { columns: 4; }
1854
+ .gp-columns-5 { columns: 5; }
1838
1855
 
1839
1856
  /* the per-shape decisions the paragraph above deliberately leaves to the
1840
1857
  author, named instead of left as raw CSS every book was reinventing
@@ -2035,8 +2052,12 @@ var GP_CLASSES = new Set([
2035
2052
  "gp-large",
2036
2053
  "gp-tight",
2037
2054
  "gp-loose",
2055
+ "gp-columns",
2056
+ "gp-columns-1",
2038
2057
  "gp-columns-2",
2039
2058
  "gp-columns-3",
2059
+ "gp-columns-4",
2060
+ "gp-columns-5",
2040
2061
  "gp-columns-all",
2041
2062
  "gp-columns-flow",
2042
2063
  "gp-columns-balanced",
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  UsageError,
7
7
  package_default,
8
8
  rejectUnknownFlags
9
- } from "./cli-nzzsyw1e.js";
9
+ } from "./cli-182j48xc.js";
10
10
  import {
11
11
  EXIT_CODES
12
12
  } from "./cli-46ycxe6r.js";
@@ -18,14 +18,14 @@ import {
18
18
  import { defineCommand, parseArgs, runMain } from "citty";
19
19
  import { statSync } from "node:fs";
20
20
  var SUBCOMMANDS = {
21
- new: () => import("./new-rxkqh5t2.js").then((m) => m.default),
22
- preview: () => import("./preview-55jbgv9p.js").then((m) => m.default),
23
- build: () => import("./build-bk0rw638.js").then((m) => m.default),
24
- publish: () => import("./publish-mv3kcwwn.js").then((m) => m.default),
25
- validate: () => import("./validate-bhn2tjsw.js").then((m) => m.default),
26
- preflight: () => import("./preflight-wm3seg5z.js").then((m) => m.default),
27
- doctor: () => import("./doctor-qmd7gjwt.js").then((m) => m.default),
28
- ext: () => import("./ext-j28pn3ng.js").then((m) => m.default)
21
+ new: () => import("./new-wsjsrm7w.js").then((m) => m.default),
22
+ preview: () => import("./preview-azy06gw0.js").then((m) => m.default),
23
+ build: () => import("./build-8epzrj8g.js").then((m) => m.default),
24
+ publish: () => import("./publish-8db67m2h.js").then((m) => m.default),
25
+ validate: () => import("./validate-e7mw1xyd.js").then((m) => m.default),
26
+ preflight: () => import("./preflight-0fjjnk9e.js").then((m) => m.default),
27
+ doctor: () => import("./doctor-24mbx7y1.js").then((m) => m.default),
28
+ ext: () => import("./ext-p9gx5aac.js").then((m) => m.default)
29
29
  };
30
30
  var VERSION = package_default.version;
31
31
  var main = defineCommand({
@@ -50,7 +50,7 @@ async function preflightRequiredInvocations(rawArgs) {
50
50
  const [command, ...commandArgs] = rawArgs;
51
51
  try {
52
52
  if (command === "new") {
53
- const { newArgs } = await import("./new-rxkqh5t2.js");
53
+ const { newArgs } = await import("./new-wsjsrm7w.js");
54
54
  rejectUnknownFlags(commandArgs, newArgs, "new");
55
55
  const parsed = parseArgs(commandArgs, {
56
56
  ...newArgs,
@@ -62,7 +62,7 @@ async function preflightRequiredInvocations(rawArgs) {
62
62
  return;
63
63
  }
64
64
  if (command === "preflight") {
65
- const { preflightArgs } = await import("./preflight-wm3seg5z.js");
65
+ const { preflightArgs } = await import("./preflight-0fjjnk9e.js");
66
66
  rejectUnknownFlags(commandArgs, preflightArgs, "preflight");
67
67
  const parsed = parseArgs(commandArgs, {
68
68
  ...preflightArgs,
@@ -82,7 +82,7 @@ async function preflightRequiredInvocations(rawArgs) {
82
82
  }
83
83
  if (subcommand.startsWith("-"))
84
84
  return;
85
- const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-j28pn3ng.js");
85
+ const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-p9gx5aac.js");
86
86
  if (!EXT_SUBCOMMANDS.includes(subcommand)) {
87
87
  throw new UsageError(`gutterpress ext: unknown command "${subcommand}"`);
88
88
  }
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  getSystemDiagnostics,
3
3
  log
4
- } from "./cli-n9e1mzb7.js";
4
+ } from "./cli-0prrt9e4.js";
5
5
  import {
6
6
  UsageError,
7
7
  rejectExtraPositionals,
8
8
  rejectUnknownFlags
9
- } from "./cli-nzzsyw1e.js";
9
+ } from "./cli-182j48xc.js";
10
10
  import"./cli-46ycxe6r.js";
11
11
  import"./cli-7fkhgtfn.js";
12
12
  import"./cli-37x76zdn.js";
@@ -12,15 +12,15 @@ import {
12
12
  searchNpmExtensions,
13
13
  setExtensionEnabled,
14
14
  updateExtensions
15
- } from "./cli-ac7zs8sp.js";
16
- import"./cli-n9e1mzb7.js";
15
+ } from "./cli-ev175hx9.js";
16
+ import"./cli-0prrt9e4.js";
17
17
  import {
18
18
  UsageError,
19
19
  exitForUsage,
20
20
  rejectExtraPositionals,
21
21
  rejectUnknownFlags,
22
22
  resolveProjectDir
23
- } from "./cli-nzzsyw1e.js";
23
+ } from "./cli-182j48xc.js";
24
24
  import"./cli-wqy8hnnh.js";
25
25
  import {
26
26
  EXIT_CODES
@@ -1140,16 +1140,23 @@ function resolveMarkerDeclaration(name, rawDecl, rawRegistry, originOf) {
1140
1140
  }
1141
1141
  return { name, baseKind: name, ...resolveContainerShape(name, pluginName, rawDecl) };
1142
1142
  }
1143
+ var CORE_MARKER_OWNER = "Gutterpress";
1144
+ var CORE_DECLARED_MARKERS = {
1145
+ columns: {
1146
+ class: "gp-columns",
1147
+ variants: { 1: "gp-columns-1", 2: "gp-columns-2", 3: "gp-columns-3", 4: "gp-columns-4", 5: "gp-columns-5" }
1148
+ }
1149
+ };
1143
1150
  function buildDeclaredMarkerRegistry(sources) {
1144
1151
  const rawRegistry = new Map;
1145
1152
  const originOf = new Map;
1146
- for (const { pluginName, markers } of sources) {
1153
+ for (const { pluginName, markers } of [{ pluginName: CORE_MARKER_OWNER, markers: CORE_DECLARED_MARKERS }, ...sources]) {
1147
1154
  if (!markers)
1148
1155
  continue;
1149
1156
  for (const [name, rawDecl] of Object.entries(markers)) {
1150
1157
  validateDeclaredMarkerName(name, pluginName);
1151
- if (KNOWN_KINDS.includes(name)) {
1152
- throw new Error(`Plugin "${pluginName}" declares marker "@${name}", which is a core Gutterpress marker name ` + `(${KNOWN_KINDS.map((k) => `@${k}`).join(", ")}). Core marker names cannot be shadowed — ` + `rename the plugin's marker.`);
1158
+ if (KNOWN_KINDS.includes(name) || pluginName !== CORE_MARKER_OWNER && name in CORE_DECLARED_MARKERS) {
1159
+ throw new Error(`Plugin "${pluginName}" declares marker "@${name}", which is a core Gutterpress marker name ` + `(${[...KNOWN_KINDS, ...Object.keys(CORE_DECLARED_MARKERS)].map((k) => `@${k}`).join(", ")}). ` + `Core marker names cannot be shadowed — ` + `rename the plugin's marker.`);
1153
1160
  }
1154
1161
  if (rawRegistry.has(name)) {
1155
1162
  throw new Error(`Marker "@${name}" is declared by both plugin "${originOf.get(name)}" and plugin "${pluginName}". ` + `Declared marker names must be unique across every loaded plugin — rename one of them.`);
@@ -1232,7 +1239,7 @@ function plugin(md, pluginOptions = {}) {
1232
1239
  preferPagesInSpreads: false,
1233
1240
  ...pluginOptions
1234
1241
  };
1235
- const declaredMarkers = options.declaredMarkers instanceof Map && options.declaredMarkers.size > 0 ? options.declaredMarkers : null;
1242
+ const declaredMarkers = options.declaredMarkers instanceof Map && options.declaredMarkers.size > 0 ? options.declaredMarkers : buildDeclaredMarkerRegistry([]);
1236
1243
  const declaredWords = declaredKindWords(declaredMarkers);
1237
1244
  function markerBlock(state, startLine, endLine, silent) {
1238
1245
  const pos = state.bMarks[startLine] + state.tShift[startLine];
@@ -1791,9 +1798,19 @@ var GUTTERPRESS_CSS = `
1791
1798
  NOT set, because the correct value depends on whether the run fragments
1792
1799
  across pages (auto packs each page's columns; the CSS initial balance is
1793
1800
  right for a run that fits on one page) and only the author knows which.
1794
- --gp-column-gap is author-settable. */
1795
- .gp-columns-2 { columns: 2; column-gap: var(--gp-column-gap, 1.5em); }
1796
- .gp-columns-3 { columns: 3; column-gap: var(--gp-column-gap, 1.5em); }
1801
+ --gp-column-gap is author-settable.
1802
+ .gp-columns is what the core @columns marker emits (markers.js); on its
1803
+ own it is two columns, and @columns 1 to 5 add the matching count, which
1804
+ wins because it comes later at the same specificity. */
1805
+ .gp-columns, .gp-columns-1, .gp-columns-2, .gp-columns-3, .gp-columns-4, .gp-columns-5 {
1806
+ column-gap: var(--gp-column-gap, 1.5em);
1807
+ }
1808
+ .gp-columns { columns: 2; }
1809
+ .gp-columns-1 { columns: 1; }
1810
+ .gp-columns-2 { columns: 2; }
1811
+ .gp-columns-3 { columns: 3; }
1812
+ .gp-columns-4 { columns: 4; }
1813
+ .gp-columns-5 { columns: 5; }
1797
1814
 
1798
1815
  /* the per-shape decisions the paragraph above deliberately leaves to the
1799
1816
  author, named instead of left as raw CSS every book was reinventing
@@ -1994,8 +2011,12 @@ var GP_CLASSES = new Set([
1994
2011
  "gp-large",
1995
2012
  "gp-tight",
1996
2013
  "gp-loose",
2014
+ "gp-columns",
2015
+ "gp-columns-1",
1997
2016
  "gp-columns-2",
1998
2017
  "gp-columns-3",
2018
+ "gp-columns-4",
2019
+ "gp-columns-5",
1999
2020
  "gp-columns-all",
2000
2021
  "gp-columns-flow",
2001
2022
  "gp-columns-balanced",
@@ -5617,7 +5638,7 @@ import git from "isomorphic-git";
5617
5638
  // package.json
5618
5639
  var package_default = {
5619
5640
  name: "gutterpress",
5620
- version: "0.11.16-alpha.6",
5641
+ version: "0.11.16",
5621
5642
  description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
5622
5643
  author: "itlackey",
5623
5644
  license: "MPL-2.0",
package/dist/index.js CHANGED
@@ -148,7 +148,7 @@ import {
148
148
  testRemoteAccess,
149
149
  updateExtensions,
150
150
  validateProjectExtensions
151
- } from "./index-ss8dv3zf.js";
151
+ } from "./index-40achhs8.js";
152
152
  import {
153
153
  BUILD_DIAGNOSTIC_CODES
154
154
  } from "./index-qep93v0z.js";
@@ -133,7 +133,7 @@
133
133
  * carrying gp-left could start shifting; that is standards-tracking per
134
134
  * CLAUDE.md ("Chrome wins once it ships"), not a bug in the author's book.
135
135
  */
136
- export declare const GUTTERPRESS_CSS = "\n/* gp-* author image/block vocabulary. One vocabulary, gp-* only \u2014 the\n pre-vocabulary utility names (.center/.float-left/.float-right/\n .full-width/.full-bleed) were REMOVED when gp-* shipped; books rename\n the classes in their markdown (see the migration note). Source ORDER is\n the contract \u2014 see the doctrine comment above. */\n\n/* flow positions */\n.gp-left {\n float: left;\n margin: 0 var(--gp-gap, 1em) var(--gp-gap, 1em) 0;\n max-width: 50%;\n}\n.gp-right {\n float: right;\n margin: 0 0 var(--gp-gap, 1em) var(--gp-gap, 1em);\n max-width: 50%;\n}\n.gp-center {\n display: block;\n float: none;\n margin-left: auto;\n margin-right: auto;\n max-width: 100%;\n}\n.gp-full {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n@page gp-full-bleed { margin-left: 0; margin-right: 0; }\n.gp-bleed {\n display: block;\n float: none;\n break-before: page;\n page: gp-full-bleed;\n max-width: none;\n width: 100%;\n margin-left: 0;\n margin-right: 0;\n}\n\n/* sizes \u2014 AFTER the flow positions so max-width:100% lifts the floats' 50%\n cap at equal specificity */\n.gp-small { width: 25%; max-width: 100%; }\n.gp-medium { width: 50%; max-width: 100%; }\n.gp-large { width: 75%; max-width: 100%; }\n\n/* float clearance presets \u2014 consumed by var(--gp-gap) in the float rules\n above and by .gp-shape's shape-margin below; --gp-gap itself is\n author-settable CSS */\n.gp-tight { --gp-gap: 0.5em; }\n.gp-loose { --gp-gap: 2em; }\n\n/* column runs \u2014 plain CSS Multi-column, exposed as author vocabulary so\n \"put this in two columns\" does not require borrowing a styled container\n from the book's own component layer. That borrowing is what this exists\n to prevent: a book whose theme paints .section chrome by default gives\n every author who opens a section just to start a column run a panel they\n did not ask for, and the book then needs a reset rule to take it back.\n With a neutral primitive the author opts into columns and nothing else.\n\n Permanent vocabulary, not a shim: Chromium implements multicol natively\n and these rules are the standard properties verbatim, so there is no\n spec gap here to remove later. Deliberately minimal \u2014 column-fill is\n NOT set, because the correct value depends on whether the run fragments\n across pages (auto packs each page's columns; the CSS initial balance is\n right for a run that fits on one page) and only the author knows which.\n --gp-column-gap is author-settable. */\n.gp-columns-2 { columns: 2; column-gap: var(--gp-column-gap, 1.5em); }\n.gp-columns-3 { columns: 3; column-gap: var(--gp-column-gap, 1.5em); }\n\n/* the per-shape decisions the paragraph above deliberately leaves to the\n author, named instead of left as raw CSS every book was reinventing\n (CLAUDE.md \u00A70: \"behavior broadly useful to non-technical authors belongs\n in core\").\n Permanent vocabulary, standard properties verbatim \u2014 same rationale as\n the column/grid runs above. One name each, no aliases:\n .gp-columns-all column-span: all a heading or block that\n spans every column in the\n run it sits inside.\n .gp-columns-flow column-fill: auto a run that FRAGMENTS across\n pages \u2014 every page's\n columns fill instead of\n only the last one\n balancing (the dead-column\n collapse the build's\n engine.multicol.dead-column\n warning names this fix\n for).\n .gp-columns-balanced column-fill: balance a run that fits on ONE\n page (the CSS initial\n value \u2014 ragged columns\n would be wrong here). */\n.gp-columns-all { column-span: all; }\n.gp-columns-flow { column-fill: auto; }\n.gp-columns-balanced { column-fill: balance; }\n\n/* grid runs \u2014 the SLOTTED counterpart to the column runs above. Grid places\n each child into the next cell, across then down (deterministic slots: card\n layouts, stat blocks, image-plus-caption pairs); columns FLOW one text run\n down then across. Same neutral-primitive rationale as .gp-columns-*, and\n permanent vocabulary for the same reason: standard CSS Grid verbatim, no\n spec gap to remove later. MEASURED (Chromium 151, gp-grid evidence pack):\n grid rows fragment across sheets with EXACT print/viewer parity \u2014 2- and\n 3-col, unequal item heights, mid-row cuts, multi-sheet overflow,\n break-inside:avoid, gap geometry \u2014 so a grid taller than the page is safe,\n no fit-one-page constraint. Two things to know, not fix:\n - on a min-height page root (MARKER_CSS), default align-content\n stretches rows apart to fill the page \u2014 identically in both engines.\n Authors wanting packed rows set align-content: start.\n - a @page-break / @column-break marker DIRECTLY inside a grid container\n becomes a grid item and corrupts placement (the one measured parity\n break); markers.js diagnoses it (break_inside_grid).\n --gp-grid-gap is author-settable. */\n.gp-grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gp-grid-gap, 1.5em); }\n.gp-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gp-grid-gap, 1.5em); }\n\n/* fragmentation controls \u2014 generic pagination utilities for any element,\n independent of the column/grid vocabulary above (a book reached for\n these just as often outside a multicol run: keeping a card whole,\n forcing a section to start a fresh page). Standard properties only \u2014\n this project is Chromium-only (CLAUDE.md), so there are no legacy\n page-break-* twins to also emit. One name each. */\n.gp-no-break { break-inside: avoid; }\n.gp-break-before { break-before: page; }\n\n/* shape wrap \u2014 text follows the image's alpha silhouette instead of its\n rectangular box. shape-outside only applies to floats, so this is inert\n without .gp-left/.gp-right (and under .gp-pin, which un-floats). The\n shape URL cannot be written in CSS (url() contexts can't read attr()),\n so the image renderer rule (images.ts) mirrors the src into an inline\n --gp-shape:url(...) custom property whenever it sees this class --\n authors only ever type the class. threshold 0.2 ignores near-transparent\n anti-aliasing halos; shape-margin shares the float-gap vocabulary. */\nimg.gp-shape {\n shape-outside: var(--gp-shape);\n shape-image-threshold: 0.2;\n shape-margin: var(--gp-gap, 1em);\n}\n\n/* pin \u2014 within the nearest positioned ancestor (.page/.spread, rule above).\n inset:0 and the explicit centers are load-bearing; see doctrine comment. */\n.gp-pin {\n position: absolute;\n inset: 0;\n align-self: center;\n justify-self: center;\n margin: 0;\n max-width: 100%;\n}\n\n/* pin edge modifiers \u2014 AFTER .gp-pin to beat its center defaults;\n justify-self is inert on in-flow floats, so gp-left/gp-right safely do\n double duty as flow float + pin edge */\n.gp-top { align-self: start; }\n.gp-bottom { align-self: end; }\n.gp-left { justify-self: start; }\n.gp-right { justify-self: end; }\n\n/* wrapper-margin neutralization (same pattern and rationale as the\n .gp-bleed paragraph-margin note in the doctrine comment; for pin, the\n emptied paragraph would otherwise leave a phantom margin gap in flow) */\n:where(p:has(> img.gp-bleed:only-child)) { margin: 0; }\n:where(p:has(> img.gp-pin:only-child)) { margin: 0; }\n\n/* depth \u2014 a named ladder for z-index, so books stop hand-tuning bare\n integers. A real book measured 21 z-index declarations using only four\n distinct values (-1, 0, 1, 2), each written literally at its use site.\n The custom properties are the author-settable surface (a book needing a\n deeper stack raises them once); the classes are the shorthand.\n\n NOT named \"layer\": CSS Paged Media 3 \u00A73.1 already defines \"page layers\"\n (page background, canvas, borders, contents, margin boxes) and those are\n parts of the PAGE BOX, not a z-ladder for content. Reusing the word for a\n different concept would collide with the spec vocabulary this project\n tracks. The pin EDGE modifiers already own .gp-top/.gp-bottom, so the\n ladder avoids those words too.\n\n .gp-behind is the one that earns its place: it puts a pinned image UNDER\n the page's text, which is otherwise impossible to express without a bare\n negative z-index. \"Above\" needs no class \u2014 an out-of-flow pin already\n paints above in-flow content.\n\n Two things silently defeat .gp-behind, neither visible at the use site:\n - a stacking context on the .page/.spread ancestor (z-index, isolation,\n opacity, filter, transform on it traps the negative layer inside).\n Core keeps .page/.spread at 'position: relative; z-index: auto'\n precisely so they are not stacking contexts.\n - a clipping ancestor (overflow other than visible) \u2014 but only where\n the art actually overhangs that ancestor's clip box on a clipped\n axis: the overhang is cut off, the same mechanism that clips a\n .gp-bleed plate back to the wrapper's width. Clipping never reorders\n layers \u2014 within-bounds art under a clipping .page prints whole and\n still behind (measured; see the build audit's comment in\n engine/compiler/build.ts), and a static wrapper's overflow never\n binds an abspos .gp-pin at all.\n The build-time engine.layer.trapped audit reports both against the live\n ancestor chain. printsafe/page-containment is only an early source hint for\n declarations written directly on .page/.spread. */\n:root {\n --gp-z-behind: -1;\n --gp-z-base: 0;\n --gp-z-raised: 1;\n --gp-z-front: 2;\n}\n.gp-behind { z-index: var(--gp-z-behind); }\n.gp-base { z-index: var(--gp-z-base); }\n.gp-raised { z-index: var(--gp-z-raised); }\n.gp-front { z-index: var(--gp-z-front); }\n\n/* GFM-style alert/callout boxes (#237) \u2014 the DOM gfm-alerts.ts emits from\n \"> [!TYPE]\" blockquote syntax when a project opts into the bundled\n gutterpress-gfm-alerts feature (BUILTIN_OPTIONAL_PLUGINS, renderer.ts).\n The plugin is optional and inert by default; these rules are equally\n inert wherever the classes never appear, exactly like every other\n utility above, so shipping them costs nothing to a book that has not\n turned the feature on.\n\n This is authored-COMPONENT vocabulary, not the @marker structural family\n (markers.js/MARKER_CSS) \u2014 CLAUDE.md \u00A76 splits the two core CSS blocks by\n ROLE, and an author-facing box an author invokes via inline syntax is the\n same role as every other gp-* utility here, not page/chapter/section DOM.\n\n Deliberately minimal (CLAUDE.md \"thin over capable\" / the issue's own\n \"a rule and a label\"): a left border plus a bold label, :where()'d to\n zero specificity so a theme's own (unlayered) rule for any of these\n classes wins outright regardless of selector weight \u2014 see the\n cascade-layers note atop this file. Five semantic accent colors (the same\n NOTE/TIP/IMPORTANT/WARNING/CAUTION hues GitHub's own alerts use \u2014 a\n long-established, non-proprietary convention, not DC branding) are\n exposed as :root custom properties, the same author-settable-surface\n pattern as the --gp-z-* ladder above: a book retints every alert of one\n type by overriding a single property, no specificity fight required.\n --gp-alert-color cascades from the type modifier down to .gp-alert-title\n through ordinary CSS inheritance (the title is always a DOM descendant of\n the box), so it is set in exactly five places, not ten. */\n:root {\n --gp-alert-note-color: #0969da;\n --gp-alert-tip-color: #1a7f37;\n --gp-alert-important-color: #8250df;\n --gp-alert-warning-color: #9a6700;\n --gp-alert-caution-color: #cf222e;\n}\n:where(.gp-alert) {\n margin: 1em 0;\n padding: 0.5em 1em;\n border-left: 0.25em solid var(--gp-alert-color, currentColor);\n}\n:where(.gp-alert-title) {\n margin: 0 0 0.5em;\n font-weight: bold;\n color: var(--gp-alert-color, inherit);\n}\n:where(.gp-alert-note) { --gp-alert-color: var(--gp-alert-note-color); }\n:where(.gp-alert-tip) { --gp-alert-color: var(--gp-alert-tip-color); }\n:where(.gp-alert-important) { --gp-alert-color: var(--gp-alert-important-color); }\n:where(.gp-alert-warning) { --gp-alert-color: var(--gp-alert-warning-color); }\n:where(.gp-alert-caution) { --gp-alert-color: var(--gp-alert-caution-color); }\n";
136
+ export declare const GUTTERPRESS_CSS = "\n/* gp-* author image/block vocabulary. One vocabulary, gp-* only \u2014 the\n pre-vocabulary utility names (.center/.float-left/.float-right/\n .full-width/.full-bleed) were REMOVED when gp-* shipped; books rename\n the classes in their markdown (see the migration note). Source ORDER is\n the contract \u2014 see the doctrine comment above. */\n\n/* flow positions */\n.gp-left {\n float: left;\n margin: 0 var(--gp-gap, 1em) var(--gp-gap, 1em) 0;\n max-width: 50%;\n}\n.gp-right {\n float: right;\n margin: 0 0 var(--gp-gap, 1em) var(--gp-gap, 1em);\n max-width: 50%;\n}\n.gp-center {\n display: block;\n float: none;\n margin-left: auto;\n margin-right: auto;\n max-width: 100%;\n}\n.gp-full {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n@page gp-full-bleed { margin-left: 0; margin-right: 0; }\n.gp-bleed {\n display: block;\n float: none;\n break-before: page;\n page: gp-full-bleed;\n max-width: none;\n width: 100%;\n margin-left: 0;\n margin-right: 0;\n}\n\n/* sizes \u2014 AFTER the flow positions so max-width:100% lifts the floats' 50%\n cap at equal specificity */\n.gp-small { width: 25%; max-width: 100%; }\n.gp-medium { width: 50%; max-width: 100%; }\n.gp-large { width: 75%; max-width: 100%; }\n\n/* float clearance presets \u2014 consumed by var(--gp-gap) in the float rules\n above and by .gp-shape's shape-margin below; --gp-gap itself is\n author-settable CSS */\n.gp-tight { --gp-gap: 0.5em; }\n.gp-loose { --gp-gap: 2em; }\n\n/* column runs \u2014 plain CSS Multi-column, exposed as author vocabulary so\n \"put this in two columns\" does not require borrowing a styled container\n from the book's own component layer. That borrowing is what this exists\n to prevent: a book whose theme paints .section chrome by default gives\n every author who opens a section just to start a column run a panel they\n did not ask for, and the book then needs a reset rule to take it back.\n With a neutral primitive the author opts into columns and nothing else.\n\n Permanent vocabulary, not a shim: Chromium implements multicol natively\n and these rules are the standard properties verbatim, so there is no\n spec gap here to remove later. Deliberately minimal \u2014 column-fill is\n NOT set, because the correct value depends on whether the run fragments\n across pages (auto packs each page's columns; the CSS initial balance is\n right for a run that fits on one page) and only the author knows which.\n --gp-column-gap is author-settable.\n .gp-columns is what the core @columns marker emits (markers.js); on its\n own it is two columns, and @columns 1 to 5 add the matching count, which\n wins because it comes later at the same specificity. */\n.gp-columns, .gp-columns-1, .gp-columns-2, .gp-columns-3, .gp-columns-4, .gp-columns-5 {\n column-gap: var(--gp-column-gap, 1.5em);\n}\n.gp-columns { columns: 2; }\n.gp-columns-1 { columns: 1; }\n.gp-columns-2 { columns: 2; }\n.gp-columns-3 { columns: 3; }\n.gp-columns-4 { columns: 4; }\n.gp-columns-5 { columns: 5; }\n\n/* the per-shape decisions the paragraph above deliberately leaves to the\n author, named instead of left as raw CSS every book was reinventing\n (CLAUDE.md \u00A70: \"behavior broadly useful to non-technical authors belongs\n in core\").\n Permanent vocabulary, standard properties verbatim \u2014 same rationale as\n the column/grid runs above. One name each, no aliases:\n .gp-columns-all column-span: all a heading or block that\n spans every column in the\n run it sits inside.\n .gp-columns-flow column-fill: auto a run that FRAGMENTS across\n pages \u2014 every page's\n columns fill instead of\n only the last one\n balancing (the dead-column\n collapse the build's\n engine.multicol.dead-column\n warning names this fix\n for).\n .gp-columns-balanced column-fill: balance a run that fits on ONE\n page (the CSS initial\n value \u2014 ragged columns\n would be wrong here). */\n.gp-columns-all { column-span: all; }\n.gp-columns-flow { column-fill: auto; }\n.gp-columns-balanced { column-fill: balance; }\n\n/* grid runs \u2014 the SLOTTED counterpart to the column runs above. Grid places\n each child into the next cell, across then down (deterministic slots: card\n layouts, stat blocks, image-plus-caption pairs); columns FLOW one text run\n down then across. Same neutral-primitive rationale as .gp-columns-*, and\n permanent vocabulary for the same reason: standard CSS Grid verbatim, no\n spec gap to remove later. MEASURED (Chromium 151, gp-grid evidence pack):\n grid rows fragment across sheets with EXACT print/viewer parity \u2014 2- and\n 3-col, unequal item heights, mid-row cuts, multi-sheet overflow,\n break-inside:avoid, gap geometry \u2014 so a grid taller than the page is safe,\n no fit-one-page constraint. Two things to know, not fix:\n - on a min-height page root (MARKER_CSS), default align-content\n stretches rows apart to fill the page \u2014 identically in both engines.\n Authors wanting packed rows set align-content: start.\n - a @page-break / @column-break marker DIRECTLY inside a grid container\n becomes a grid item and corrupts placement (the one measured parity\n break); markers.js diagnoses it (break_inside_grid).\n --gp-grid-gap is author-settable. */\n.gp-grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gp-grid-gap, 1.5em); }\n.gp-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gp-grid-gap, 1.5em); }\n\n/* fragmentation controls \u2014 generic pagination utilities for any element,\n independent of the column/grid vocabulary above (a book reached for\n these just as often outside a multicol run: keeping a card whole,\n forcing a section to start a fresh page). Standard properties only \u2014\n this project is Chromium-only (CLAUDE.md), so there are no legacy\n page-break-* twins to also emit. One name each. */\n.gp-no-break { break-inside: avoid; }\n.gp-break-before { break-before: page; }\n\n/* shape wrap \u2014 text follows the image's alpha silhouette instead of its\n rectangular box. shape-outside only applies to floats, so this is inert\n without .gp-left/.gp-right (and under .gp-pin, which un-floats). The\n shape URL cannot be written in CSS (url() contexts can't read attr()),\n so the image renderer rule (images.ts) mirrors the src into an inline\n --gp-shape:url(...) custom property whenever it sees this class --\n authors only ever type the class. threshold 0.2 ignores near-transparent\n anti-aliasing halos; shape-margin shares the float-gap vocabulary. */\nimg.gp-shape {\n shape-outside: var(--gp-shape);\n shape-image-threshold: 0.2;\n shape-margin: var(--gp-gap, 1em);\n}\n\n/* pin \u2014 within the nearest positioned ancestor (.page/.spread, rule above).\n inset:0 and the explicit centers are load-bearing; see doctrine comment. */\n.gp-pin {\n position: absolute;\n inset: 0;\n align-self: center;\n justify-self: center;\n margin: 0;\n max-width: 100%;\n}\n\n/* pin edge modifiers \u2014 AFTER .gp-pin to beat its center defaults;\n justify-self is inert on in-flow floats, so gp-left/gp-right safely do\n double duty as flow float + pin edge */\n.gp-top { align-self: start; }\n.gp-bottom { align-self: end; }\n.gp-left { justify-self: start; }\n.gp-right { justify-self: end; }\n\n/* wrapper-margin neutralization (same pattern and rationale as the\n .gp-bleed paragraph-margin note in the doctrine comment; for pin, the\n emptied paragraph would otherwise leave a phantom margin gap in flow) */\n:where(p:has(> img.gp-bleed:only-child)) { margin: 0; }\n:where(p:has(> img.gp-pin:only-child)) { margin: 0; }\n\n/* depth \u2014 a named ladder for z-index, so books stop hand-tuning bare\n integers. A real book measured 21 z-index declarations using only four\n distinct values (-1, 0, 1, 2), each written literally at its use site.\n The custom properties are the author-settable surface (a book needing a\n deeper stack raises them once); the classes are the shorthand.\n\n NOT named \"layer\": CSS Paged Media 3 \u00A73.1 already defines \"page layers\"\n (page background, canvas, borders, contents, margin boxes) and those are\n parts of the PAGE BOX, not a z-ladder for content. Reusing the word for a\n different concept would collide with the spec vocabulary this project\n tracks. The pin EDGE modifiers already own .gp-top/.gp-bottom, so the\n ladder avoids those words too.\n\n .gp-behind is the one that earns its place: it puts a pinned image UNDER\n the page's text, which is otherwise impossible to express without a bare\n negative z-index. \"Above\" needs no class \u2014 an out-of-flow pin already\n paints above in-flow content.\n\n Two things silently defeat .gp-behind, neither visible at the use site:\n - a stacking context on the .page/.spread ancestor (z-index, isolation,\n opacity, filter, transform on it traps the negative layer inside).\n Core keeps .page/.spread at 'position: relative; z-index: auto'\n precisely so they are not stacking contexts.\n - a clipping ancestor (overflow other than visible) \u2014 but only where\n the art actually overhangs that ancestor's clip box on a clipped\n axis: the overhang is cut off, the same mechanism that clips a\n .gp-bleed plate back to the wrapper's width. Clipping never reorders\n layers \u2014 within-bounds art under a clipping .page prints whole and\n still behind (measured; see the build audit's comment in\n engine/compiler/build.ts), and a static wrapper's overflow never\n binds an abspos .gp-pin at all.\n The build-time engine.layer.trapped audit reports both against the live\n ancestor chain. printsafe/page-containment is only an early source hint for\n declarations written directly on .page/.spread. */\n:root {\n --gp-z-behind: -1;\n --gp-z-base: 0;\n --gp-z-raised: 1;\n --gp-z-front: 2;\n}\n.gp-behind { z-index: var(--gp-z-behind); }\n.gp-base { z-index: var(--gp-z-base); }\n.gp-raised { z-index: var(--gp-z-raised); }\n.gp-front { z-index: var(--gp-z-front); }\n\n/* GFM-style alert/callout boxes (#237) \u2014 the DOM gfm-alerts.ts emits from\n \"> [!TYPE]\" blockquote syntax when a project opts into the bundled\n gutterpress-gfm-alerts feature (BUILTIN_OPTIONAL_PLUGINS, renderer.ts).\n The plugin is optional and inert by default; these rules are equally\n inert wherever the classes never appear, exactly like every other\n utility above, so shipping them costs nothing to a book that has not\n turned the feature on.\n\n This is authored-COMPONENT vocabulary, not the @marker structural family\n (markers.js/MARKER_CSS) \u2014 CLAUDE.md \u00A76 splits the two core CSS blocks by\n ROLE, and an author-facing box an author invokes via inline syntax is the\n same role as every other gp-* utility here, not page/chapter/section DOM.\n\n Deliberately minimal (CLAUDE.md \"thin over capable\" / the issue's own\n \"a rule and a label\"): a left border plus a bold label, :where()'d to\n zero specificity so a theme's own (unlayered) rule for any of these\n classes wins outright regardless of selector weight \u2014 see the\n cascade-layers note atop this file. Five semantic accent colors (the same\n NOTE/TIP/IMPORTANT/WARNING/CAUTION hues GitHub's own alerts use \u2014 a\n long-established, non-proprietary convention, not DC branding) are\n exposed as :root custom properties, the same author-settable-surface\n pattern as the --gp-z-* ladder above: a book retints every alert of one\n type by overriding a single property, no specificity fight required.\n --gp-alert-color cascades from the type modifier down to .gp-alert-title\n through ordinary CSS inheritance (the title is always a DOM descendant of\n the box), so it is set in exactly five places, not ten. */\n:root {\n --gp-alert-note-color: #0969da;\n --gp-alert-tip-color: #1a7f37;\n --gp-alert-important-color: #8250df;\n --gp-alert-warning-color: #9a6700;\n --gp-alert-caution-color: #cf222e;\n}\n:where(.gp-alert) {\n margin: 1em 0;\n padding: 0.5em 1em;\n border-left: 0.25em solid var(--gp-alert-color, currentColor);\n}\n:where(.gp-alert-title) {\n margin: 0 0 0.5em;\n font-weight: bold;\n color: var(--gp-alert-color, inherit);\n}\n:where(.gp-alert-note) { --gp-alert-color: var(--gp-alert-note-color); }\n:where(.gp-alert-tip) { --gp-alert-color: var(--gp-alert-tip-color); }\n:where(.gp-alert-important) { --gp-alert-color: var(--gp-alert-important-color); }\n:where(.gp-alert-warning) { --gp-alert-color: var(--gp-alert-warning-color); }\n:where(.gp-alert-caution) { --gp-alert-color: var(--gp-alert-caution-color); }\n";
137
137
  /**
138
138
  * GP_CLASSES — every class an author may legitimately write with a `gp-`
139
139
  * prefix: the `.gp-*` selectors in `GUTTERPRESS_CSS` above, the two
@@ -7,15 +7,15 @@ import {
7
7
  TARGET_IDS,
8
8
  scaffoldExtension,
9
9
  scaffoldProject
10
- } from "./cli-ac7zs8sp.js";
10
+ } from "./cli-ev175hx9.js";
11
11
  import {
12
12
  resolveGhostscript
13
- } from "./cli-n9e1mzb7.js";
13
+ } from "./cli-0prrt9e4.js";
14
14
  import {
15
15
  UsageError,
16
16
  rejectExtraPositionals,
17
17
  rejectUnknownFlags
18
- } from "./cli-nzzsyw1e.js";
18
+ } from "./cli-182j48xc.js";
19
19
  import"./cli-wqy8hnnh.js";
20
20
  import {
21
21
  EXIT_CODES
@@ -2,15 +2,15 @@ import {
2
2
  executeValidation,
3
3
  publishTargetFor,
4
4
  reportMissingTools
5
- } from "./cli-ac7zs8sp.js";
5
+ } from "./cli-ev175hx9.js";
6
6
  import {
7
7
  log
8
- } from "./cli-n9e1mzb7.js";
8
+ } from "./cli-0prrt9e4.js";
9
9
  import {
10
10
  UsageError,
11
11
  rejectExtraPositionals,
12
12
  rejectUnknownFlags
13
- } from "./cli-nzzsyw1e.js";
13
+ } from "./cli-182j48xc.js";
14
14
  import"./cli-wqy8hnnh.js";
15
15
  import {
16
16
  BuildError,
@@ -7,10 +7,10 @@ import {
7
7
  runBuild,
8
8
  splitOutPath,
9
9
  startPreviewServer
10
- } from "./cli-ac7zs8sp.js";
10
+ } from "./cli-ev175hx9.js";
11
11
  import {
12
12
  log
13
- } from "./cli-n9e1mzb7.js";
13
+ } from "./cli-0prrt9e4.js";
14
14
  import {
15
15
  UsageError,
16
16
  parseFormat,
@@ -18,7 +18,7 @@ import {
18
18
  rejectExtraPositionals,
19
19
  rejectUnknownFlags,
20
20
  resolvePort
21
- } from "./cli-nzzsyw1e.js";
21
+ } from "./cli-182j48xc.js";
22
22
  import"./cli-wqy8hnnh.js";
23
23
  import {
24
24
  BuildError
@@ -11,16 +11,16 @@ import {
11
11
  publishProviderFor,
12
12
  resolvePublishFormat,
13
13
  runPublish
14
- } from "./cli-ac7zs8sp.js";
14
+ } from "./cli-ev175hx9.js";
15
15
  import {
16
16
  FileTokenStore,
17
17
  log
18
- } from "./cli-n9e1mzb7.js";
18
+ } from "./cli-0prrt9e4.js";
19
19
  import {
20
20
  UsageError,
21
21
  rejectExtraPositionals,
22
22
  rejectUnknownFlags
23
- } from "./cli-nzzsyw1e.js";
23
+ } from "./cli-182j48xc.js";
24
24
  import"./cli-wqy8hnnh.js";
25
25
  import {
26
26
  EXIT_CODES
package/dist/render.js CHANGED
@@ -457,16 +457,23 @@ function resolveMarkerDeclaration(name, rawDecl, rawRegistry, originOf) {
457
457
  }
458
458
  return { name, baseKind: name, ...resolveContainerShape(name, pluginName, rawDecl) };
459
459
  }
460
+ var CORE_MARKER_OWNER = "Gutterpress";
461
+ var CORE_DECLARED_MARKERS = {
462
+ columns: {
463
+ class: "gp-columns",
464
+ variants: { 1: "gp-columns-1", 2: "gp-columns-2", 3: "gp-columns-3", 4: "gp-columns-4", 5: "gp-columns-5" }
465
+ }
466
+ };
460
467
  function buildDeclaredMarkerRegistry(sources) {
461
468
  const rawRegistry = new Map;
462
469
  const originOf = new Map;
463
- for (const { pluginName, markers } of sources) {
470
+ for (const { pluginName, markers } of [{ pluginName: CORE_MARKER_OWNER, markers: CORE_DECLARED_MARKERS }, ...sources]) {
464
471
  if (!markers)
465
472
  continue;
466
473
  for (const [name, rawDecl] of Object.entries(markers)) {
467
474
  validateDeclaredMarkerName(name, pluginName);
468
- if (KNOWN_KINDS.includes(name)) {
469
- throw new Error(`Plugin "${pluginName}" declares marker "@${name}", which is a core Gutterpress marker name ` + `(${KNOWN_KINDS.map((k) => `@${k}`).join(", ")}). Core marker names cannot be shadowed — ` + `rename the plugin's marker.`);
475
+ if (KNOWN_KINDS.includes(name) || pluginName !== CORE_MARKER_OWNER && name in CORE_DECLARED_MARKERS) {
476
+ throw new Error(`Plugin "${pluginName}" declares marker "@${name}", which is a core Gutterpress marker name ` + `(${[...KNOWN_KINDS, ...Object.keys(CORE_DECLARED_MARKERS)].map((k) => `@${k}`).join(", ")}). ` + `Core marker names cannot be shadowed — ` + `rename the plugin's marker.`);
470
477
  }
471
478
  if (rawRegistry.has(name)) {
472
479
  throw new Error(`Marker "@${name}" is declared by both plugin "${originOf.get(name)}" and plugin "${pluginName}". ` + `Declared marker names must be unique across every loaded plugin — rename one of them.`);
@@ -549,7 +556,7 @@ function plugin(md, pluginOptions = {}) {
549
556
  preferPagesInSpreads: false,
550
557
  ...pluginOptions
551
558
  };
552
- const declaredMarkers = options.declaredMarkers instanceof Map && options.declaredMarkers.size > 0 ? options.declaredMarkers : null;
559
+ const declaredMarkers = options.declaredMarkers instanceof Map && options.declaredMarkers.size > 0 ? options.declaredMarkers : buildDeclaredMarkerRegistry([]);
553
560
  const declaredWords = declaredKindWords(declaredMarkers);
554
561
  function markerBlock(state, startLine, endLine, silent) {
555
562
  const pos = state.bMarks[startLine] + state.tShift[startLine];
@@ -1108,9 +1115,19 @@ var GUTTERPRESS_CSS = `
1108
1115
  NOT set, because the correct value depends on whether the run fragments
1109
1116
  across pages (auto packs each page's columns; the CSS initial balance is
1110
1117
  right for a run that fits on one page) and only the author knows which.
1111
- --gp-column-gap is author-settable. */
1112
- .gp-columns-2 { columns: 2; column-gap: var(--gp-column-gap, 1.5em); }
1113
- .gp-columns-3 { columns: 3; column-gap: var(--gp-column-gap, 1.5em); }
1118
+ --gp-column-gap is author-settable.
1119
+ .gp-columns is what the core @columns marker emits (markers.js); on its
1120
+ own it is two columns, and @columns 1 to 5 add the matching count, which
1121
+ wins because it comes later at the same specificity. */
1122
+ .gp-columns, .gp-columns-1, .gp-columns-2, .gp-columns-3, .gp-columns-4, .gp-columns-5 {
1123
+ column-gap: var(--gp-column-gap, 1.5em);
1124
+ }
1125
+ .gp-columns { columns: 2; }
1126
+ .gp-columns-1 { columns: 1; }
1127
+ .gp-columns-2 { columns: 2; }
1128
+ .gp-columns-3 { columns: 3; }
1129
+ .gp-columns-4 { columns: 4; }
1130
+ .gp-columns-5 { columns: 5; }
1114
1131
 
1115
1132
  /* the per-shape decisions the paragraph above deliberately leaves to the
1116
1133
  author, named instead of left as raw CSS every book was reinventing
@@ -1311,8 +1328,12 @@ var GP_CLASSES = new Set([
1311
1328
  "gp-large",
1312
1329
  "gp-tight",
1313
1330
  "gp-loose",
1331
+ "gp-columns",
1332
+ "gp-columns-1",
1314
1333
  "gp-columns-2",
1315
1334
  "gp-columns-3",
1335
+ "gp-columns-4",
1336
+ "gp-columns-5",
1316
1337
  "gp-columns-all",
1317
1338
  "gp-columns-flow",
1318
1339
  "gp-columns-balanced",
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  executeAndReport
3
- } from "./cli-ac7zs8sp.js";
3
+ } from "./cli-ev175hx9.js";
4
4
  import {
5
5
  log
6
- } from "./cli-n9e1mzb7.js";
6
+ } from "./cli-0prrt9e4.js";
7
7
  import {
8
8
  UsageError,
9
9
  rejectExtraPositionals,
10
10
  rejectUnknownFlags
11
- } from "./cli-nzzsyw1e.js";
11
+ } from "./cli-182j48xc.js";
12
12
  import"./cli-wqy8hnnh.js";
13
13
  import {
14
14
  BuildError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gutterpress",
3
- "version": "0.11.16-alpha.6",
3
+ "version": "0.11.16",
4
4
  "description": "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
5
5
  "author": "itlackey",
6
6
  "license": "MPL-2.0",