gutterpress 0.11.23-alpha.2 → 0.11.23-alpha.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.
Files changed (55) hide show
  1. package/README.md +6 -7
  2. package/dist/{README-8ef336pp.md → README-8db7btxb.md} +13 -19
  3. package/dist/api/index.d.ts +1 -1
  4. package/dist/api/index.js +4 -4
  5. package/dist/{build-encgnv0c.js → build-m78jcpf7.js} +7 -7
  6. package/dist/{cli-xq6djqbj.js → cli-1h17ktsg.js} +84 -113
  7. package/dist/{cli-kh8v4vvw.js → cli-5jzyw06s.js} +1 -1
  8. package/dist/{cli-sdmv4bba.js → cli-h4x81x97.js} +112 -8
  9. package/dist/{cli-evg8sbht.js → cli-n2tsxqpn.js} +1 -1
  10. package/dist/{cli-aqh6brew.js → cli-s6djx4ma.js} +1 -1
  11. package/dist/{cli-pwwfxdgb.js → cli-t8be9yeb.js} +9 -20
  12. package/dist/{cli-pz4bn98t.js → cli-xsrffqzt.js} +19 -13
  13. package/dist/cli.js +12 -12
  14. package/dist/{doctor-5gtpgpd1.js → doctor-j71jqce3.js} +3 -3
  15. package/dist/engine/shared/gcpm-extract.d.ts +8 -0
  16. package/dist/engine/shared/print-area.d.ts +16 -4
  17. package/dist/{engine-tn13gk0b.js → engine-1r6q80tq.js} +2 -2
  18. package/dist/{engine-mc5br8g8.js → engine-m4y10shc.js} +1 -1
  19. package/dist/{ext-wn2a5afq.js → ext-fq2hg9va.js} +7 -7
  20. package/dist/{extension-restore-s3x1618g.js → extension-restore-9dh7c4tp.js} +2 -2
  21. package/dist/{extension-restore-g8jnmmzq.js → extension-restore-tmxtzkm0.js} +4 -4
  22. package/dist/{gutterpress-viewer-701vf4qp.js → gutterpress-viewer-mafsby5k.js} +9 -2
  23. package/dist/{index-2bjcghze.js → index-0wee4408.js} +9 -20
  24. package/dist/{index-x3ema2w3.js → index-7pck1q9c.js} +124 -17
  25. package/dist/{index-0skhjx3e.js → index-nedd07bk.js} +19 -13
  26. package/dist/{index-4x6y8krm.js → index-nvmf22rt.js} +1 -1
  27. package/dist/{index-j5z86r4a.js → index-prqvz3xm.js} +213 -276
  28. package/dist/index.js +5 -5
  29. package/dist/lib/extension-manager.d.ts +8 -7
  30. package/dist/lib/extension-manifest.d.ts +1 -13
  31. package/dist/lib/manifest.d.ts +15 -1
  32. package/dist/lib/markdown/assemble.d.ts +4 -3
  33. package/dist/lib/page-size.d.ts +34 -27
  34. package/dist/lib/printsafe.d.ts +1 -0
  35. package/dist/lib/project-templates.d.ts +9 -0
  36. package/dist/manifest-8afhrk30.yaml +19 -0
  37. package/dist/manifest-d4f9q79e.yaml +23 -0
  38. package/dist/{manifest-eagfhba6.yaml → manifest-gf13sjp8.yaml} +10 -2
  39. package/dist/manifest-my7mdv8j.yaml +23 -0
  40. package/dist/{manifest.schema-t7nx2stg.json → manifest.schema-650pe0d1.json} +15 -3
  41. package/dist/{new-mhs46pw3.js → new-s4zcaepg.js} +7 -7
  42. package/dist/{package-aenwjew3.json → package-awwkt7sa.json} +0 -1
  43. package/dist/{page-rules-nsj3aw42.css → page-rules-fj09xct5.css} +12 -40
  44. package/dist/{plugin.test.js-xgxrd8hf.tpl → plugin.test.js-gxzqqfdh.tpl} +0 -1
  45. package/dist/{plugins-1sxe0dkz.js → plugins-4vaf27n9.js} +3 -3
  46. package/dist/{plugins-2cek4mz1.js → plugins-80emnf31.js} +1 -1
  47. package/dist/{preflight-3k2b1x8e.js → preflight-c7w1xdn3.js} +7 -7
  48. package/dist/{preview-6p9v6rht.js → preview-mzytcwyk.js} +7 -7
  49. package/dist/{publish-qgsngy8s.js → publish-fez14ad4.js} +7 -7
  50. package/dist/render.js +24 -561
  51. package/dist/schema/manifest.types.d.ts +22 -0
  52. package/dist/{tokens-7984461t.css → tokens-ye64p899.css} +5 -12
  53. package/dist/{validate-0v7xw6wa.js → validate-p2chr6hr.js} +7 -7
  54. package/package.json +1 -1
  55. package/dist/manifest-n1gh3qw5.yaml +0 -9
package/README.md CHANGED
@@ -363,7 +363,7 @@ List, add, remove, enable, or disable the project's extensions. Markdown-it
363
363
  plugins, looks (stylesheets) and component libraries are all extensions — one
364
364
  `extensions:` list in `manifest.yaml`, in load order (see
365
365
  [Extensions](#extensions) below). These are the same shared-lib functions the
366
- desktop app's Look and Features views call, so an extension added from the
366
+ desktop app's Extensions tab calls, so an extension added from the
367
367
  terminal is the same entry the GUI shows.
368
368
 
369
369
  ```sh
@@ -460,7 +460,7 @@ never touched.
460
460
 
461
461
  ```sh
462
462
  gutterpress ext remove markdown-it-highlightjs ./my-book
463
- gutterpress ext remove ./extensions/zine ./my-book
463
+ gutterpress ext remove zine ./my-book
464
464
  ```
465
465
 
466
466
  #### `gutterpress ext enable` / `gutterpress ext disable`
@@ -475,8 +475,8 @@ gutterpress ext enable markdown-it-mark ./my-book
475
475
 
476
476
  #### `gutterpress ext search`
477
477
 
478
- Search **npm** for extensions — the same list the desktop app's Features view
479
- shows under "Find more on npm." Not project-scoped (no `dir` argument): it
478
+ Search **npm** for extensions — the same list the desktop app's Extensions tab
479
+ shows under *Search*. Not project-scoped (no `dir` argument): it
480
480
  queries the registry for packages tagged `gutterpress` (Gutterpress
481
481
  extensions: plugins, looks, component libraries) or `markdown-it-plugin` (the
482
482
  markdown-it ecosystem's own tag — those work in Gutterpress unchanged), and
@@ -521,7 +521,7 @@ extensions:
521
521
  # a feature bundled with Gutterpress — nothing to install, works offline
522
522
  - markdown-it-mark
523
523
  # a folder or plugin file, relative to manifest.yaml — referenced in place
524
- - ./extensions/clean-book
524
+ - ./extensions/house-look
525
525
  - ./plugins/my-custom-plugin.js
526
526
  # an npm package, pinned to the exact version `gutterpress ext add` installed
527
527
  - markdown-it-highlightjs@4.3.0
@@ -547,8 +547,7 @@ An extension folder (or npm package) describes itself in its **`package.json`**
547
547
  "gutterpress": {
548
548
  "styles": ["styles/plugin.css"],
549
549
  "snippets": "snippets",
550
- "components": "components.yaml",
551
- "tokensFile": "styles/tokens.css"
550
+ "components": "components.yaml"
552
551
  }
553
552
  }
554
553
  ```
@@ -17,7 +17,7 @@ arrangement of the files is the part worth keeping.
17
17
  ├── base.css element baseline. Bare p/h2/table/code.
18
18
  ├── components.css named components + their public tokens.
19
19
  ├── page-templates.css .page.* layouts — arrangement WITHIN a page.
20
- ├── page-rules.css @page geometry, margin boxes, running heads.
20
+ ├── page-rules.css @page margin boxes, running heads, named pages.
21
21
  └── book.css this book's overrides. Loads last.
22
22
  ```
23
23
 
@@ -64,7 +64,7 @@ instantly: **where does this rule go?**
64
64
  | what a plain paragraph or table looks like | `base.css` |
65
65
  | a named thing an author opts into | `components.css` |
66
66
  | how one page arranges its content | `page-templates.css` |
67
- | margins, folios, running heads | `page-rules.css` |
67
+ | folios, running heads, named pages | `page-rules.css` |
68
68
  | one chapter of one book | `book.css` |
69
69
 
70
70
  If a rule seems to belong in two of them, it is usually two rules.
@@ -156,23 +156,17 @@ author retypes must be found and replaced across every chapter when it
156
156
  changes. A variant expressed as a component name plus a CSS rule changes in
157
157
  one place, and chapters written afterwards get it for free.
158
158
 
159
- ### 4. `@page { size }` is not optional, and it must match the manifest
160
-
161
- `page-rules.css` opens by declaring the trim:
162
-
163
- ```css
164
- @page { size: 6in 9in; }
165
- ```
166
-
167
- That line is load-bearing in the most literal sense. With no `size:` anywhere
168
- in the book's CSS, Chromium falls back to US Letter and prints the whole book
169
- at the wrong trim, with no error — this is the one failure in the stack that
170
- costs money rather than time.
171
-
172
- The manifest's `preset:`/`page:` remains the source of truth: it is what
173
- `gutterpress validate` measures the produced PDF against, and what the publish
174
- targets check. The CSS line is the instruction that satisfies it. Change one,
175
- change the other — and let validate catch you when you forget.
159
+ ### 4. The page size and margins are the book's, not the look's
160
+
161
+ A look never declares `@page { size }` or `@page { margin }`. The book's
162
+ manifest records both (`preset:`, `page: width / height / margin`, which the
163
+ app edits under Setup > Details), and the build writes them as the `@page`
164
+ rule after every stylesheet, so a `size` in a look is ignored and reported by
165
+ the print-safety check, and a `margin` holds only until the author sets
166
+ margins in the app. `page-rules.css` owns what IS a look's: the margin boxes
167
+ (folios, running heads) and the named pages. Design them to sit in whatever
168
+ margin the book gives them — a folio at `@bottom-right` needs no particular
169
+ margin to work.
176
170
 
177
171
  ### 5. Keep the catalog honest
178
172
 
@@ -52,7 +52,7 @@ export type { ProjectStyle } from "../lib/style-resolver.ts";
52
52
  export { readManifestFields, setManifestFields, setActiveStyles, } from "../lib/manifest-config.ts";
53
53
  export type { ProjectConfigFields } from "../lib/manifest-config.ts";
54
54
  export { readPageSetup, setPageSetup } from "../lib/page-size.ts";
55
- export type { PageSetup, PageSizeChoice, PageSizePoints } from "../lib/page-size.ts";
55
+ export type { PageMargin, PageSetup, PageSetupChange, PageSizeChoice, PageSizePoints } from "../lib/page-size.ts";
56
56
  export { providerFor, restoreVersionWithBackup, isNoChangesError, countUnversionedChanges, whenGitIdle, AUTO_SNAPSHOT_MESSAGE, RESTORE_BACKUP_MESSAGE, HISTORY_PAGE_LIMIT, listLocalBranches, switchBranch, SWITCH_BRANCH_SNAPSHOT_MESSAGE, } from "../lib/source-provider.ts";
57
57
  export type { ListHistoryOptions, HistoryPage, UnversionedChanges, LocalBranches, SwitchBranchOptions, SwitchBranchResult, } from "../lib/source-provider.ts";
58
58
  export { describeVersions, listOnlineVersions, compareVersionFile, exportVersionTree, VERSION_CHANGES_SHOWN, } from "../lib/version-changes.ts";
package/dist/api/index.js CHANGED
@@ -101,7 +101,7 @@ import {
101
101
  substituteVariables,
102
102
  syncProject,
103
103
  testRemoteAccess
104
- } from "../index-j5z86r4a.js";
104
+ } from "../index-prqvz3xm.js";
105
105
  import {
106
106
  DEFAULT_NPM_REGISTRY,
107
107
  MANIFEST_FILENAMES,
@@ -130,7 +130,7 @@ import {
130
130
  setExtensionEnabled,
131
131
  updateExtensions,
132
132
  validateProjectExtensions
133
- } from "../index-x3ema2w3.js";
133
+ } from "../index-7pck1q9c.js";
134
134
  import {
135
135
  BUNDLED_EXTENSIONS,
136
136
  EXTENSION_MANIFEST_FILENAME,
@@ -145,9 +145,9 @@ import {
145
145
  pathEscapesFolder,
146
146
  readExtensionMeta,
147
147
  resolveExtension
148
- } from "../index-2bjcghze.js";
148
+ } from "../index-0wee4408.js";
149
149
  import"../index-ht1bcqdd.js";
150
- import"../index-0skhjx3e.js";
150
+ import"../index-nedd07bk.js";
151
151
  import {
152
152
  BuildError
153
153
  } from "../index-46ycxe6r.js";
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  runBuild,
3
3
  splitOutPath
4
- } from "./cli-xq6djqbj.js";
5
- import"./cli-evg8sbht.js";
4
+ } from "./cli-1h17ktsg.js";
5
+ import"./cli-n2tsxqpn.js";
6
6
  import"./cli-ht1bcqdd.js";
7
- import"./cli-pz4bn98t.js";
7
+ import"./cli-xsrffqzt.js";
8
8
  import"./cli-2ppw6q9v.js";
9
9
  import"./cli-eyyggect.js";
10
10
  import"./cli-asap4t1z.js";
11
11
  import"./cli-a35w7wzg.js";
12
12
  import"./cli-v5mp7a6q.js";
13
- import"./cli-sdmv4bba.js";
14
- import"./cli-pwwfxdgb.js";
13
+ import"./cli-h4x81x97.js";
14
+ import"./cli-t8be9yeb.js";
15
15
  import {
16
16
  log
17
- } from "./cli-aqh6brew.js";
17
+ } from "./cli-s6djx4ma.js";
18
18
  import {
19
19
  UsageError,
20
20
  parseFormat,
@@ -22,7 +22,7 @@ import {
22
22
  rejectExtraPositionals,
23
23
  rejectUnknownFlags
24
24
  } from "./cli-d8xjns66.js";
25
- import"./cli-kh8v4vvw.js";
25
+ import"./cli-5jzyw06s.js";
26
26
  import {
27
27
  BuildError
28
28
  } from "./cli-46ycxe6r.js";
@@ -8,17 +8,16 @@ import {
8
8
  stampCreator,
9
9
  stripAnnotations,
10
10
  transparentPages
11
- } from "./cli-evg8sbht.js";
11
+ } from "./cli-n2tsxqpn.js";
12
12
  import {
13
13
  blackTextToGray
14
14
  } from "./cli-ht1bcqdd.js";
15
15
  import {
16
+ DEFAULT_PAGE_MARGIN_PT,
16
17
  MARGIN_BOX_IGNORED_PROPERTIES,
17
- extract,
18
18
  getAssetPath,
19
- lastPageMode,
20
- resolvePage
21
- } from "./cli-pz4bn98t.js";
19
+ lastPageMode
20
+ } from "./cli-xsrffqzt.js";
22
21
  import {
23
22
  countLinkAnnotations,
24
23
  getImageResolutions,
@@ -57,11 +56,17 @@ import {
57
56
  TARGET_IDS,
58
57
  addExtension,
59
58
  applyDefaultPdfStrictChecks,
59
+ cssLength,
60
60
  ensureProjectGitignore,
61
+ formatPageSize,
62
+ isPositivePoints,
63
+ judgeRect,
61
64
  loadManifest,
62
65
  loadManifestDoc,
63
66
  loadManifestWithPath,
64
67
  npmRegistryUrl,
68
+ pageBoxes,
69
+ printAreaMeta,
65
70
  publishTargetFor,
66
71
  resolveConfig,
67
72
  resolveConfigForTarget,
@@ -70,7 +75,7 @@ import {
70
75
  uniqueExtensionId,
71
76
  withFetchTimeout,
72
77
  writeManifestDoc
73
- } from "./cli-sdmv4bba.js";
78
+ } from "./cli-h4x81x97.js";
74
79
  import {
75
80
  EXTENSION_MANIFEST_FILENAME,
76
81
  GUTTERPRESS_CSS,
@@ -91,7 +96,7 @@ import {
91
96
  readExtensionMeta,
92
97
  resolveDeclaredStyles,
93
98
  slugify
94
- } from "./cli-pwwfxdgb.js";
99
+ } from "./cli-t8be9yeb.js";
95
100
  import {
96
101
  PACKAGE_META,
97
102
  PACKAGE_VERSION,
@@ -101,7 +106,7 @@ import {
101
106
  log,
102
107
  setLogLevel,
103
108
  warn
104
- } from "./cli-aqh6brew.js";
109
+ } from "./cli-s6djx4ma.js";
105
110
  import {
106
111
  DEBOUNCE,
107
112
  UsageError,
@@ -281,84 +286,6 @@ var check2 = {
281
286
  };
282
287
  registerCheck(check2);
283
288
 
284
- // src/engine/shared/print-area.ts
285
- function isPositivePoints(value) {
286
- return typeof value === "number" && Number.isFinite(value) && value > 0;
287
- }
288
- var round3 = (n) => Math.round(n * 1000) / 1000;
289
- function cssLength(pt) {
290
- const inches = round3(pt / 72);
291
- return Math.abs(inches * 72 - pt) < 0.000001 ? `${inches}in` : `${round3(pt)}pt`;
292
- }
293
- function formatPageSize(page) {
294
- return `${cssLength(page.width)} ${cssLength(page.height)}`;
295
- }
296
- function printAreaMeta(page) {
297
- const area = JSON.stringify({
298
- width: page.width,
299
- height: page.height,
300
- bleed: page.bleed ?? 0,
301
- safe: page.safe ?? 0,
302
- artSafe: page.artSafe,
303
- gutter: page.gutter,
304
- preset: page.preset,
305
- spec: page.spec
306
- });
307
- return `<meta name="gp-print-area" content='${area.replace(/&/g, "&amp;").replace(/'/g, "&#39;")}'>`;
308
- }
309
- function pageBoxes(area, side, scale = 1) {
310
- const w = area.width * scale;
311
- const h = area.height * scale;
312
- const b = Math.max(0, area.bleed) * scale;
313
- const s = Math.max(0, area.safe) * scale;
314
- const a = Math.max(0, area.artSafe) * scale;
315
- const g = Math.max(0, area.gutter) * scale;
316
- const [textLeft, textRight] = side === "verso" ? [s, g] : [g, s];
317
- const [artLeft, artRight] = side === "verso" ? [a, g] : [g, a];
318
- const trim = { x: side === "verso" ? b : 0, y: b, w: Math.max(0, w - b), h: Math.max(0, h - 2 * b) };
319
- return {
320
- sheet: { x: 0, y: 0, w, h },
321
- trim,
322
- safe: {
323
- x: trim.x + textLeft,
324
- y: trim.y + s,
325
- w: Math.max(0, trim.w - textLeft - textRight),
326
- h: Math.max(0, trim.h - 2 * s)
327
- },
328
- safeArt: {
329
- x: trim.x + artLeft,
330
- y: trim.y + a,
331
- w: Math.max(0, trim.w - artLeft - artRight),
332
- h: Math.max(0, trim.h - 2 * a)
333
- },
334
- bleed: b
335
- };
336
- }
337
- var SEVERITY = { inside: 0, unsafe: 1, bleed: 2, "off-page": 3 };
338
- function judgeRect(r, boxes, rule, tol = 0) {
339
- const { sheet, trim } = boxes;
340
- const safe = rule === "art" ? boxes.safeArt : boxes.safe;
341
- const sides = [
342
- ["left", -r.x, -safe.x, -trim.x, -sheet.x],
343
- ["right", r.x + r.w, safe.x + safe.w, trim.x + trim.w, sheet.x + sheet.w],
344
- ["top", -r.y, -safe.y, -trim.y, -sheet.y],
345
- ["bottom", r.y + r.h, safe.y + safe.h, trim.y + trim.h, sheet.y + sheet.h]
346
- ];
347
- let worst = { kind: "inside", gap: 0, need: 0, edge: null };
348
- let beyond = 0;
349
- for (const [edge, ink, limit, trimEdge, sheetEdge] of sides) {
350
- const past = ink - limit;
351
- if (past <= tol || rule === "art" && ink >= sheetEdge - tol)
352
- continue;
353
- const kind = ink > sheetEdge + tol ? "off-page" : ink > trimEdge + tol ? "bleed" : "unsafe";
354
- if (SEVERITY[kind] > SEVERITY[worst.kind] || kind === worst.kind && past > beyond) {
355
- worst = { kind, gap: trimEdge - ink, need: trimEdge - limit, edge };
356
- beyond = past;
357
- }
358
- }
359
- return worst;
360
- }
361
-
362
289
  // src/checks/pdf/safe-margins.ts
363
290
  var TOLERANCE_PT = 0.5;
364
291
  var ABOVE_BASELINE = 0.8;
@@ -1388,6 +1315,7 @@ var ruleRiskyProps = "printsafe/no-risky-print-effects";
1388
1315
  var ruleSyntax = "printsafe/syntax-error";
1389
1316
  var rulePageContainment = "printsafe/page-containment";
1390
1317
  var rulePreviewCannotFollow = "printsafe/preview-cannot-follow";
1318
+ var rulePageSizeInStylesheet = "printsafe/page-size-in-stylesheet";
1391
1319
  function extractUrls(value) {
1392
1320
  const urls = [];
1393
1321
  const re = /url\(\s*(['"]?)(.*?)\1\s*\)/gi;
@@ -1436,6 +1364,12 @@ function isInPageBox(decl) {
1436
1364
  const page = decl.parent;
1437
1365
  return !!page && page.type === "atrule" && page.name.toLowerCase() === "page";
1438
1366
  }
1367
+ function isInBookPageRule(decl) {
1368
+ if (!isInPageBox(decl))
1369
+ return false;
1370
+ const params = decl.parent.params.trim();
1371
+ return params === "" || /^(:[a-z-]+\s*)+$/i.test(params);
1372
+ }
1439
1373
  function isDroppedPageGradient(decl) {
1440
1374
  const prop = decl.prop.toLowerCase();
1441
1375
  if (prop !== "background" && prop !== "background-image")
@@ -1675,6 +1609,15 @@ function checkCssRaw(css, from) {
1675
1609
  root.walkAtRules((at) => reportRemoteUrls(at.params || "", at));
1676
1610
  root.walkDecls((decl) => {
1677
1611
  const prop = decl.prop.toLowerCase();
1612
+ if (prop === "size" && isInBookPageRule(decl)) {
1613
+ warnings.push({
1614
+ rule: rulePageSizeInStylesheet,
1615
+ severity: "warning",
1616
+ message: `"size" in a stylesheet's @page rule is ignored: the page size comes from the manifest (preset:, or page: width and height — Setup > Details in the app), which is written after every stylesheet. Remove this declaration; to print at another size, change the manifest.`,
1617
+ ...nodeLoc(decl)
1618
+ });
1619
+ return;
1620
+ }
1678
1621
  if (isInertValue(prop, decl.value))
1679
1622
  return;
1680
1623
  if (marginBoxIgnoredProperties.has(prop) && isInPageMarginBox(decl)) {
@@ -3995,16 +3938,25 @@ function canonicalChapterId(p) {
3995
3938
  }
3996
3939
 
3997
3940
  // src/lib/markdown/assemble.ts
3998
- function defaultPageSizeCss(css, page) {
3941
+ function pageGeometryCss(page) {
3999
3942
  if (!page || !isPositivePoints(page.width) || !isPositivePoints(page.height))
4000
3943
  return null;
4001
- try {
4002
- if (resolvePage(extract(css)).decls.size !== undefined)
4003
- return null;
4004
- } catch {
3944
+ const size2 = `size: ${formatPageSize(page)};`;
3945
+ const m = page.margin;
3946
+ if (!m)
3947
+ return `@page { ${size2} }`;
3948
+ const [top, bottom, inside, outside] = [m.top, m.bottom, m.inside, m.outside].map(cssLength);
3949
+ const recto = `margin: ${top} ${outside} ${bottom} ${inside};`;
3950
+ const verso = `margin: ${top} ${inside} ${bottom} ${outside};`;
3951
+ return [`@page { ${size2} ${recto} }`, `@page :left { ${verso} }`, `@page :right { ${recto} }`].join(`
3952
+ `);
3953
+ }
3954
+ function defaultPageMarginCss(page) {
3955
+ if (!page || page.margin)
4005
3956
  return null;
4006
- }
4007
- return `@page { size: ${formatPageSize(page)}; }`;
3957
+ return `@layer gp.vocab {
3958
+ @page { margin: ${cssLength(DEFAULT_PAGE_MARGIN_PT)}; }
3959
+ }`;
4008
3960
  }
4009
3961
  async function assembleBookHtml(opts) {
4010
3962
  const title = opts.title ?? "Document";
@@ -4044,8 +3996,8 @@ async function assembleBookHtml(opts) {
4044
3996
  imageRefs.add(ref);
4045
3997
  opts.onImageRefs([...imageRefs]);
4046
3998
  }
4047
- const pageSize = defaultPageSizeCss(`${pluginCss}
4048
- ${projectCss}`, opts.printArea);
3999
+ const pageGeometry = pageGeometryCss(opts.printArea);
4000
+ const defaultMargin = defaultPageMarginCss(opts.printArea);
4049
4001
  const inlineCss = [
4050
4002
  "@layer gp.marker, gp.vocab;",
4051
4003
  `/* gutterpress markers */
@@ -4057,14 +4009,16 @@ ${TWO_VERSIONS_CSS.trim()}
4057
4009
  @layer gp.vocab {
4058
4010
  ${GUTTERPRESS_CSS.trim()}
4059
4011
  }`,
4060
- pageSize ? `/* page size (manifest) */
4061
- ${pageSize}` : null,
4012
+ defaultMargin ? `/* page margins (default) */
4013
+ ${defaultMargin}` : null,
4062
4014
  pluginCss ? `/* extension css */
4063
4015
  ${pluginCss.trim()}` : null,
4064
4016
  `/* column alignment */
4065
4017
  ${TABLE_ALIGN_CSS.trim()}`,
4066
4018
  projectCss ? `/* project css */
4067
- ${projectCss.trim()}` : null
4019
+ ${projectCss.trim()}` : null,
4020
+ pageGeometry ? `/* page geometry (manifest) */
4021
+ ${pageGeometry}` : null
4068
4022
  ].filter(Boolean).join(`
4069
4023
 
4070
4024
  `);
@@ -5206,7 +5160,7 @@ class PdfOutput {
5206
5160
  const rawPdf = pdfxMode ? path7.join(stage, "raw.pdf") : path7.resolve(pdfFile);
5207
5161
  await fsp2.mkdir(path7.dirname(path7.resolve(pdfFile)), { recursive: true });
5208
5162
  log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
5209
- const { buildNativePdf } = await import("./engine-mc5br8g8.js");
5163
+ const { buildNativePdf } = await import("./engine-m4y10shc.js");
5210
5164
  const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
5211
5165
  title: config.title,
5212
5166
  author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
@@ -6501,17 +6455,30 @@ import { constants as FS, existsSync as existsSync7 } from "node:fs";
6501
6455
  import path12 from "node:path";
6502
6456
 
6503
6457
  // src/lib/page-size.ts
6504
- import postcss5 from "postcss";
6505
- import { isMap, Scalar } from "yaml";
6458
+ import { isMap } from "yaml";
6506
6459
  function writePageBounds(doc, page) {
6507
6460
  const tolerance = page.tolerance ?? numberAt(doc, ["page", "tolerance"]);
6508
- if (!isMap(doc.get("page", true)))
6509
- doc.set("page", doc.createNode({}));
6461
+ ensurePageMap(doc);
6510
6462
  doc.setIn(["page", "width"], page.width);
6511
6463
  doc.setIn(["page", "height"], page.height);
6512
6464
  if (tolerance !== undefined)
6513
6465
  doc.setIn(["page", "tolerance"], tolerance);
6514
6466
  }
6467
+ function deletePageBounds(doc) {
6468
+ const block = doc.get("page", true);
6469
+ if (!isMap(block)) {
6470
+ doc.delete("page");
6471
+ return;
6472
+ }
6473
+ for (const key of ["width", "height", "tolerance"])
6474
+ block.delete(key);
6475
+ if (block.items.length === 0)
6476
+ doc.delete("page");
6477
+ }
6478
+ function ensurePageMap(doc) {
6479
+ if (!isMap(doc.get("page", true)))
6480
+ doc.set("page", doc.createNode({}));
6481
+ }
6515
6482
  function numberAt(doc, keyPath) {
6516
6483
  const v = doc.getIn(keyPath);
6517
6484
  return isPositivePoints(v) ? v : undefined;
@@ -6520,13 +6487,15 @@ function numberAt(doc, keyPath) {
6520
6487
  // src/lib/project-scaffold.ts
6521
6488
  function starterOverridesCss() {
6522
6489
  return `/**
6523
- * Your book's own styles.
6490
+ * Your book's own styles. Rules here win over your look's.
6524
6491
  *
6525
- * This file loads AFTER every extension, so any rule you add here overrides
6526
- * a look's defaults. A new book has no look until its template or you add
6527
- * one:
6528
- * gutterpress ext add academic <book> (a built-in look)
6529
- * gutterpress ext add <package> <book> (a look from npm)
6492
+ * In the app you rarely need this file: Setup > Looks & features adds a
6493
+ * look, Setup > Design changes its fonts, colors and sizes (those changes
6494
+ * are saved here as :root custom properties), and Setup > Details sets the
6495
+ * page size and margins (in the manifest).
6496
+ *
6497
+ * To change the look from the command line: gutterpress ext remove <old>
6498
+ * <book>, then gutterpress ext add <look> <book>.
6530
6499
  */
6531
6500
  `;
6532
6501
  }
@@ -6649,6 +6618,8 @@ async function scaffoldProject(options) {
6649
6618
  if (preset) {
6650
6619
  doc.set("preset", preset);
6651
6620
  doc.set("targets", doc.createNode(targets ?? []));
6621
+ if (preset !== "custom")
6622
+ deletePageBounds(doc);
6652
6623
  }
6653
6624
  if (options.customPage)
6654
6625
  writePageBounds(doc, options.customPage);
@@ -9020,7 +8991,7 @@ async function resolvePublishProvider(id, book) {
9020
8991
  const ext = await bookExtensions(book);
9021
8992
  const npmEntry = ext.extensions.some((c) => !c.path && c.name === id);
9022
8993
  if (npmEntry) {
9023
- const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-g8jnmmzq.js");
8994
+ const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-tmxtzkm0.js");
9024
8995
  await restoreForCommand2(book.projectDir, { manifestPath: book.manifestPath, failFast: true });
9025
8996
  }
9026
8997
  const publishers = await discover(ext);
@@ -9058,7 +9029,7 @@ function infoFor(p) {
9058
9029
  }
9059
9030
  function pluginProvider(p) {
9060
9031
  let loading;
9061
- const load = () => loading ??= import("./plugins-1sxe0dkz.js").then((m) => m.loadPublishFunction(p));
9032
+ const load = () => loading ??= import("./plugins-4vaf27n9.js").then((m) => m.loadPublishFunction(p));
9062
9033
  return {
9063
9034
  info: infoFor(p),
9064
9035
  async authenticate() {
@@ -9332,10 +9303,10 @@ async function disconnectPublishCredential(key, deps, options = {}) {
9332
9303
  }
9333
9304
  }
9334
9305
  // src/lib/manifest-config.ts
9335
- import { isSeq as isSeq2, isMap as isMap3, YAMLSeq, Scalar as Scalar2 } from "yaml";
9306
+ import { isSeq as isSeq2, isMap as isMap3, YAMLSeq, Scalar } from "yaml";
9336
9307
  // src/lib/version-changes.ts
9337
9308
  import git3 from "isomorphic-git";
9338
- import postcss6 from "postcss";
9309
+ import postcss5 from "postcss";
9339
9310
 
9340
9311
  // src/lib/remote-auth/transport.ts
9341
9312
  import git2 from "isomorphic-git";
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "gutterpress",
4
- version: "0.11.23-alpha.2",
4
+ version: "0.11.23-alpha.3",
5
5
  description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
6
6
  author: "itlackey",
7
7
  license: "MPL-2.0",