@bendyline/squisq 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +24 -0
  3. package/dist/{ContentContainer-BXUlIf18.d.ts → ContentContainer-B2w9sUoL.d.ts} +15 -0
  4. package/dist/{Doc-ylqWKDc_.d.ts → Doc-BubIpWsp.d.ts} +160 -3
  5. package/dist/{ImageEditDoc-D828IXJ1.d.ts → ImageEditDoc-CGxk5CHc.d.ts} +1 -1
  6. package/dist/{annotationCoercion-Dr_DY9Hx.d.ts → annotationCoercion-PtRQhk5V.d.ts} +1 -1
  7. package/dist/chunk-2L55443L.js +0 -0
  8. package/dist/chunk-2ZWIXGAC.js +214 -0
  9. package/dist/{chunk-2PWOO4ZE.js → chunk-32R2RZAO.js} +72 -3
  10. package/dist/chunk-3IGPAPQ7.js +645 -0
  11. package/dist/{chunk-QE7TWGVT.js → chunk-4VOD55SX.js} +0 -1
  12. package/dist/{chunk-3E5F2XMR.js → chunk-67L6WRJN.js} +0 -1
  13. package/dist/{chunk-5DKBFXPY.js → chunk-6ECMNUIP.js} +26 -18
  14. package/dist/{chunk-X6DUONGT.js → chunk-7ARJZYQY.js} +280 -128
  15. package/dist/{chunk-DBS6RIFL.js → chunk-7N4G32LG.js} +0 -1
  16. package/dist/{chunk-JOQYPRDZ.js → chunk-7YEZFHLS.js} +10 -8
  17. package/dist/{chunk-2UQOHYE2.js → chunk-7ZAAICW4.js} +0 -1
  18. package/dist/{chunk-66QO7XFB.js → chunk-ACZOVWX3.js} +117 -7
  19. package/dist/{chunk-5J4HKRJF.js → chunk-BAOV476U.js} +0 -1
  20. package/dist/chunk-BCCXTMN5.js +699 -0
  21. package/dist/{chunk-W4O2TX5I.js → chunk-C33GTPUZ.js} +579 -4
  22. package/dist/{chunk-MMPBOUK7.js → chunk-CB45YGAM.js} +7 -2
  23. package/dist/{chunk-CY2R2VPR.js → chunk-DYPMOPIW.js} +18 -2
  24. package/dist/{chunk-VR7UPJ7C.js → chunk-FCG3BIZN.js} +12 -1
  25. package/dist/{chunk-5UYI3RJB.js → chunk-FDYDYL77.js} +54 -40
  26. package/dist/{chunk-TFJVXUHH.js → chunk-I2O6W7DX.js} +1513 -79
  27. package/dist/{chunk-Q7LROV2H.js → chunk-NKNMGIIN.js} +0 -1
  28. package/dist/chunk-OPO5K4DZ.js +241 -0
  29. package/dist/{chunk-TUWMK62B.js → chunk-PUS54YU6.js} +45 -2
  30. package/dist/chunk-QKPXHDLR.js +0 -0
  31. package/dist/{chunk-GZY66SDN.js → chunk-R3KTTOMS.js} +0 -1
  32. package/dist/{chunk-PXLVXTLW.js → chunk-RS5AP3J4.js} +72 -15
  33. package/dist/chunk-WV5ARNDA.js +0 -0
  34. package/dist/{chunk-4X3JQXNM.js → chunk-XOFT65EX.js} +1 -2
  35. package/dist/{chunk-FVTQSNR7.js → chunk-XRW6P7IF.js} +13 -5
  36. package/dist/chunk-XWNNA3KE.js +0 -0
  37. package/dist/chunk-YZNGMV3G.js +0 -0
  38. package/dist/{chunk-R2YZTCLO.js → chunk-ZQKZSJAX.js} +1 -2
  39. package/dist/doc/index.d.ts +166 -12
  40. package/dist/doc/index.js +36 -17
  41. package/dist/generate/index.d.ts +2 -2
  42. package/dist/generate/index.js +2 -3
  43. package/dist/icons/index.js +3 -4
  44. package/dist/icons/inlineIconMarker.js +1 -2
  45. package/dist/imageEdit/index.d.ts +48 -17
  46. package/dist/imageEdit/index.js +3 -4
  47. package/dist/index.d.ts +13 -12
  48. package/dist/index.js +118 -33
  49. package/dist/jsonForm/index.d.ts +10 -3
  50. package/dist/jsonForm/index.js +8 -7
  51. package/dist/markdown/index.d.ts +75 -11
  52. package/dist/markdown/index.js +32 -7
  53. package/dist/materializePageSection-wSLA2A1g.d.ts +223 -0
  54. package/dist/narration/index.d.ts +16 -3
  55. package/dist/narration/index.js +13 -14
  56. package/dist/random/index.d.ts +11 -2
  57. package/dist/random/index.js +2 -3
  58. package/dist/recommend/index.d.ts +1 -1
  59. package/dist/recommend/index.js +3 -4
  60. package/dist/schemas/index.d.ts +31 -6
  61. package/dist/schemas/index.js +43 -6
  62. package/dist/spatial/index.d.ts +2 -1
  63. package/dist/spatial/index.js +1 -2
  64. package/dist/storage/index.d.ts +4 -2
  65. package/dist/storage/index.js +1 -2
  66. package/dist/{themeLibrary-RjVgLpUi.d.ts → themeLibrary-DU9mUmVl.d.ts} +1 -1
  67. package/dist/timing/index.js +3 -4
  68. package/dist/transform/index.d.ts +9 -10
  69. package/dist/transform/index.js +6 -7
  70. package/dist/{types-C4kiRn_k.d.ts → types-8QjefM9J.d.ts} +38 -2
  71. package/dist/{types-BwMPl2CB.d.ts → types-CUNc9biN.d.ts} +24 -1
  72. package/dist/versions/index.d.ts +14 -11
  73. package/dist/versions/index.js +2 -3
  74. package/package.json +4 -2
  75. package/dist/chunk-2PWOO4ZE.js.map +0 -1
  76. package/dist/chunk-2UQOHYE2.js.map +0 -1
  77. package/dist/chunk-3E5F2XMR.js.map +0 -1
  78. package/dist/chunk-4X3JQXNM.js.map +0 -1
  79. package/dist/chunk-5DKBFXPY.js.map +0 -1
  80. package/dist/chunk-5J4HKRJF.js.map +0 -1
  81. package/dist/chunk-5UYI3RJB.js.map +0 -1
  82. package/dist/chunk-66QO7XFB.js.map +0 -1
  83. package/dist/chunk-AMIR72JP.js +0 -380
  84. package/dist/chunk-AMIR72JP.js.map +0 -1
  85. package/dist/chunk-CY2R2VPR.js.map +0 -1
  86. package/dist/chunk-DBS6RIFL.js.map +0 -1
  87. package/dist/chunk-DNJKBAI7.js +0 -1
  88. package/dist/chunk-DNJKBAI7.js.map +0 -1
  89. package/dist/chunk-ET53IIEP.js +0 -1
  90. package/dist/chunk-ET53IIEP.js.map +0 -1
  91. package/dist/chunk-FVJUUTEM.js +0 -74
  92. package/dist/chunk-FVJUUTEM.js.map +0 -1
  93. package/dist/chunk-FVTQSNR7.js.map +0 -1
  94. package/dist/chunk-GZY66SDN.js.map +0 -1
  95. package/dist/chunk-JOQYPRDZ.js.map +0 -1
  96. package/dist/chunk-MMPBOUK7.js.map +0 -1
  97. package/dist/chunk-PGGGKYWG.js +0 -1
  98. package/dist/chunk-PGGGKYWG.js.map +0 -1
  99. package/dist/chunk-PXLVXTLW.js.map +0 -1
  100. package/dist/chunk-Q7LROV2H.js.map +0 -1
  101. package/dist/chunk-QE7TWGVT.js.map +0 -1
  102. package/dist/chunk-R2GC6RLD.js +0 -344
  103. package/dist/chunk-R2GC6RLD.js.map +0 -1
  104. package/dist/chunk-R2YZTCLO.js.map +0 -1
  105. package/dist/chunk-S7A5D7ZJ.js +0 -174
  106. package/dist/chunk-S7A5D7ZJ.js.map +0 -1
  107. package/dist/chunk-TFJVXUHH.js.map +0 -1
  108. package/dist/chunk-TUWMK62B.js.map +0 -1
  109. package/dist/chunk-V543AI2F.js +0 -1
  110. package/dist/chunk-V543AI2F.js.map +0 -1
  111. package/dist/chunk-VR7UPJ7C.js.map +0 -1
  112. package/dist/chunk-W4O2TX5I.js.map +0 -1
  113. package/dist/chunk-X6DUONGT.js.map +0 -1
  114. package/dist/chunk-ZLQKNOZQ.js +0 -1
  115. package/dist/chunk-ZLQKNOZQ.js.map +0 -1
  116. package/dist/doc/index.js.map +0 -1
  117. package/dist/generate/index.js.map +0 -1
  118. package/dist/icons/index.js.map +0 -1
  119. package/dist/icons/inlineIconMarker.js.map +0 -1
  120. package/dist/imageEdit/index.js.map +0 -1
  121. package/dist/index.js.map +0 -1
  122. package/dist/jsonForm/index.js.map +0 -1
  123. package/dist/markdown/index.js.map +0 -1
  124. package/dist/narration/index.js.map +0 -1
  125. package/dist/random/index.js.map +0 -1
  126. package/dist/recommend/index.js.map +0 -1
  127. package/dist/schemas/index.js.map +0 -1
  128. package/dist/spatial/index.js.map +0 -1
  129. package/dist/storage/index.js.map +0 -1
  130. package/dist/timing/index.js.map +0 -1
  131. package/dist/transform/index.js.map +0 -1
  132. package/dist/versions/index.js.map +0 -1
  133. package/src/__tests__/animationUtils.test.ts +0 -117
  134. package/src/__tests__/annotationCoercion.test.ts +0 -243
  135. package/src/__tests__/applyNarrationTiming.test.ts +0 -190
  136. package/src/__tests__/applyRenderStyle.test.ts +0 -146
  137. package/src/__tests__/asciiDiagramBattle.test.ts +0 -246
  138. package/src/__tests__/asciiDiagramDetect.test.ts +0 -162
  139. package/src/__tests__/asciiDiagramMapping.test.ts +0 -38
  140. package/src/__tests__/asciiDiagramParse.test.ts +0 -233
  141. package/src/__tests__/asciiDiagramPipeline.test.ts +0 -273
  142. package/src/__tests__/asciiDiagramRender.test.ts +0 -162
  143. package/src/__tests__/asciiDiagramRepair.test.ts +0 -84
  144. package/src/__tests__/asciiTimelineDetect.test.ts +0 -157
  145. package/src/__tests__/asciiTimelineParse.test.ts +0 -205
  146. package/src/__tests__/asciiTimelinePipeline.test.ts +0 -349
  147. package/src/__tests__/asciiTimelineRender.test.ts +0 -376
  148. package/src/__tests__/atmosphereLayers.test.ts +0 -108
  149. package/src/__tests__/attrTokens.test.ts +0 -167
  150. package/src/__tests__/colorUtils.test.ts +0 -112
  151. package/src/__tests__/contentContainer.test.ts +0 -325
  152. package/src/__tests__/contentExtractor.test.ts +0 -243
  153. package/src/__tests__/coverBlock.test.ts +0 -310
  154. package/src/__tests__/customTemplateSample.test.ts +0 -144
  155. package/src/__tests__/customTemplatesFrontmatter.test.ts +0 -221
  156. package/src/__tests__/customThemesFrontmatter.test.ts +0 -146
  157. package/src/__tests__/dataTable.test.ts +0 -145
  158. package/src/__tests__/diagramBlock.test.ts +0 -122
  159. package/src/__tests__/diagramLayout.test.ts +0 -134
  160. package/src/__tests__/diagramText.test.ts +0 -26
  161. package/src/__tests__/docToMarkdownMedia.test.ts +0 -83
  162. package/src/__tests__/drawing.test.ts +0 -109
  163. package/src/__tests__/drawingBlock.test.ts +0 -124
  164. package/src/__tests__/drawingLayout.test.ts +0 -171
  165. package/src/__tests__/fixtures/asciiDiagramBattle.ts +0 -512
  166. package/src/__tests__/fixtures/asciiDiagrams.ts +0 -287
  167. package/src/__tests__/fixtures/asciiTimelines.ts +0 -35
  168. package/src/__tests__/fixtures/treeviewFixtures.ts +0 -243
  169. package/src/__tests__/geohash.test.ts +0 -110
  170. package/src/__tests__/getLayers.test.ts +0 -243
  171. package/src/__tests__/getLayersFallback.test.ts +0 -103
  172. package/src/__tests__/haversine.test.ts +0 -63
  173. package/src/__tests__/iconResolve.test.ts +0 -122
  174. package/src/__tests__/imageEditExportSvg.test.ts +0 -70
  175. package/src/__tests__/imageEditState.test.ts +0 -74
  176. package/src/__tests__/imageEditVersions.test.ts +0 -243
  177. package/src/__tests__/inferDocumentTitle.test.ts +0 -50
  178. package/src/__tests__/inlineIconMarker.test.ts +0 -36
  179. package/src/__tests__/inputDescriptors.test.ts +0 -162
  180. package/src/__tests__/jsonForm.chooseControl.test.ts +0 -86
  181. package/src/__tests__/jsonForm.evaluateWhen.test.ts +0 -59
  182. package/src/__tests__/jsonForm.inferSchema.test.ts +0 -25
  183. package/src/__tests__/jsonForm.pointer.test.ts +0 -149
  184. package/src/__tests__/jsonForm.tokens.test.ts +0 -84
  185. package/src/__tests__/layoutBlock.test.ts +0 -83
  186. package/src/__tests__/layoutLayout.test.ts +0 -169
  187. package/src/__tests__/localForageAdapter.test.ts +0 -155
  188. package/src/__tests__/majorApiTypes.test.ts +0 -18
  189. package/src/__tests__/markdown.test.ts +0 -1009
  190. package/src/__tests__/markdownIcons.test.ts +0 -104
  191. package/src/__tests__/markdownSanitize.test.ts +0 -81
  192. package/src/__tests__/markdownToDoc.test.ts +0 -957
  193. package/src/__tests__/matchFontFamily.test.ts +0 -114
  194. package/src/__tests__/materializeBlockLayers.test.ts +0 -135
  195. package/src/__tests__/materializeTestUtils.ts +0 -17
  196. package/src/__tests__/mediaAnnotations.test.ts +0 -91
  197. package/src/__tests__/mediaSchedule.test.ts +0 -118
  198. package/src/__tests__/narrationAlign.test.ts +0 -150
  199. package/src/__tests__/narrationFeatures.test.ts +0 -71
  200. package/src/__tests__/narrationNuclei.test.ts +0 -45
  201. package/src/__tests__/narrationPacing.test.ts +0 -189
  202. package/src/__tests__/narrationScript.test.ts +0 -149
  203. package/src/__tests__/narrationSessionRepro.test.ts +0 -62
  204. package/src/__tests__/narrationSidecar.test.ts +0 -88
  205. package/src/__tests__/narrationSyllables.test.ts +0 -65
  206. package/src/__tests__/narrationTestSignals.ts +0 -167
  207. package/src/__tests__/narrationVad.test.ts +0 -66
  208. package/src/__tests__/pandocAttrParse.test.ts +0 -187
  209. package/src/__tests__/recommendTemplates.test.ts +0 -183
  210. package/src/__tests__/resolveDocTheme.test.ts +0 -69
  211. package/src/__tests__/rootExports.test.ts +0 -61
  212. package/src/__tests__/scopedContentContainer.test.ts +0 -109
  213. package/src/__tests__/seededRandom.test.ts +0 -142
  214. package/src/__tests__/shapeGeometry.test.ts +0 -138
  215. package/src/__tests__/shapeVocabulary.test.ts +0 -133
  216. package/src/__tests__/storage.test.ts +0 -60
  217. package/src/__tests__/structuredData.test.ts +0 -249
  218. package/src/__tests__/surface.test.ts +0 -68
  219. package/src/__tests__/templateAnnotationParse.test.ts +0 -160
  220. package/src/__tests__/templateInputs.test.ts +0 -69
  221. package/src/__tests__/templateMetadata.test.ts +0 -32
  222. package/src/__tests__/templates.test.ts +0 -710
  223. package/src/__tests__/themeCompile.test.ts +0 -225
  224. package/src/__tests__/themeValidator.test.ts +0 -131
  225. package/src/__tests__/timing.test.ts +0 -167
  226. package/src/__tests__/transformProvenance.test.ts +0 -160
  227. package/src/__tests__/transformV2.test.ts +0 -163
  228. package/src/__tests__/transitionNormalize.test.ts +0 -61
  229. package/src/__tests__/treeviewBattle.test.ts +0 -76
  230. package/src/__tests__/treeviewDetect.test.ts +0 -168
  231. package/src/__tests__/treeviewParse.test.ts +0 -118
  232. package/src/__tests__/treeviewPipeline.test.ts +0 -183
  233. package/src/__tests__/treeviewRender.test.ts +0 -91
  234. package/src/__tests__/validateDoc.test.ts +0 -260
  235. package/src/__tests__/versions.test.ts +0 -459
  236. package/src/doc/annotationBlocks.ts +0 -117
  237. package/src/doc/applyNarrationTiming.ts +0 -244
  238. package/src/doc/asciiDiagram/chars.ts +0 -210
  239. package/src/doc/asciiDiagram/detect.ts +0 -175
  240. package/src/doc/asciiDiagram/index.ts +0 -38
  241. package/src/doc/asciiDiagram/mapping.ts +0 -225
  242. package/src/doc/asciiDiagram/parse.ts +0 -1095
  243. package/src/doc/asciiDiagram/render.ts +0 -963
  244. package/src/doc/asciiDiagram/repair.ts +0 -400
  245. package/src/doc/asciiDiagram/types.ts +0 -65
  246. package/src/doc/asciiTimeline/detect.ts +0 -138
  247. package/src/doc/asciiTimeline/index.ts +0 -26
  248. package/src/doc/asciiTimeline/mapping.ts +0 -43
  249. package/src/doc/asciiTimeline/parse.ts +0 -870
  250. package/src/doc/asciiTimeline/render.ts +0 -427
  251. package/src/doc/asciiTimeline/types.ts +0 -73
  252. package/src/doc/asciiTimeline/wrappedFlow.ts +0 -427
  253. package/src/doc/audioMapping.ts +0 -442
  254. package/src/doc/customTemplatesFrontmatter.ts +0 -273
  255. package/src/doc/customThemesFrontmatter.ts +0 -95
  256. package/src/doc/docToMarkdown.ts +0 -284
  257. package/src/doc/index.ts +0 -127
  258. package/src/doc/markdownToDoc.ts +0 -1054
  259. package/src/doc/materializeBlockLayers.ts +0 -304
  260. package/src/doc/mediaAnnotations.ts +0 -120
  261. package/src/doc/resolveDocTheme.ts +0 -56
  262. package/src/doc/standaloneAnnotation.ts +0 -58
  263. package/src/doc/structuredData.ts +0 -301
  264. package/src/doc/templateInputs.ts +0 -423
  265. package/src/doc/templates/__tests__/customTemplate.test.ts +0 -170
  266. package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +0 -124
  267. package/src/doc/templates/__tests__/listBlock.test.ts +0 -64
  268. package/src/doc/templates/accentImage.ts +0 -362
  269. package/src/doc/templates/captionUtils.ts +0 -56
  270. package/src/doc/templates/comparisonBar.ts +0 -173
  271. package/src/doc/templates/coverBlock.ts +0 -255
  272. package/src/doc/templates/customTemplate.ts +0 -51
  273. package/src/doc/templates/dataTable.ts +0 -102
  274. package/src/doc/templates/dateEvent.ts +0 -147
  275. package/src/doc/templates/definitionCard.ts +0 -140
  276. package/src/doc/templates/diagramBlock.ts +0 -403
  277. package/src/doc/templates/diagramLayout.ts +0 -159
  278. package/src/doc/templates/drawingBlock.ts +0 -325
  279. package/src/doc/templates/drawingLayout.ts +0 -539
  280. package/src/doc/templates/factCard.ts +0 -146
  281. package/src/doc/templates/fallbackBlock.ts +0 -123
  282. package/src/doc/templates/featureBlock.ts +0 -209
  283. package/src/doc/templates/fullBleedQuote.ts +0 -83
  284. package/src/doc/templates/imageWithCaption.ts +0 -186
  285. package/src/doc/templates/index.ts +0 -642
  286. package/src/doc/templates/inputDescriptors.ts +0 -451
  287. package/src/doc/templates/layoutBlock.ts +0 -43
  288. package/src/doc/templates/layoutLayout.ts +0 -243
  289. package/src/doc/templates/listBlock.ts +0 -207
  290. package/src/doc/templates/mapBlock.ts +0 -138
  291. package/src/doc/templates/metadata.ts +0 -130
  292. package/src/doc/templates/persistentLayers.ts +0 -526
  293. package/src/doc/templates/photoGrid.ts +0 -190
  294. package/src/doc/templates/pullQuote.ts +0 -141
  295. package/src/doc/templates/quoteBlock.ts +0 -141
  296. package/src/doc/templates/registry.ts +0 -88
  297. package/src/doc/templates/sectionHeader.ts +0 -120
  298. package/src/doc/templates/statHighlight.ts +0 -146
  299. package/src/doc/templates/templateNames.ts +0 -22
  300. package/src/doc/templates/timelineBlock.ts +0 -613
  301. package/src/doc/templates/titleBlock.ts +0 -150
  302. package/src/doc/templates/tokens/__tests__/resolveTokens.test.ts +0 -487
  303. package/src/doc/templates/tokens/resolveTokens.ts +0 -453
  304. package/src/doc/templates/treeBlock.ts +0 -131
  305. package/src/doc/templates/twoColumn.ts +0 -263
  306. package/src/doc/templates/videoPullQuote.ts +0 -142
  307. package/src/doc/templates/videoWithCaption.ts +0 -135
  308. package/src/doc/treeview/chars.ts +0 -72
  309. package/src/doc/treeview/detect.ts +0 -145
  310. package/src/doc/treeview/index.ts +0 -30
  311. package/src/doc/treeview/mapping.ts +0 -95
  312. package/src/doc/treeview/parse.ts +0 -201
  313. package/src/doc/treeview/render.ts +0 -41
  314. package/src/doc/treeview/types.ts +0 -43
  315. package/src/doc/utils/animationUtils.ts +0 -399
  316. package/src/doc/utils/applyRenderStyle.ts +0 -106
  317. package/src/doc/utils/diagramText.ts +0 -78
  318. package/src/doc/utils/imageTreatment.ts +0 -70
  319. package/src/doc/utils/nearest.ts +0 -59
  320. package/src/doc/utils/shapeGeometry.ts +0 -614
  321. package/src/doc/utils/themeUtils.ts +0 -243
  322. package/src/doc/validate.ts +0 -575
  323. package/src/generate/contentExtractor.ts +0 -921
  324. package/src/generate/index.ts +0 -18
  325. package/src/generate/templateMapper.ts +0 -177
  326. package/src/icons/iconData.ts +0 -31
  327. package/src/icons/index.ts +0 -26
  328. package/src/icons/inlineIconMarker.ts +0 -73
  329. package/src/icons/resolve.ts +0 -139
  330. package/src/imageEdit/ImageEditVersionManager.ts +0 -73
  331. package/src/imageEdit/export.ts +0 -410
  332. package/src/imageEdit/index.ts +0 -72
  333. package/src/imageEdit/persistence.ts +0 -113
  334. package/src/imageEdit/state.ts +0 -112
  335. package/src/imageEdit/versionPaths.ts +0 -44
  336. package/src/imageEdit/versions.ts +0 -152
  337. package/src/index.ts +0 -15
  338. package/src/internal/immutable.ts +0 -58
  339. package/src/jsonForm/chooseControl.ts +0 -88
  340. package/src/jsonForm/evaluateWhen.ts +0 -59
  341. package/src/jsonForm/index.ts +0 -32
  342. package/src/jsonForm/inferSchema.ts +0 -25
  343. package/src/jsonForm/pointer.ts +0 -154
  344. package/src/jsonForm/tokens.ts +0 -78
  345. package/src/jsonForm/types.ts +0 -167
  346. package/src/markdown/annotationCoercion.ts +0 -295
  347. package/src/markdown/attrTokens.ts +0 -243
  348. package/src/markdown/convert.ts +0 -1353
  349. package/src/markdown/htmlParse.ts +0 -212
  350. package/src/markdown/index.ts +0 -152
  351. package/src/markdown/parse.ts +0 -103
  352. package/src/markdown/sanitize.ts +0 -318
  353. package/src/markdown/stringify.ts +0 -207
  354. package/src/markdown/types.ts +0 -710
  355. package/src/markdown/utils.ts +0 -459
  356. package/src/narration/align.ts +0 -514
  357. package/src/narration/features.ts +0 -231
  358. package/src/narration/index.ts +0 -86
  359. package/src/narration/nuclei.ts +0 -118
  360. package/src/narration/pacing.ts +0 -211
  361. package/src/narration/script.ts +0 -239
  362. package/src/narration/session.ts +0 -100
  363. package/src/narration/sidecar.ts +0 -187
  364. package/src/narration/syllables.ts +0 -85
  365. package/src/narration/trace.ts +0 -50
  366. package/src/narration/types.ts +0 -299
  367. package/src/narration/vad.ts +0 -131
  368. package/src/ngeohash.d.ts +0 -11
  369. package/src/random/SeededRandom.ts +0 -127
  370. package/src/random/index.ts +0 -1
  371. package/src/recommend/index.ts +0 -16
  372. package/src/recommend/numberHighlight.ts +0 -25
  373. package/src/recommend/templates.ts +0 -393
  374. package/src/schemas/BlockTemplates.ts +0 -1046
  375. package/src/schemas/CustomTemplates.ts +0 -126
  376. package/src/schemas/Doc.ts +0 -1052
  377. package/src/schemas/ImageEditDoc.ts +0 -102
  378. package/src/schemas/LayoutStrategy.ts +0 -178
  379. package/src/schemas/Media.ts +0 -179
  380. package/src/schemas/MediaProvider.ts +0 -70
  381. package/src/schemas/Theme.ts +0 -406
  382. package/src/schemas/Transitions.ts +0 -224
  383. package/src/schemas/Types.ts +0 -15
  384. package/src/schemas/Viewport.ts +0 -91
  385. package/src/schemas/colorUtils.ts +0 -219
  386. package/src/schemas/fontStacks.ts +0 -339
  387. package/src/schemas/index.ts +0 -29
  388. package/src/schemas/themeCompile.ts +0 -237
  389. package/src/schemas/themeConstants.ts +0 -2
  390. package/src/schemas/themeLibrary.ts +0 -60
  391. package/src/schemas/themeValidator.ts +0 -426
  392. package/src/schemas/themes/bold.json +0 -48
  393. package/src/schemas/themes/cinematic.json +0 -111
  394. package/src/schemas/themes/documentary.json +0 -96
  395. package/src/schemas/themes/gezellig.json +0 -93
  396. package/src/schemas/themes/index.ts +0 -53
  397. package/src/schemas/themes/magazine.json +0 -89
  398. package/src/schemas/themes/minimalist.json +0 -45
  399. package/src/schemas/themes/morning-light.json +0 -85
  400. package/src/schemas/themes/standard-dark.json +0 -85
  401. package/src/schemas/themes/standard.json +0 -74
  402. package/src/schemas/themes/tech-dark.json +0 -101
  403. package/src/schemas/themes/warm-earth.json +0 -50
  404. package/src/spatial/Geohash.ts +0 -196
  405. package/src/spatial/Haversine.ts +0 -59
  406. package/src/spatial/index.ts +0 -2
  407. package/src/storage/ContentContainer.ts +0 -220
  408. package/src/storage/LocalForageAdapter.ts +0 -103
  409. package/src/storage/LocalStorageAdapter.ts +0 -57
  410. package/src/storage/MediaProviderFromContainer.ts +0 -92
  411. package/src/storage/MemoryStorageAdapter.ts +0 -37
  412. package/src/storage/ScopedContentContainer.ts +0 -143
  413. package/src/storage/Storage.ts +0 -28
  414. package/src/storage/index.ts +0 -9
  415. package/src/timing/index.ts +0 -17
  416. package/src/timing/narrationTiming.ts +0 -220
  417. package/src/timing/readingTime.ts +0 -94
  418. package/src/transform/applyTransform.ts +0 -122
  419. package/src/transform/blockAnalyzer.ts +0 -181
  420. package/src/transform/index.ts +0 -23
  421. package/src/transform/registry.ts +0 -198
  422. package/src/transform/styles/dataDriven.ts +0 -17
  423. package/src/transform/styles/documentary.ts +0 -17
  424. package/src/transform/styles/index.ts +0 -5
  425. package/src/transform/styles/magazine.ts +0 -18
  426. package/src/transform/styles/minimal.ts +0 -17
  427. package/src/transform/styles/narrative.ts +0 -18
  428. package/src/transform/templateSelector.ts +0 -389
  429. package/src/transform/timingAllocator.ts +0 -257
  430. package/src/transform/types.ts +0 -151
  431. package/src/versions/DocumentVersionManager.ts +0 -70
  432. package/src/versions/gitignore.ts +0 -34
  433. package/src/versions/index.ts +0 -56
  434. package/src/versions/operations.ts +0 -144
  435. package/src/versions/paths.ts +0 -51
  436. package/src/versions/snapshotStore.ts +0 -202
  437. package/src/versions/timestamp.ts +0 -48
  438. package/src/versions/types.ts +0 -93
@@ -2,11 +2,14 @@ import {
2
2
  SHAPE_NAMES,
3
3
  TEMPLATE_ALIASES,
4
4
  buildNarrationScript,
5
+ coerceTemplateParams,
5
6
  deriveTemplateInputs,
7
+ extractBodyPlainText,
6
8
  flattenBlocks,
7
9
  flattenRenderableBlocks,
8
10
  getBlockBodyText,
9
11
  getPinnedBlockMeta,
12
+ isContainerTemplate,
10
13
  isDataFence,
11
14
  isShapeName,
12
15
  lintTemplateParams,
@@ -21,45 +24,55 @@ import {
21
24
  templateRegistry,
22
25
  writeCustomTemplatesToFrontmatter,
23
26
  writeCustomThemesToFrontmatter
24
- } from "./chunk-X6DUONGT.js";
27
+ } from "./chunk-7ARJZYQY.js";
25
28
  import {
26
29
  ASCII_TREE_VOCAB,
27
30
  ASCII_VOCAB,
31
+ MAX_BRIDGE_GAP,
28
32
  UNICODE_TREE_VOCAB,
29
33
  UNICODE_VOCAB,
30
34
  arrowDirection,
35
+ cellWidth,
31
36
  detectAsciiDiagram,
32
37
  isHoriz,
33
38
  isJunction,
34
39
  isVert,
40
+ toCells,
35
41
  toGrid,
36
42
  traceBoxes
37
- } from "./chunk-5UYI3RJB.js";
43
+ } from "./chunk-FDYDYL77.js";
38
44
  import {
45
+ defaultPageStyle,
39
46
  resolveMediaSchedule
40
- } from "./chunk-FVJUUTEM.js";
47
+ } from "./chunk-2ZWIXGAC.js";
41
48
  import {
49
+ DEFAULT_THEME,
42
50
  FRONTMATTER_CUSTOM_TEMPLATES_KEY,
43
51
  FRONTMATTER_CUSTOM_THEMES_KEY,
44
52
  hexHueDegrees,
53
+ resolveFontFamily,
45
54
  resolveTheme
46
- } from "./chunk-W4O2TX5I.js";
55
+ } from "./chunk-C33GTPUZ.js";
56
+ import {
57
+ VIEWPORT_PRESETS,
58
+ isTemplateBlock
59
+ } from "./chunk-BAOV476U.js";
47
60
  import {
48
61
  parseMarkdown
49
- } from "./chunk-66QO7XFB.js";
62
+ } from "./chunk-ACZOVWX3.js";
50
63
  import {
51
64
  KNOWN_BLOCK_META_KEYS,
52
65
  coerceAnnotationValues,
53
66
  serializeAnnotation
54
- } from "./chunk-R2YZTCLO.js";
67
+ } from "./chunk-ZQKZSJAX.js";
55
68
  import {
56
69
  extractPlainText,
57
70
  getChildren,
58
71
  readFrontmatterThemeId
59
- } from "./chunk-AMIR72JP.js";
72
+ } from "./chunk-BCCXTMN5.js";
60
73
  import {
61
74
  estimateTimeFromText
62
- } from "./chunk-3E5F2XMR.js";
75
+ } from "./chunk-67L6WRJN.js";
63
76
 
64
77
  // src/doc/utils/animationUtils.ts
65
78
  function getAnimationStyle(animation, _currentTime = 0) {
@@ -320,16 +333,18 @@ function cssFilterForTreatment(treatment, blur) {
320
333
 
321
334
  // src/doc/docToMarkdown.ts
322
335
  var TRANSITION_PARAM_KEYS = ["transition", "transitionDuration", "transitionDirection"];
323
- function docToMarkdown(doc) {
336
+ var DEFAULT_TEMPLATE = "sectionHeader";
337
+ function docToMarkdown(doc, options = {}) {
338
+ const defaultTemplate = resolveTemplateName(options.defaultTemplate ?? DEFAULT_TEMPLATE);
324
339
  const children = [];
325
340
  const blockIds = new Set(flattenBlocks(doc.blocks).map((b) => b.id));
326
341
  const docMediaByBlock = /* @__PURE__ */ new Map();
327
342
  const homelessDocMedia = [];
328
343
  for (const clip of doc.documentMedia ?? []) {
329
344
  if (clip.origin && blockIds.has(clip.origin.blockId)) {
330
- const list = docMediaByBlock.get(clip.origin.blockId) ?? [];
331
- list.push(clip);
332
- docMediaByBlock.set(clip.origin.blockId, list);
345
+ const list2 = docMediaByBlock.get(clip.origin.blockId) ?? [];
346
+ list2.push(clip);
347
+ docMediaByBlock.set(clip.origin.blockId, list2);
333
348
  } else {
334
349
  homelessDocMedia.push(clip);
335
350
  }
@@ -339,7 +354,7 @@ function docToMarkdown(doc) {
339
354
  }
340
355
  function emitBlock(block) {
341
356
  if (block.sourceHeading) {
342
- const heading = ensureAnnotation(block, block.sourceHeading);
357
+ const heading = ensureAnnotation(block, block.sourceHeading, defaultTemplate);
343
358
  children.push(heading);
344
359
  } else if (block.standaloneAnnotation) {
345
360
  children.push(synthesizeAnnotationParagraph(block));
@@ -413,15 +428,16 @@ function synthesizeMediaParagraph(clip) {
413
428
  children: [{ type: "text", value: serializeAnnotation(clip.kind, params) }]
414
429
  };
415
430
  }
416
- function ensureAnnotation(block, heading) {
431
+ function ensureAnnotation(block, heading, defaultTemplate) {
417
432
  const { attributes, transitionParams } = ensureTransitionMetadata(block, heading);
418
- const hasExplicitTemplate = block.template && block.template !== "sectionHeader" && block.autoTemplate !== true;
419
- const hasOverrides = block.templateOverrides && Object.keys(block.templateOverrides).length > 0;
420
- let templateAnnotation = heading.templateAnnotation;
421
- if (!templateAnnotation && (hasExplicitTemplate || hasOverrides || transitionParams)) {
433
+ const existing = heading.templateAnnotation;
434
+ const template = resolveAnnotationTemplate(block, existing, defaultTemplate);
435
+ const overrides = block.templateOverrides && Object.keys(block.templateOverrides).length > 0 ? block.templateOverrides : void 0;
436
+ let templateAnnotation;
437
+ if (template !== void 0 || overrides !== void 0) {
422
438
  templateAnnotation = {
423
- ...hasExplicitTemplate ? { template: block.template ?? "sectionHeader" } : {},
424
- ...hasOverrides ? { params: block.templateOverrides } : {}
439
+ ...template !== void 0 ? { template } : {},
440
+ ...overrides ? { params: overrides } : {}
425
441
  };
426
442
  }
427
443
  if (transitionParams) {
@@ -433,11 +449,33 @@ function ensureAnnotation(block, heading) {
433
449
  }
434
450
  };
435
451
  }
452
+ if (annotationsEqual(existing, templateAnnotation)) templateAnnotation = existing;
436
453
  if (attributes === heading.attributes && templateAnnotation === heading.templateAnnotation) {
437
454
  return heading;
438
455
  }
439
456
  return { ...heading, children: [...heading.children], attributes, templateAnnotation };
440
457
  }
458
+ function resolveAnnotationTemplate(block, existing, defaultTemplate) {
459
+ if (!block.template || block.autoTemplate === true) return existing?.template;
460
+ const template = resolveTemplateName(block.template);
461
+ if (existing?.template && resolveTemplateName(existing.template) === template) {
462
+ return existing.template;
463
+ }
464
+ if (template === defaultTemplate) return void 0;
465
+ return block.template;
466
+ }
467
+ function annotationsEqual(a, b) {
468
+ if (a === b) return true;
469
+ if (!a || !b) return false;
470
+ return a.template === b.template && paramsEqual(a.params, b.params);
471
+ }
472
+ function paramsEqual(a, b) {
473
+ if (a === b) return true;
474
+ if (!a || !b) return false;
475
+ const keys = Object.keys(a);
476
+ if (keys.length !== Object.keys(b).length) return false;
477
+ return keys.every((key) => Object.prototype.hasOwnProperty.call(b, key) && a[key] === b[key]);
478
+ }
441
479
  function ensureTransitionMetadata(block, heading) {
442
480
  const transition = block.transition;
443
481
  if (!transition) {
@@ -479,16 +517,1358 @@ function resolveThemeForDoc(doc, explicitId, registry) {
479
517
  return resolveTheme(id, registry);
480
518
  }
481
519
 
520
+ // src/doc/page/resolvePageBlock.ts
521
+ function isTemplatedPageBlock(block) {
522
+ if (block.sourceHeading?.templateAnnotation?.template) return true;
523
+ if (block.autoTemplate && block.template) return true;
524
+ return !block.sourceHeading && isTemplateBlock(block);
525
+ }
526
+ function templatedName(block) {
527
+ return block.sourceHeading?.templateAnnotation?.template ?? block.template;
528
+ }
529
+ function resolvePageBlock(block) {
530
+ if (!isTemplatedPageBlock(block)) return { templated: false };
531
+ const annotation = block.sourceHeading?.templateAnnotation;
532
+ const rawName = templatedName(block) ?? "sectionHeader";
533
+ const templateName = resolveTemplateName(rawName);
534
+ const rawParams = {
535
+ ...annotation?.params ?? {},
536
+ ...block.templateOverrides ?? {}
537
+ };
538
+ const coercedParams = coerceTemplateParams(rawName, rawParams).input;
539
+ let base;
540
+ if (annotation) {
541
+ const headingText = extractPlainText(block.sourceHeading);
542
+ base = {
543
+ id: block.id,
544
+ template: rawName,
545
+ startTime: 0,
546
+ duration: 1,
547
+ audioSegment: 0,
548
+ title: headingText,
549
+ contents: block.contents,
550
+ children: block.children,
551
+ ...deriveTemplateInputs(rawName, headingText, block.contents, {
552
+ placeholders: true
553
+ }) ?? {}
554
+ };
555
+ } else {
556
+ base = {
557
+ ...block,
558
+ startTime: block.startTime ?? 0,
559
+ duration: block.duration ?? 1,
560
+ audioSegment: block.audioSegment ?? 0,
561
+ template: rawName
562
+ };
563
+ }
564
+ const templateBlock = {
565
+ ...base,
566
+ ...block.templateData ?? {},
567
+ ...coercedParams
568
+ };
569
+ return { templated: true, templateName, templateBlock };
570
+ }
571
+
572
+ // src/doc/page/sectionExtractors.ts
573
+ function bodyRichText(input) {
574
+ const contents = input.contents;
575
+ if (!contents || contents.length === 0) return void 0;
576
+ const text = contents.map((node) => extractPlainText(node)).join("\n").trim();
577
+ return text ? { text, markdown: contents } : void 0;
578
+ }
579
+ function accentImageMedia(accent) {
580
+ if (!accent?.src) return void 0;
581
+ return {
582
+ type: "image",
583
+ src: accent.src,
584
+ alt: accent.alt ?? "",
585
+ credit: accent.credit,
586
+ license: accent.license
587
+ };
588
+ }
589
+ function canvasDraft(spatial, ctx, block) {
590
+ return {
591
+ kind: "canvas-embed",
592
+ variant: spatial,
593
+ slots: {
594
+ media: {
595
+ type: "canvas",
596
+ spatial,
597
+ block: block ?? ctx.block,
598
+ aspect: { width: ctx.viewport.width, height: ctx.viewport.height }
599
+ }
600
+ }
601
+ };
602
+ }
603
+ var title = (input) => {
604
+ const t = input;
605
+ const contents = input.contents;
606
+ const firstParagraph = contents?.find((node) => node.type === "paragraph");
607
+ const subtitle = t.subtitle ?? (firstParagraph ? extractPlainText(firstParagraph) : void 0);
608
+ return {
609
+ kind: "hero",
610
+ variant: "title",
611
+ slots: { title: t.title, subtitle },
612
+ emphasis: "lead",
613
+ hints: t.backgroundColor ? { backgroundColor: t.backgroundColor } : void 0
614
+ };
615
+ };
616
+ var sectionHeader = (input) => {
617
+ const s = input;
618
+ const media = s.imageSrc ? { type: "image", src: s.imageSrc, alt: s.imageAlt ?? "" } : void 0;
619
+ return {
620
+ kind: "banner",
621
+ slots: { title: s.title, media },
622
+ colorScheme: s.colorScheme,
623
+ mediaBackground: !!s.imageSrc
624
+ };
625
+ };
626
+ var statHighlight = (input) => {
627
+ const s = input;
628
+ return {
629
+ kind: "stat-band",
630
+ variant: "single",
631
+ slots: {
632
+ items: [{ value: s.stat, title: s.description, body: s.detail }],
633
+ media: accentImageMedia(s.accentImage)
634
+ },
635
+ emphasis: "strong",
636
+ colorScheme: s.colorScheme
637
+ };
638
+ };
639
+ var quote = (input) => {
640
+ const q = input;
641
+ return {
642
+ kind: "quote-band",
643
+ variant: "plain",
644
+ slots: {
645
+ body: { text: q.quote ?? "" },
646
+ attribution: q.attribution,
647
+ media: accentImageMedia(q.accentImage)
648
+ }
649
+ };
650
+ };
651
+ var factCard = (input) => {
652
+ const f = input;
653
+ return {
654
+ kind: "callout",
655
+ variant: "fact",
656
+ slots: {
657
+ title: f.fact,
658
+ body: { text: f.explanation ?? "" },
659
+ meta: f.source,
660
+ media: accentImageMedia(f.accentImage)
661
+ }
662
+ };
663
+ };
664
+ var twoColumn = (input) => {
665
+ const t = input;
666
+ return {
667
+ kind: "card-grid",
668
+ variant: "two-column",
669
+ slots: {
670
+ title: t.header,
671
+ items: [
672
+ { title: t.left?.label, body: t.left?.sublabel, accentScheme: t.leftColor },
673
+ { title: t.right?.label, body: t.right?.sublabel, accentScheme: t.rightColor }
674
+ ]
675
+ }
676
+ };
677
+ };
678
+ var dateEvent = (input) => {
679
+ const d = input;
680
+ return {
681
+ kind: "timeline-rail",
682
+ slots: {
683
+ milestone: {
684
+ date: d.date ?? "",
685
+ description: d.description ?? "",
686
+ footer: d.footer,
687
+ mood: d.mood
688
+ },
689
+ media: accentImageMedia(d.accentImage)
690
+ }
691
+ };
692
+ };
693
+ var imageWithCaption = (input) => {
694
+ const i = input;
695
+ const media = {
696
+ type: "image",
697
+ src: i.imageSrc,
698
+ alt: i.imageAlt ?? "",
699
+ credit: i.imageCredit,
700
+ license: i.imageLicense
701
+ };
702
+ if (i.isTitle) {
703
+ return {
704
+ kind: "hero",
705
+ variant: "media",
706
+ slots: { title: i.caption, subtitle: i.subtitle, media },
707
+ emphasis: "lead",
708
+ mediaBackground: true
709
+ };
710
+ }
711
+ return {
712
+ kind: "media-figure",
713
+ variant: "image",
714
+ slots: { media, caption: i.caption }
715
+ };
716
+ };
717
+ function featureDraft(input, side) {
718
+ return {
719
+ kind: "feature-split",
720
+ variant: side === "left" ? "media-left" : "media-right",
721
+ slots: {
722
+ title: input.title,
723
+ body: input.body ? { text: input.body } : void 0,
724
+ media: {
725
+ type: "image",
726
+ src: input.imageSrc,
727
+ alt: input.imageAlt ?? "",
728
+ width: input.imageWidth,
729
+ height: input.imageHeight
730
+ }
731
+ }
732
+ };
733
+ }
734
+ var leftFeature = (input) => featureDraft(input, "left");
735
+ var rightFeature = (input) => featureDraft(input, "right");
736
+ var fullBleedQuote = (input) => {
737
+ const f = input;
738
+ return {
739
+ kind: "quote-band",
740
+ variant: "display",
741
+ slots: { body: { text: f.text ?? "" } },
742
+ emphasis: "strong",
743
+ colorScheme: f.colorScheme
744
+ };
745
+ };
746
+ var list = (input) => {
747
+ const l = input;
748
+ return {
749
+ kind: "item-list",
750
+ slots: {
751
+ title: l.title,
752
+ items: (l.items ?? []).map((item) => ({ body: item })),
753
+ media: accentImageMedia(l.accentImage)
754
+ },
755
+ colorScheme: l.colorScheme
756
+ };
757
+ };
758
+ var photoGrid = (input) => {
759
+ const p = input;
760
+ const images = p.images ?? [];
761
+ const fallback = images.length === 0 ? {
762
+ title: input.title,
763
+ body: bodyRichText(input)
764
+ } : void 0;
765
+ return {
766
+ kind: "gallery",
767
+ slots: {
768
+ ...fallback,
769
+ caption: p.caption,
770
+ items: images.map((img) => ({
771
+ media: {
772
+ type: "image",
773
+ src: img.src,
774
+ alt: img.alt ?? "",
775
+ credit: img.credit,
776
+ license: img.license
777
+ }
778
+ }))
779
+ }
780
+ };
781
+ };
782
+ var definitionCard = (input) => {
783
+ const d = input;
784
+ return {
785
+ kind: "callout",
786
+ variant: "definition",
787
+ slots: {
788
+ title: d.term,
789
+ body: { text: d.definition ?? "" },
790
+ meta: d.origin,
791
+ media: accentImageMedia(d.accentImage)
792
+ },
793
+ colorScheme: d.colorScheme
794
+ };
795
+ };
796
+ var comparisonBar = (input) => {
797
+ const c = input;
798
+ return {
799
+ kind: "stat-band",
800
+ variant: "comparison",
801
+ slots: {
802
+ items: [
803
+ { title: c.leftLabel, value: c.leftValue },
804
+ { title: c.rightLabel, value: c.rightValue }
805
+ ],
806
+ meta: c.unit
807
+ },
808
+ emphasis: "strong",
809
+ colorScheme: c.colorScheme
810
+ };
811
+ };
812
+ var pullQuote = (input) => {
813
+ const p = input;
814
+ const bg = p.backgroundImage;
815
+ return {
816
+ kind: "quote-band",
817
+ variant: "full-bleed",
818
+ slots: {
819
+ body: { text: p.text ?? "" },
820
+ attribution: p.attribution,
821
+ media: bg?.src ? { type: "image", src: bg.src, alt: bg.alt ?? "", credit: bg.credit, license: bg.license } : void 0
822
+ },
823
+ emphasis: "strong",
824
+ mediaBackground: !!bg?.src
825
+ };
826
+ };
827
+ var videoWithCaption = (input) => {
828
+ const v = input;
829
+ return {
830
+ kind: "media-figure",
831
+ variant: "video",
832
+ slots: {
833
+ media: {
834
+ type: "video",
835
+ src: v.videoSrc,
836
+ posterSrc: v.posterSrc,
837
+ alt: v.videoAlt ?? "",
838
+ clipStart: v.clipStart,
839
+ clipEnd: v.clipEnd,
840
+ credit: v.videoCredit,
841
+ license: v.videoLicense
842
+ },
843
+ caption: v.caption
844
+ }
845
+ };
846
+ };
847
+ var videoPullQuote = (input) => {
848
+ const v = input;
849
+ const bg = v.backgroundVideo;
850
+ return {
851
+ kind: "quote-band",
852
+ variant: "full-bleed",
853
+ slots: {
854
+ body: { text: v.text ?? "" },
855
+ attribution: v.attribution,
856
+ media: bg?.src ? {
857
+ type: "video",
858
+ src: bg.src,
859
+ posterSrc: bg.posterSrc,
860
+ alt: bg.alt ?? "",
861
+ clipStart: bg.clipStart,
862
+ clipEnd: bg.clipEnd,
863
+ credit: bg.credit,
864
+ license: bg.license
865
+ } : void 0
866
+ },
867
+ emphasis: "strong",
868
+ mediaBackground: !!bg?.src
869
+ };
870
+ };
871
+ var dataTable = (input) => {
872
+ const d = input;
873
+ return {
874
+ kind: "table-section",
875
+ slots: {
876
+ title: d.title,
877
+ table: { headers: d.headers ?? [], rows: d.rows ?? [], align: d.align }
878
+ },
879
+ colorScheme: d.colorScheme
880
+ };
881
+ };
882
+ var diagram = (input, ctx) => canvasDraft("diagram", ctx, input);
883
+ var tree = (input, ctx) => canvasDraft("tree", ctx, input);
884
+ var timeline = (input, ctx) => canvasDraft("timeline", ctx, input);
885
+ var map = (input, ctx) => canvasDraft("map", ctx, input);
886
+ var drawing = (input, ctx) => canvasDraft("drawing", ctx, input);
887
+ var layout = (input, ctx) => canvasDraft("layout", ctx, input);
888
+ var sectionExtractors = {
889
+ title,
890
+ sectionHeader,
891
+ statHighlight,
892
+ quote,
893
+ factCard,
894
+ twoColumn,
895
+ dateEvent,
896
+ imageWithCaption,
897
+ leftFeature,
898
+ rightFeature,
899
+ map,
900
+ fullBleedQuote,
901
+ list,
902
+ photoGrid,
903
+ definitionCard,
904
+ comparisonBar,
905
+ pullQuote,
906
+ videoWithCaption,
907
+ videoPullQuote,
908
+ dataTable,
909
+ diagram,
910
+ tree,
911
+ timeline,
912
+ layout,
913
+ drawing
914
+ };
915
+
916
+ // src/doc/page/materializePageSection.ts
917
+ function resolvePageStyle(theme, hints) {
918
+ const base = theme?.pageStyle ?? defaultPageStyle(theme ?? DEFAULT_THEME);
919
+ if (!hints?.spacing || hints.spacing === base.tokens.sectionSpacing) return base;
920
+ return { ...base, tokens: { ...base.tokens, sectionSpacing: hints.spacing } };
921
+ }
922
+ var ACCENT_KINDS = /* @__PURE__ */ new Set([
923
+ "banner",
924
+ "stat-band",
925
+ "quote-band",
926
+ "callout",
927
+ "card-grid",
928
+ "item-list",
929
+ "timeline-rail",
930
+ "footer"
931
+ ]);
932
+ var BAND_KINDS = /* @__PURE__ */ new Set([
933
+ "banner",
934
+ "quote-band",
935
+ "stat-band",
936
+ "footer"
937
+ ]);
938
+ var PANEL_KINDS = /* @__PURE__ */ new Set([
939
+ "callout",
940
+ "card-grid",
941
+ "stat-band",
942
+ "item-list",
943
+ "timeline-rail",
944
+ "table-section"
945
+ ]);
946
+ function isMermaidFence(node) {
947
+ return node.type === "code" && node.lang?.trim().toLowerCase() === "mermaid";
948
+ }
949
+ function htmlTreeContainsMedia(nodes) {
950
+ for (const value of nodes) {
951
+ if (!value || typeof value !== "object") continue;
952
+ const node = value;
953
+ if (node.type === "htmlElement" && typeof node.tagName === "string" && ["img", "video", "audio"].includes(node.tagName.toLowerCase())) {
954
+ return true;
955
+ }
956
+ if (Array.isArray(node.children) && htmlTreeContainsMedia(node.children)) return true;
957
+ }
958
+ return false;
959
+ }
960
+ function markdownNodeContainsMedia(value) {
961
+ if (!value || typeof value !== "object") return false;
962
+ const node = value;
963
+ if (node.type === "image") return true;
964
+ if ((node.type === "htmlBlock" || node.type === "htmlInline") && Array.isArray(node.htmlChildren) && htmlTreeContainsMedia(node.htmlChildren)) {
965
+ return true;
966
+ }
967
+ return Array.isArray(node.children) && node.children.some(markdownNodeContainsMedia);
968
+ }
969
+ function unconsumedRichContent(block, draft) {
970
+ if (!block.contents || block.contents.length === 0) return void 0;
971
+ const templateHasMedia = Boolean(draft.slots.media) || Boolean(draft.slots.items?.some((item) => item.media !== void 0));
972
+ const markdown = block.contents.filter(
973
+ (node) => isMermaidFence(node) || !templateHasMedia && markdownNodeContainsMedia(node)
974
+ );
975
+ if (markdown.length === 0) return void 0;
976
+ return {
977
+ text: markdown.map((node) => extractPlainText(node)).join("\n").trim(),
978
+ markdown
979
+ };
980
+ }
981
+ function preserveRichContent(block, draft) {
982
+ const richContent = unconsumedRichContent(block, draft);
983
+ return richContent ? { ...draft, slots: { ...draft.slots, richContent } } : draft;
984
+ }
985
+ function draftForBlock(block, viewport, customTemplates) {
986
+ if (isTemplatedPageBlock(block)) {
987
+ const resolved = resolvePageBlock(block);
988
+ const templateName = resolved.templateName;
989
+ const extractor = sectionExtractors[templateName];
990
+ if (extractor) {
991
+ return {
992
+ draft: preserveRichContent(block, extractor(resolved.templateBlock, { block, viewport })),
993
+ source: "template",
994
+ templateName
995
+ };
996
+ }
997
+ const custom = customTemplates?.find((definition) => definition.name === templateName);
998
+ if (custom) {
999
+ const draft2 = {
1000
+ kind: "canvas-embed",
1001
+ variant: "custom",
1002
+ slots: {
1003
+ media: {
1004
+ type: "canvas",
1005
+ spatial: "custom",
1006
+ block: resolved.templateBlock,
1007
+ aspect: {
1008
+ width: custom.viewport?.width ?? viewport.width,
1009
+ height: custom.viewport?.height ?? viewport.height
1010
+ }
1011
+ }
1012
+ }
1013
+ };
1014
+ return {
1015
+ draft: preserveRichContent(block, draft2),
1016
+ source: "custom-template",
1017
+ templateName
1018
+ };
1019
+ }
1020
+ const diagnostic = {
1021
+ code: "unknown-template",
1022
+ template: templateName,
1023
+ message: `Unknown template "${templateName}"`
1024
+ };
1025
+ const headingText = block.sourceHeading ? extractPlainText(block.sourceHeading) : void 0;
1026
+ const draft = {
1027
+ kind: "callout",
1028
+ variant: "diagnostic",
1029
+ slots: {
1030
+ title: headingText ?? diagnostic.message,
1031
+ body: { text: extractBodyPlainText(block.contents) },
1032
+ meta: diagnostic.message
1033
+ },
1034
+ emphasis: "quiet"
1035
+ };
1036
+ return {
1037
+ draft: preserveRichContent(block, draft),
1038
+ source: "fallback",
1039
+ templateName,
1040
+ diagnostic
1041
+ };
1042
+ }
1043
+ if (block.layers && block.layers.length > 0) {
1044
+ const draft = {
1045
+ kind: "canvas-embed",
1046
+ variant: "authored",
1047
+ slots: {
1048
+ media: {
1049
+ type: "canvas",
1050
+ spatial: "authored",
1051
+ block,
1052
+ aspect: { width: viewport.width, height: viewport.height }
1053
+ }
1054
+ }
1055
+ };
1056
+ return {
1057
+ draft: preserveRichContent(block, draft),
1058
+ source: "authored"
1059
+ };
1060
+ }
1061
+ const heading = block.sourceHeading;
1062
+ return {
1063
+ draft: {
1064
+ kind: "prose",
1065
+ slots: {
1066
+ title: heading ? extractPlainText(heading) : void 0,
1067
+ headingLevel: heading?.depth,
1068
+ body: block.contents && block.contents.length > 0 ? { text: extractBodyPlainText(block.contents), markdown: block.contents } : void 0
1069
+ }
1070
+ },
1071
+ source: "prose"
1072
+ };
1073
+ }
1074
+ function overrideFor(pageStyle, kind, templateName) {
1075
+ const byTemplate = templateName ? pageStyle.templates?.[templateName] : void 0;
1076
+ const byKind = pageStyle.sections?.[kind];
1077
+ if (!byTemplate) return byKind;
1078
+ if (!byKind) return byTemplate;
1079
+ return {
1080
+ ...byKind,
1081
+ ...byTemplate,
1082
+ hints: { ...byKind.hints, ...byTemplate.hints }
1083
+ };
1084
+ }
1085
+ function buildSection(seed, index, totalSections, background, emphasis, accent) {
1086
+ const { draft, override } = seed;
1087
+ const hints = { ...draft.hints, ...override?.hints };
1088
+ const section = {
1089
+ kind: override?.kind ?? draft.kind,
1090
+ variant: override?.variant ?? draft.variant,
1091
+ blockId: seed.block?.id ?? "cover",
1092
+ template: seed.source === "template" || seed.source === "custom-template" || seed.source === "fallback" ? seed.templateName : void 0,
1093
+ slots: draft.slots,
1094
+ emphasis,
1095
+ accent,
1096
+ background,
1097
+ index,
1098
+ totalSections,
1099
+ depth: seed.depth,
1100
+ source: seed.source
1101
+ };
1102
+ if (seed.diagnostic) section.diagnostic = seed.diagnostic;
1103
+ if (Object.keys(hints).length > 0) section.hints = hints;
1104
+ return section;
1105
+ }
1106
+ function resolveScheme(theme, schemeName) {
1107
+ return schemeName ? theme.colorSchemes?.[schemeName] : void 0;
1108
+ }
1109
+ function rotationSchemeNames(pageStyle, theme) {
1110
+ const all = Object.keys(theme.colorSchemes ?? {});
1111
+ const requested = pageStyle.accentRotation.schemes;
1112
+ if (!requested || requested.length === 0) return all;
1113
+ return requested.filter((name) => all.includes(name));
1114
+ }
1115
+ function materializePageSection(block, options = {}) {
1116
+ const theme = options.theme ?? DEFAULT_THEME;
1117
+ const viewport = options.viewport ?? VIEWPORT_PRESETS.landscape;
1118
+ const pageStyle = resolvePageStyle(theme);
1119
+ const result = draftForBlock(block, viewport, options.customTemplates);
1120
+ const override = overrideFor(pageStyle, result.draft.kind, result.templateName);
1121
+ const background = override?.background ?? (result.draft.mediaBackground ? "media" : "base");
1122
+ const emphasis = override?.emphasis ?? result.draft.emphasis ?? "standard";
1123
+ const accent = result.draft.colorScheme ? {
1124
+ schemeName: result.draft.colorScheme,
1125
+ scheme: resolveScheme(theme, result.draft.colorScheme),
1126
+ role: "block"
1127
+ } : { role: pageStyle.accentRotation.strategy === "none" ? "none" : "primary" };
1128
+ const section = buildSection(
1129
+ { ...result, override, block, depth: 0 },
1130
+ options.blockIndex ?? 0,
1131
+ options.totalBlocks ?? 1,
1132
+ background,
1133
+ emphasis,
1134
+ accent
1135
+ );
1136
+ return {
1137
+ section,
1138
+ block,
1139
+ source: result.source,
1140
+ diagnostic: result.diagnostic
1141
+ };
1142
+ }
1143
+ function materializePageSections(doc, options = {}) {
1144
+ const theme = options.theme ?? DEFAULT_THEME;
1145
+ const viewport = options.viewport ?? VIEWPORT_PRESETS.landscape;
1146
+ const pageStyle = resolvePageStyle(theme, options.transformPage);
1147
+ const customTemplates = options.customTemplates ?? doc.customTemplates;
1148
+ const seeds = [];
1149
+ if (options.cover) {
1150
+ const cover = options.cover;
1151
+ seeds.push({
1152
+ draft: {
1153
+ kind: "hero",
1154
+ variant: "cover",
1155
+ slots: {
1156
+ title: cover.title,
1157
+ subtitle: cover.subtitle,
1158
+ media: cover.heroSrc ? {
1159
+ type: "image",
1160
+ src: cover.heroSrc,
1161
+ alt: cover.heroAlt ?? "",
1162
+ credit: cover.heroCredit,
1163
+ license: cover.heroLicense
1164
+ } : void 0
1165
+ },
1166
+ emphasis: "lead",
1167
+ mediaBackground: !!cover.heroSrc
1168
+ },
1169
+ source: "cover",
1170
+ depth: 0
1171
+ });
1172
+ }
1173
+ const walk = (blocks, depth) => {
1174
+ for (const block of blocks) {
1175
+ const result = draftForBlock(block, viewport, customTemplates);
1176
+ seeds.push({ ...result, block, depth });
1177
+ const consumed = result.draft.kind === "canvas-embed" && isContainerTemplate(result.templateName);
1178
+ if (!consumed && block.children && block.children.length > 0) {
1179
+ walk(block.children, depth + 1);
1180
+ }
1181
+ }
1182
+ };
1183
+ walk(doc.blocks ?? [], 0);
1184
+ if (options.cover && seeds.length > 1) {
1185
+ const cover = options.cover;
1186
+ const first = seeds[1];
1187
+ if (first.draft.kind === "hero" && first.draft.slots.title === cover.title) {
1188
+ const coverSeed = seeds[0];
1189
+ const coverMedia = coverSeed.draft.slots.media;
1190
+ if (coverMedia && !first.draft.slots.media) {
1191
+ first.draft = {
1192
+ ...first.draft,
1193
+ slots: { ...first.draft.slots, media: coverMedia },
1194
+ mediaBackground: true
1195
+ };
1196
+ }
1197
+ seeds.splice(0, 1);
1198
+ } else if (first.draft.kind === "prose" && first.draft.slots.title === cover.title) {
1199
+ const slots = { ...first.draft.slots };
1200
+ delete slots.title;
1201
+ delete slots.headingLevel;
1202
+ let markdown = slots.body?.markdown;
1203
+ if (cover.subtitle && markdown && markdown.length > 0 && markdown[0].type === "paragraph" && extractPlainText(markdown[0]) === cover.subtitle) {
1204
+ markdown = markdown.slice(1);
1205
+ }
1206
+ if (markdown && markdown.length > 0) {
1207
+ slots.body = {
1208
+ text: markdown.map((node) => extractPlainText(node)).join("\n").trim(),
1209
+ markdown
1210
+ };
1211
+ first.draft = { ...first.draft, slots };
1212
+ } else {
1213
+ seeds.splice(1, 1);
1214
+ }
1215
+ }
1216
+ }
1217
+ for (const seed of seeds) {
1218
+ seed.override = overrideFor(pageStyle, seed.draft.kind, seed.templateName);
1219
+ }
1220
+ const totalSections = seeds.length;
1221
+ const rhythm = pageStyle.tokens.backgroundRhythm;
1222
+ const strategy = pageStyle.accentRotation.strategy;
1223
+ const schemeNames = rotationSchemeNames(pageStyle, theme);
1224
+ const rotationSize = strategy === "alternate-two" ? Math.min(2, schemeNames.length) : schemeNames.length;
1225
+ let bandCounter = 0;
1226
+ let rotationCounter = 0;
1227
+ let promotedCount = 0;
1228
+ let eyebrowCounter = 0;
1229
+ const eyebrowTreatment = pageStyle.tokens.headingTreatment.eyebrow;
1230
+ const results = [];
1231
+ for (let index = 0; index < seeds.length; index++) {
1232
+ const seed = seeds[index];
1233
+ const kind = seed.override?.kind ?? seed.draft.kind;
1234
+ let background;
1235
+ if (seed.override?.background) {
1236
+ background = seed.override.background;
1237
+ } else if (seed.draft.mediaBackground) {
1238
+ background = "media";
1239
+ } else if (kind === "prose" || rhythm === "flat") {
1240
+ background = "base";
1241
+ } else if (rhythm === "accent-bands" && BAND_KINDS.has(kind)) {
1242
+ background = "accent";
1243
+ } else if (rhythm === "tinted-panels") {
1244
+ background = PANEL_KINDS.has(kind) ? "alternate" : "base";
1245
+ } else if (rhythm === "alternate" || rhythm === "accent-bands") {
1246
+ background = bandCounter % 2 === 1 ? "alternate" : "base";
1247
+ bandCounter++;
1248
+ } else {
1249
+ background = "base";
1250
+ }
1251
+ let accent;
1252
+ if (seed.draft.colorScheme) {
1253
+ accent = {
1254
+ schemeName: seed.draft.colorScheme,
1255
+ scheme: resolveScheme(theme, seed.draft.colorScheme),
1256
+ role: "block"
1257
+ };
1258
+ } else if (ACCENT_KINDS.has(kind) && (strategy === "cycle" || strategy === "alternate-two") && rotationSize > 0) {
1259
+ const schemeName = schemeNames[rotationCounter % rotationSize];
1260
+ rotationCounter++;
1261
+ accent = { schemeName, scheme: resolveScheme(theme, schemeName), role: "rotation" };
1262
+ } else if (strategy === "none") {
1263
+ accent = { role: "none" };
1264
+ } else {
1265
+ accent = { role: "primary" };
1266
+ }
1267
+ let emphasis = seed.override?.emphasis ?? seed.draft.emphasis ?? "standard";
1268
+ if (options.transformPage?.emphasisCurve === "front-loaded" && kind !== "hero" && kind !== "prose" && promotedCount < 2) {
1269
+ if (emphasis === "standard") emphasis = "strong";
1270
+ promotedCount++;
1271
+ }
1272
+ if ((eyebrowTreatment === "numbered" || eyebrowTreatment === "mono-tag") && (kind === "hero" || kind === "banner")) {
1273
+ eyebrowCounter++;
1274
+ if (!seed.draft.slots.eyebrow) {
1275
+ seed.draft.slots = {
1276
+ ...seed.draft.slots,
1277
+ eyebrow: String(eyebrowCounter).padStart(2, "0")
1278
+ };
1279
+ }
1280
+ }
1281
+ const section = buildSection(seed, index, totalSections, background, emphasis, accent);
1282
+ results.push({
1283
+ section,
1284
+ block: seed.block,
1285
+ source: seed.source,
1286
+ diagnostic: seed.diagnostic
1287
+ });
1288
+ }
1289
+ return results;
1290
+ }
1291
+
1292
+ // src/doc/pageCss.ts
1293
+ var NOISE_DATA_URI = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='0.35'/%3E%3C/svg%3E")`;
1294
+ function buildPageCssVars(theme, pageStyle) {
1295
+ const t = theme ?? DEFAULT_THEME;
1296
+ const style = pageStyle ?? resolvePageStyle(t);
1297
+ const colors = t.colors;
1298
+ const typography = t.typography;
1299
+ return {
1300
+ "--squisq-page-bg": colors.background,
1301
+ "--squisq-page-bg-alt": colors.backgroundLight,
1302
+ "--squisq-page-text": colors.text,
1303
+ "--squisq-page-text-muted": colors.textMuted,
1304
+ "--squisq-page-primary": colors.primary,
1305
+ "--squisq-page-secondary": colors.secondary,
1306
+ "--squisq-page-highlight": colors.highlight,
1307
+ "--squisq-page-title-font": resolveFontFamily(typography.titleFont, "Georgia, serif"),
1308
+ "--squisq-page-body-font": resolveFontFamily(typography.bodyFont, "system-ui, sans-serif"),
1309
+ "--squisq-page-mono-font": resolveFontFamily(
1310
+ typography.monoFont,
1311
+ "ui-monospace, SFMono-Regular, Menlo, monospace"
1312
+ ),
1313
+ "--squisq-page-line-height": String(typography.lineHeight ?? 1.65),
1314
+ "--squisq-page-title-weight": typography.titleWeight === "normal" ? "400" : "700",
1315
+ "--squisq-page-content-max": `${style.tokens.contentMaxWidth}px`,
1316
+ "--squisq-page-wide-max": `${style.tokens.wideMaxWidth}px`,
1317
+ "--squisq-page-radius": `${style.tokens.cornerRadius}px`,
1318
+ // Per-section accent defaults; the renderer overrides these per section.
1319
+ "--squisq-page-accent": colors.primary,
1320
+ "--squisq-page-accent-bg": colors.backgroundLight,
1321
+ "--squisq-page-accent-text": colors.text
1322
+ };
1323
+ }
1324
+ function pageStyleDataAttributes(pageStyle) {
1325
+ const tokens = pageStyle.tokens;
1326
+ const attrs = {
1327
+ "data-family": pageStyle.family,
1328
+ "data-spacing": tokens.sectionSpacing,
1329
+ "data-divider": tokens.divider,
1330
+ "data-rhythm": tokens.backgroundRhythm,
1331
+ "data-hero-style": tokens.heroStyle,
1332
+ "data-eyebrow": tokens.headingTreatment.eyebrow,
1333
+ "data-heading-scale": tokens.headingTreatment.scale,
1334
+ "data-framing": tokens.imageFraming,
1335
+ "data-shadow": tokens.shadow,
1336
+ "data-quote-mark": tokens.quoteMark,
1337
+ "data-numerals": tokens.numeralStyle
1338
+ };
1339
+ if (tokens.headingTreatment.case && tokens.headingTreatment.case !== "none") {
1340
+ attrs["data-heading-case"] = tokens.headingTreatment.case;
1341
+ }
1342
+ if (tokens.headingTreatment.underline && tokens.headingTreatment.underline !== "none") {
1343
+ attrs["data-underline"] = tokens.headingTreatment.underline;
1344
+ }
1345
+ if (tokens.pattern && tokens.pattern !== "none") {
1346
+ attrs["data-pattern"] = tokens.pattern;
1347
+ }
1348
+ return attrs;
1349
+ }
1350
+ var NARROW_RULES = `
1351
+ .squisq-page-hero-grid { grid-template-columns: 1fr; gap: 1.5rem; }
1352
+ .squisq-page-feature { grid-template-columns: 1fr; }
1353
+ .squisq-page-feature--media-right .squisq-page-feature-media { order: 0; }
1354
+ .squisq-page-stats { flex-direction: column; gap: 1.75rem; }
1355
+ .squisq-page-cards { grid-template-columns: 1fr; }
1356
+ .squisq-page-gallery { grid-template-columns: repeat(2, 1fr); }
1357
+ .squisq-page-milestone { grid-template-columns: 1fr; gap: 0.5rem; }
1358
+ .squisq-page-milestone-rail { display: none; }
1359
+ .squisq-page-section-inner { padding-inline: 18px; }
1360
+ `;
1361
+ var PAGE_BASE_CSS = `
1362
+ /* \u2500\u2500 Base \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1363
+ .squisq-page {
1364
+ background: var(--squisq-page-bg);
1365
+ color: var(--squisq-page-text);
1366
+ font-family: var(--squisq-page-body-font);
1367
+ line-height: var(--squisq-page-line-height);
1368
+ --squisq-page-divider-color: color-mix(in srgb, var(--squisq-page-text) 16%, transparent);
1369
+ --squisq-page-section-pad: 3.5rem;
1370
+ --squisq-page-shadow: none;
1371
+ }
1372
+ .squisq-page *, .squisq-page *::before, .squisq-page *::after { box-sizing: border-box; }
1373
+ .squisq-page img { max-width: 100%; height: auto; }
1374
+
1375
+ /* Page pattern washes (very low intensity) */
1376
+ .squisq-page[data-pattern='dots'] {
1377
+ background-image: radial-gradient(color-mix(in srgb, var(--squisq-page-text) 7%, transparent) 1px, transparent 1px);
1378
+ background-size: 22px 22px;
1379
+ }
1380
+ .squisq-page[data-pattern='grid'] {
1381
+ background-image:
1382
+ linear-gradient(color-mix(in srgb, var(--squisq-page-primary) 7%, transparent) 1px, transparent 1px),
1383
+ linear-gradient(90deg, color-mix(in srgb, var(--squisq-page-primary) 7%, transparent) 1px, transparent 1px);
1384
+ background-size: 44px 44px;
1385
+ }
1386
+ .squisq-page[data-pattern='diagonal'] {
1387
+ background-image: repeating-linear-gradient(
1388
+ -45deg,
1389
+ color-mix(in srgb, var(--squisq-page-text) 4%, transparent) 0 1px,
1390
+ transparent 1px 14px
1391
+ );
1392
+ }
1393
+ .squisq-page[data-pattern='noise'] { background-image: ${NOISE_DATA_URI}; }
1394
+
1395
+ /* Spacing scale */
1396
+ .squisq-page[data-spacing='compact'] { --squisq-page-section-pad: 2.25rem; }
1397
+ .squisq-page[data-spacing='comfortable'] { --squisq-page-section-pad: 3.5rem; }
1398
+ .squisq-page[data-spacing='generous'] { --squisq-page-section-pad: 5.25rem; }
1399
+
1400
+ /* Shadow language */
1401
+ .squisq-page[data-shadow='soft'] { --squisq-page-shadow: 0 14px 36px color-mix(in srgb, var(--squisq-page-text) 14%, transparent); }
1402
+ .squisq-page[data-shadow='crisp'] { --squisq-page-shadow: 0 2px 10px color-mix(in srgb, var(--squisq-page-text) 26%, transparent); }
1403
+ .squisq-page[data-shadow='heavy'] { --squisq-page-shadow: 10px 10px 0 color-mix(in srgb, var(--squisq-page-text) 82%, transparent); }
1404
+
1405
+ /* \u2500\u2500 Sections \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1406
+ .squisq-page-section { position: relative; padding-block: var(--squisq-page-section-pad); }
1407
+ .squisq-page-section-inner {
1408
+ max-width: var(--squisq-page-content-max);
1409
+ margin-inline: auto;
1410
+ padding-inline: 24px;
1411
+ }
1412
+ /* Backdrops anchor to the section; these content roots stack above them. */
1413
+ .squisq-page-hero-body,
1414
+ .squisq-page-banner-body,
1415
+ .squisq-page-quote-figure { position: relative; }
1416
+ .squisq-page-section--feature-split .squisq-page-section-inner,
1417
+ .squisq-page-section--gallery .squisq-page-section-inner,
1418
+ .squisq-page-section--table-section .squisq-page-section-inner,
1419
+ .squisq-page-section--canvas-embed .squisq-page-section-inner,
1420
+ .squisq-page-section--stat-band .squisq-page-section-inner,
1421
+ .squisq-page-section--card-grid .squisq-page-section-inner,
1422
+ .squisq-page-section--media-figure .squisq-page-section-inner,
1423
+ .squisq-page-section--hero .squisq-page-section-inner {
1424
+ max-width: var(--squisq-page-wide-max);
1425
+ }
1426
+
1427
+ /* Background rhythm */
1428
+ .squisq-page-section--bg-alternate { background: var(--squisq-page-bg-alt); }
1429
+ .squisq-page-section--bg-accent {
1430
+ background: var(--squisq-page-accent-bg);
1431
+ color: var(--squisq-page-accent-text);
1432
+ }
1433
+ .squisq-page-section--bg-media { color: #ffffff; }
1434
+
1435
+ /* Dividers between adjacent sections */
1436
+ .squisq-page[data-divider='hairline'] .squisq-page-section + .squisq-page-section { border-top: 1px solid var(--squisq-page-divider-color); }
1437
+ .squisq-page[data-divider='thick-rule'] .squisq-page-section + .squisq-page-section { border-top: 3px solid var(--squisq-page-primary); }
1438
+ .squisq-page[data-divider='double-rule'] .squisq-page-section + .squisq-page-section { border-top: 4px double var(--squisq-page-divider-color); }
1439
+ .squisq-page[data-divider='dotted'] .squisq-page-section + .squisq-page-section { border-top: 2px dotted var(--squisq-page-divider-color); }
1440
+ /* Banded sections carry their own edges; media sections never need rules. */
1441
+ .squisq-page .squisq-page-section--bg-media,
1442
+ .squisq-page .squisq-page-section--bg-media + .squisq-page-section,
1443
+ .squisq-page .squisq-page-section--timeline-rail + .squisq-page-section--timeline-rail { border-top: none; }
1444
+
1445
+ /* \u2500\u2500 Headings, eyebrows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1446
+ .squisq-page-section-title {
1447
+ font-family: var(--squisq-page-title-font);
1448
+ font-weight: var(--squisq-page-title-weight);
1449
+ line-height: 1.15;
1450
+ margin: 0 0 0.5em;
1451
+ }
1452
+ .squisq-page[data-heading-case='uppercase'] .squisq-page-section-title { text-transform: uppercase; letter-spacing: 0.03em; }
1453
+ .squisq-page[data-underline='accent-bar'] .squisq-page-section-title::after {
1454
+ content: '';
1455
+ display: block;
1456
+ width: 56px;
1457
+ height: 4px;
1458
+ margin-top: 0.4em;
1459
+ border-radius: 2px;
1460
+ background: var(--squisq-page-accent);
1461
+ }
1462
+ .squisq-page[data-underline='full-rule'] .squisq-page-section-title {
1463
+ border-bottom: 1px solid var(--squisq-page-divider-color);
1464
+ padding-bottom: 0.35em;
1465
+ }
1466
+
1467
+ .squisq-page-eyebrow {
1468
+ display: block;
1469
+ font-size: 0.8125rem;
1470
+ font-weight: 600;
1471
+ letter-spacing: 0.14em;
1472
+ text-transform: uppercase;
1473
+ color: var(--squisq-page-accent);
1474
+ margin: 0 0 0.9em;
1475
+ }
1476
+ .squisq-page[data-eyebrow='numbered'] .squisq-page-eyebrow::after { content: ' \u2014'; color: var(--squisq-page-text-muted); }
1477
+ .squisq-page[data-eyebrow='mono-tag'] .squisq-page-eyebrow {
1478
+ display: inline-block;
1479
+ font-family: var(--squisq-page-mono-font);
1480
+ text-transform: none;
1481
+ letter-spacing: 0.06em;
1482
+ border: 1px solid color-mix(in srgb, var(--squisq-page-accent) 55%, transparent);
1483
+ border-radius: var(--squisq-page-radius);
1484
+ padding: 0.15em 0.6em;
1485
+ background: color-mix(in srgb, var(--squisq-page-accent) 10%, transparent);
1486
+ }
1487
+ .squisq-page[data-eyebrow='mono-tag'] .squisq-page-eyebrow::before { content: '['; opacity: 0.6; }
1488
+ .squisq-page[data-eyebrow='mono-tag'] .squisq-page-eyebrow::after { content: ']'; opacity: 0.6; }
1489
+
1490
+ /* \u2500\u2500 Hero \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1491
+ .squisq-page-section--hero { padding-block: calc(var(--squisq-page-section-pad) * 1.5); }
1492
+ .squisq-page-hero-title {
1493
+ font-family: var(--squisq-page-title-font);
1494
+ font-weight: var(--squisq-page-title-weight);
1495
+ line-height: 1.08;
1496
+ margin: 0;
1497
+ font-size: 2.75rem;
1498
+ }
1499
+ .squisq-page[data-heading-scale='display'] .squisq-page-hero-title { font-size: 3.4rem; }
1500
+ .squisq-page[data-heading-scale='oversized'] .squisq-page-hero-title { font-size: 4rem; font-size: clamp(3rem, 9cqw, 6rem); line-height: 1.02; }
1501
+ .squisq-page[data-heading-case='uppercase'] .squisq-page-hero-title { text-transform: uppercase; letter-spacing: 0.02em; }
1502
+ .squisq-page-hero-subtitle {
1503
+ margin: 1.1em 0 0;
1504
+ font-size: 1.25rem;
1505
+ color: var(--squisq-page-text-muted);
1506
+ max-width: 42em;
1507
+ white-space: pre-line;
1508
+ }
1509
+ .squisq-page-section--bg-media .squisq-page-hero-subtitle { color: rgba(255, 255, 255, 0.88); }
1510
+
1511
+ /* Stacked (default): centered column */
1512
+ .squisq-page[data-hero-style='stacked'] .squisq-page-hero-body { text-align: center; }
1513
+ .squisq-page[data-hero-style='stacked'] .squisq-page-hero-subtitle { margin-inline: auto; }
1514
+
1515
+ /* Oversized type: hard left, no decoration */
1516
+ .squisq-page[data-hero-style='oversized-type'] .squisq-page-hero-title { font-size: 4.25rem; font-size: clamp(3.25rem, 10cqw, 6.5rem); line-height: 0.98; }
1517
+
1518
+ /* Split: text and media side by side */
1519
+ .squisq-page-hero-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 3rem; align-items: center; }
1520
+ .squisq-page-hero-grid .squisq-page-hero-media img { width: 100%; object-fit: cover; }
1521
+
1522
+ /* Full-bleed & letterbox: media behind text */
1523
+ .squisq-page-section--hero-media {
1524
+ padding-block: 0;
1525
+ min-height: min(72svh, 620px);
1526
+ display: flex;
1527
+ align-items: flex-end;
1528
+ }
1529
+ .squisq-page[data-hero-style='letterbox'] .squisq-page-section--hero-media { min-height: min(52svh, 460px); }
1530
+ .squisq-page-hero-backdrop { position: absolute; inset: 0; overflow: hidden; }
1531
+ .squisq-page-hero-backdrop img { width: 100%; height: 100%; object-fit: cover; }
1532
+ .squisq-page-hero-backdrop::after {
1533
+ content: '';
1534
+ position: absolute;
1535
+ inset: 0;
1536
+ background: linear-gradient(180deg, rgba(0, 0, 0, 0.1) 30%, rgba(0, 0, 0, 0.68) 100%);
1537
+ }
1538
+ .squisq-page[data-hero-style='letterbox'] .squisq-page-hero-backdrop img { filter: saturate(0.9); }
1539
+ .squisq-page-section--hero-media .squisq-page-section-inner { padding-block: 3rem; width: 100%; }
1540
+
1541
+ /* \u2500\u2500 Banner (sectionHeader) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1542
+ .squisq-page-banner-title { font-size: 2rem; }
1543
+ .squisq-page[data-heading-scale='display'] .squisq-page-banner-title { font-size: 2.5rem; }
1544
+ .squisq-page[data-heading-scale='oversized'] .squisq-page-banner-title { font-size: 3rem; font-size: clamp(2.25rem, 6cqw, 3.75rem); }
1545
+ .squisq-page-section--banner.squisq-page-section--bg-media { padding-block: 0; min-height: 280px; display: flex; align-items: flex-end; }
1546
+ .squisq-page-section--banner.squisq-page-section--bg-media .squisq-page-section-inner { padding-block: 2rem; width: 100%; }
1547
+ .squisq-page-section--banner .squisq-page-section-title { margin-bottom: 0; }
1548
+
1549
+ /* \u2500\u2500 Stat band \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1550
+ .squisq-page-stats { display: flex; gap: 3rem; justify-content: center; text-align: center; flex-wrap: wrap; }
1551
+ .squisq-page-stat { flex: 1 1 220px; max-width: 420px; }
1552
+ .squisq-page-stat-value {
1553
+ display: block;
1554
+ font-family: var(--squisq-page-title-font);
1555
+ font-weight: 700;
1556
+ font-size: 3.25rem;
1557
+ line-height: 1;
1558
+ color: var(--squisq-page-accent);
1559
+ }
1560
+ .squisq-page[data-numerals='oversized'] .squisq-page-stat-value { font-size: 4.5rem; font-size: clamp(3.5rem, 8cqw, 5.5rem); }
1561
+ .squisq-page[data-numerals='mono'] .squisq-page-stat-value { font-family: var(--squisq-page-mono-font); letter-spacing: -0.02em; }
1562
+ .squisq-page[data-numerals='boxed'] .squisq-page-stat-value {
1563
+ display: inline-block;
1564
+ border: 2px solid var(--squisq-page-accent);
1565
+ border-radius: var(--squisq-page-radius);
1566
+ padding: 0.18em 0.4em;
1567
+ }
1568
+ .squisq-page-stat-title { display: block; margin-top: 0.9em; font-size: 1.125rem; font-weight: 600; }
1569
+ .squisq-page-stat-body { display: block; margin-top: 0.45em; color: var(--squisq-page-text-muted); font-size: 0.95rem; }
1570
+ .squisq-page-stat-meta { text-align: center; margin-top: 1.5rem; color: var(--squisq-page-text-muted); font-size: 0.85rem; }
1571
+ .squisq-page-stat-bar { height: 10px; border-radius: 999px; background: var(--squisq-page-accent); margin-top: 0.8em; }
1572
+ .squisq-page-stat--bars { text-align: left; }
1573
+
1574
+ /* \u2500\u2500 Quote band \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1575
+ .squisq-page-quote {
1576
+ margin: 0;
1577
+ font-family: var(--squisq-page-title-font);
1578
+ font-size: 1.6rem;
1579
+ line-height: 1.35;
1580
+ white-space: pre-line;
1581
+ }
1582
+ .squisq-page-section--em-strong .squisq-page-quote { font-size: 2.1rem; }
1583
+ .squisq-page-section--em-quiet .squisq-page-quote { font-size: 1.25rem; color: var(--squisq-page-text-muted); }
1584
+ .squisq-page-quote-attribution { margin-top: 1.1em; font-family: var(--squisq-page-body-font); font-size: 0.95rem; color: var(--squisq-page-text-muted); }
1585
+ .squisq-page-quote-attribution::before { content: '\u2014 '; }
1586
+ .squisq-page[data-quote-mark='accent-bar'] .squisq-page-quote-figure { border-left: 4px solid var(--squisq-page-accent); padding-left: 1.5rem; }
1587
+ .squisq-page[data-quote-mark='oversized-glyph'] .squisq-page-quote-figure { position: relative; padding-top: 1.25rem; }
1588
+ .squisq-page[data-quote-mark='oversized-glyph'] .squisq-page-quote-figure::before {
1589
+ content: '\\201C';
1590
+ position: absolute;
1591
+ top: -0.12em;
1592
+ left: -0.05em;
1593
+ font-family: var(--squisq-page-title-font);
1594
+ font-size: 5.5rem;
1595
+ line-height: 1;
1596
+ color: color-mix(in srgb, var(--squisq-page-accent) 42%, transparent);
1597
+ pointer-events: none;
1598
+ }
1599
+ .squisq-page-section--v-display .squisq-page-quote-figure { text-align: center; border-left: none; }
1600
+ .squisq-page-section--v-display .squisq-page-quote { font-size: 2.4rem; font-size: clamp(1.9rem, 5cqw, 3rem); }
1601
+ .squisq-page-section--v-editorial .squisq-page-quote-figure {
1602
+ border-block: 3px solid var(--squisq-page-primary);
1603
+ border-left: none;
1604
+ padding: 2rem 0.5rem;
1605
+ }
1606
+ /* Full-bleed quote over media */
1607
+ .squisq-page-section--quote-band.squisq-page-section--bg-media { padding-block: 0; min-height: 380px; display: flex; align-items: center; }
1608
+ .squisq-page-section--quote-band.squisq-page-section--bg-media .squisq-page-section-inner { padding-block: 3.5rem; }
1609
+ .squisq-page-quote-backdrop { position: absolute; inset: 0; overflow: hidden; }
1610
+ .squisq-page-quote-backdrop img, .squisq-page-quote-backdrop video { width: 100%; height: 100%; object-fit: cover; }
1611
+ .squisq-page-quote-backdrop::after { content: ''; position: absolute; inset: 0; background: rgba(0, 0, 0, 0.55); }
1612
+ .squisq-page-section--quote-band[data-hint-vignette] .squisq-page-quote-backdrop::after {
1613
+ background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.35) 0%, rgba(0, 0, 0, 0.75) 100%);
1614
+ }
1615
+ .squisq-page-section--quote-band.squisq-page-section--bg-media .squisq-page-quote-figure { border: none; text-align: center; }
1616
+
1617
+ /* \u2500\u2500 Feature split \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1618
+ .squisq-page-feature { display: grid; grid-template-columns: 1fr 1fr; gap: 3rem; align-items: center; }
1619
+ .squisq-page-feature--media-right .squisq-page-feature-media { order: 2; }
1620
+ .squisq-page-feature-media img { width: 100%; object-fit: cover; }
1621
+ .squisq-page-feature-title { font-size: 1.75rem; }
1622
+ .squisq-page-feature-body { color: var(--squisq-page-text-muted); font-size: 1.05rem; white-space: pre-line; margin: 0; }
1623
+
1624
+ /* \u2500\u2500 Media figure \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1625
+ .squisq-page-figure { margin: 0; }
1626
+ .squisq-page-figure img, .squisq-page-figure video { width: 100%; display: block; }
1627
+ .squisq-page-figure figcaption { margin-top: 0.9em; font-size: 0.9rem; color: var(--squisq-page-text-muted); text-align: center; }
1628
+ .squisq-page-media-credit { font-size: 0.78rem; opacity: 0.75; }
1629
+
1630
+ /* Media frame treatment (figures, features, gallery tiles, cards) */
1631
+ .squisq-page-media-frame { overflow: hidden; }
1632
+ .squisq-page[data-framing='rounded'] .squisq-page-media-frame { border-radius: var(--squisq-page-radius); }
1633
+ .squisq-page[data-framing='bordered'] .squisq-page-media-frame { border: 3px solid var(--squisq-page-text); }
1634
+ .squisq-page[data-framing='polaroid'] .squisq-page-media-frame {
1635
+ background: #ffffff;
1636
+ padding: 10px 10px 16px;
1637
+ border: 1px solid rgba(0, 0, 0, 0.12);
1638
+ border-radius: 2px;
1639
+ }
1640
+ .squisq-page[data-framing='letterboxed'] .squisq-page-media-frame img { aspect-ratio: 21 / 9; object-fit: cover; }
1641
+ .squisq-page[data-framing='circle-accent'] .squisq-page-media-frame { border-radius: calc(var(--squisq-page-radius) * 2); }
1642
+ .squisq-page .squisq-page-media-frame { box-shadow: var(--squisq-page-shadow); }
1643
+
1644
+ /* Rich body nodes that the selected template did not consume. This universal
1645
+ * supplement keeps diagrams/media visible without making every template
1646
+ * duplicate the same preservation logic. */
1647
+ .squisq-page-rich-content {
1648
+ margin-top: clamp(1.5rem, 4vw, 3rem);
1649
+ padding-top: clamp(1.25rem, 3vw, 2rem);
1650
+ border-top: 1px solid var(--squisq-page-divider-color);
1651
+ }
1652
+ .squisq-page-rich-content :is(img, video) { display: block; max-width: 100%; height: auto; margin-inline: auto; }
1653
+ .squisq-page-rich-content .squisq-md-mermaid { min-height: min(520px, 62vh); margin-block: 0; }
1654
+
1655
+ /* \u2500\u2500 Gallery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1656
+ .squisq-page-gallery { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1.25rem; }
1657
+ .squisq-page-gallery .squisq-page-media-frame img { width: 100%; height: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
1658
+ .squisq-page-gallery-caption { margin-top: 1.1rem; text-align: center; font-size: 0.9rem; color: var(--squisq-page-text-muted); }
1659
+
1660
+ /* \u2500\u2500 Callout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1661
+ .squisq-page-callout {
1662
+ border-radius: var(--squisq-page-radius);
1663
+ border: 1px solid color-mix(in srgb, var(--squisq-page-accent) 32%, transparent);
1664
+ border-left: 5px solid var(--squisq-page-accent);
1665
+ background: color-mix(in srgb, var(--squisq-page-accent) 7%, var(--squisq-page-bg));
1666
+ padding: 1.75rem 2rem;
1667
+ box-shadow: var(--squisq-page-shadow);
1668
+ display: flex;
1669
+ gap: 1.75rem;
1670
+ align-items: flex-start;
1671
+ }
1672
+ .squisq-page-callout-title { font-family: var(--squisq-page-title-font); font-size: 1.35rem; font-weight: 700; margin: 0 0 0.5em; }
1673
+ .squisq-page-callout-body { margin: 0; white-space: pre-line; }
1674
+ .squisq-page-callout-meta { margin-top: 0.9em; font-size: 0.82rem; color: var(--squisq-page-text-muted); }
1675
+ .squisq-page-callout .squisq-page-media-frame { flex: 0 0 132px; }
1676
+ .squisq-page-callout .squisq-page-media-frame img { width: 132px; height: 132px; object-fit: cover; }
1677
+ .squisq-page-callout[data-hint-framing='circle-accent'] .squisq-page-media-frame,
1678
+ .squisq-page-callout[data-hint-framing='circle-accent'] .squisq-page-media-frame img { border-radius: 50%; }
1679
+ .squisq-page-section--v-definition .squisq-page-callout-title { font-style: italic; }
1680
+ .squisq-page-section--v-diagnostic .squisq-page-callout { border-left-color: var(--squisq-page-highlight); }
1681
+
1682
+ /* \u2500\u2500 Card grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1683
+ .squisq-page-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1.5rem; }
1684
+ .squisq-page-card {
1685
+ border-radius: var(--squisq-page-radius);
1686
+ background: var(--squisq-page-bg-alt);
1687
+ border-top: 4px solid var(--squisq-page-card-accent, var(--squisq-page-accent));
1688
+ padding: 1.75rem 1.75rem 1.9rem;
1689
+ box-shadow: var(--squisq-page-shadow);
1690
+ }
1691
+ .squisq-page-card-title { font-family: var(--squisq-page-title-font); font-size: 1.3rem; margin: 0 0 0.4em; }
1692
+ .squisq-page-card-body { margin: 0; color: var(--squisq-page-text-muted); white-space: pre-line; }
1693
+ .squisq-page-cards-title { text-align: center; font-size: 1.9rem; margin-bottom: 1.75rem; }
1694
+
1695
+ /* \u2500\u2500 Item list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1696
+ .squisq-page-items { list-style: none; margin: 0; padding: 0; counter-reset: squisq-item; max-width: 40em; }
1697
+ .squisq-page-items li {
1698
+ counter-increment: squisq-item;
1699
+ position: relative;
1700
+ padding: 0.9em 0 0.9em 3.4em;
1701
+ font-size: 1.1rem;
1702
+ }
1703
+ .squisq-page-items li + li { border-top: 1px solid var(--squisq-page-divider-color); }
1704
+ .squisq-page-items li::before {
1705
+ content: counter(squisq-item, decimal-leading-zero);
1706
+ position: absolute;
1707
+ left: 0;
1708
+ top: 0.85em;
1709
+ font-family: var(--squisq-page-title-font);
1710
+ font-weight: 700;
1711
+ color: var(--squisq-page-accent);
1712
+ font-size: 1.15em;
1713
+ }
1714
+ .squisq-page[data-numerals='mono'] .squisq-page-items li::before { font-family: var(--squisq-page-mono-font); }
1715
+ .squisq-page-items-title { font-size: 1.9rem; }
1716
+
1717
+ /* \u2500\u2500 Timeline rail (dateEvent) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1718
+ .squisq-page-section--timeline-rail { padding-block: 1.4rem; }
1719
+ .squisq-page-section--timeline-rail:first-child { padding-top: var(--squisq-page-section-pad); }
1720
+ .squisq-page-milestone { display: grid; grid-template-columns: 150px 1fr; gap: 2rem; align-items: baseline; position: relative; }
1721
+ .squisq-page-milestone-date {
1722
+ font-family: var(--squisq-page-title-font);
1723
+ font-weight: 700;
1724
+ color: var(--squisq-page-accent);
1725
+ font-size: 1.05rem;
1726
+ text-align: right;
1727
+ }
1728
+ .squisq-page-milestone-rail {
1729
+ position: absolute;
1730
+ left: 166px;
1731
+ top: -1.4rem;
1732
+ bottom: -1.4rem;
1733
+ width: 2px;
1734
+ background: color-mix(in srgb, var(--squisq-page-accent) 35%, transparent);
1735
+ }
1736
+ .squisq-page-milestone-rail::after {
1737
+ content: '';
1738
+ position: absolute;
1739
+ left: 50%;
1740
+ top: 0.55em;
1741
+ width: 12px;
1742
+ height: 12px;
1743
+ border-radius: 50%;
1744
+ transform: translateX(-50%);
1745
+ background: var(--squisq-page-accent);
1746
+ border: 2px solid var(--squisq-page-bg);
1747
+ }
1748
+ .squisq-page-milestone-body { padding-left: 2.25rem; white-space: pre-line; }
1749
+ .squisq-page-milestone-footer { margin-top: 0.5em; font-size: 0.85rem; color: var(--squisq-page-text-muted); }
1750
+
1751
+ /* \u2500\u2500 Table section \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1752
+ .squisq-page-table-title { font-size: 1.9rem; }
1753
+ .squisq-page-table-scroll { overflow-x: auto; border-radius: var(--squisq-page-radius); box-shadow: var(--squisq-page-shadow); }
1754
+ .squisq-page-table { width: 100%; border-collapse: collapse; font-size: 0.98rem; }
1755
+ .squisq-page-table th {
1756
+ background: var(--squisq-page-accent-bg);
1757
+ color: var(--squisq-page-accent-text);
1758
+ font-family: var(--squisq-page-title-font);
1759
+ text-align: left;
1760
+ padding: 0.8em 1em;
1761
+ }
1762
+ .squisq-page-table td { padding: 0.7em 1em; border-top: 1px solid var(--squisq-page-divider-color); }
1763
+ .squisq-page-table tbody tr:nth-child(even) { background: color-mix(in srgb, var(--squisq-page-text) 3.5%, transparent); }
1764
+
1765
+ /* \u2500\u2500 Canvas embed (spatial SVG) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1766
+ .squisq-page-canvas {
1767
+ width: 100%;
1768
+ margin-inline: auto;
1769
+ overflow: hidden;
1770
+ border-radius: var(--squisq-page-radius);
1771
+ }
1772
+ .squisq-page-canvas svg { display: block; width: 100%; height: 100%; }
1773
+ .squisq-page-canvas--framed { border: 1px solid var(--squisq-page-divider-color); box-shadow: var(--squisq-page-shadow); }
1774
+ .squisq-page-canvas--terminal { border: 1px solid color-mix(in srgb, var(--squisq-page-accent) 45%, transparent); }
1775
+ .squisq-page-canvas--terminal::before {
1776
+ content: '\\25CF \\25CF \\25CF';
1777
+ display: block;
1778
+ font-size: 9px;
1779
+ letter-spacing: 4px;
1780
+ padding: 6px 12px;
1781
+ color: color-mix(in srgb, var(--squisq-page-accent) 70%, transparent);
1782
+ background: color-mix(in srgb, var(--squisq-page-accent) 9%, var(--squisq-page-bg));
1783
+ border-bottom: 1px solid color-mix(in srgb, var(--squisq-page-accent) 30%, transparent);
1784
+ }
1785
+
1786
+ /* \u2500\u2500 Prose \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1787
+ .squisq-page-section--prose { padding-block: calc(var(--squisq-page-section-pad) * 0.45); }
1788
+ .squisq-page[data-divider] .squisq-page-section--prose + .squisq-page-section--prose { border-top: none; }
1789
+ .squisq-page-prose { font-size: 1.05rem; }
1790
+ .squisq-page-prose p { margin: 0; }
1791
+ .squisq-page-prose p + p { margin-top: 1.25em; }
1792
+ .squisq-page-prose > * + * { margin-top: 1.1em; }
1793
+ .squisq-page-prose a { color: var(--squisq-page-primary); text-decoration-color: color-mix(in srgb, var(--squisq-page-primary) 40%, transparent); }
1794
+ .squisq-page-prose code { font-family: var(--squisq-page-mono-font); font-size: 0.9em; background: color-mix(in srgb, var(--squisq-page-text) 8%, transparent); border-radius: 4px; padding: 0.12em 0.35em; }
1795
+ .squisq-page-prose pre { background: color-mix(in srgb, var(--squisq-page-text) 6%, transparent); border-radius: var(--squisq-page-radius); padding: 1em 1.25em; overflow-x: auto; }
1796
+ .squisq-page-prose pre code { background: none; padding: 0; }
1797
+ .squisq-page-prose blockquote { margin: 0; border-left: 4px solid var(--squisq-page-accent); padding-left: 1.25em; color: var(--squisq-page-text-muted); }
1798
+ .squisq-page-prose ul, .squisq-page-prose ol { padding-left: 1.5em; margin: 0; }
1799
+ .squisq-page-prose li + li { margin-top: 0.4em; }
1800
+ .squisq-page-prose hr { border: none; border-top: 1px solid var(--squisq-page-divider-color); }
1801
+ .squisq-page-prose table { width: 100%; border-collapse: collapse; }
1802
+ .squisq-page-prose th { font-family: var(--squisq-page-title-font); text-align: left; padding: 0.6em 0.8em; border-bottom: 2px solid var(--squisq-page-divider-color); }
1803
+ .squisq-page-prose td { padding: 0.55em 0.8em; border-bottom: 1px solid var(--squisq-page-divider-color); }
1804
+ .squisq-page-prose img { border-radius: var(--squisq-page-radius); }
1805
+ .squisq-page-prose h1, .squisq-page-prose h2, .squisq-page-prose h3,
1806
+ .squisq-page-prose h4, .squisq-page-prose h5, .squisq-page-prose h6 {
1807
+ font-family: var(--squisq-page-title-font);
1808
+ font-weight: var(--squisq-page-title-weight);
1809
+ line-height: 1.2;
1810
+ margin: 0 0 0.45em;
1811
+ }
1812
+ .squisq-page-prose h1 { font-size: 2.1rem; }
1813
+ .squisq-page-prose h2 { font-size: 1.65rem; }
1814
+ .squisq-page-prose h3 { font-size: 1.35rem; }
1815
+ .squisq-page-prose h4, .squisq-page-prose h5, .squisq-page-prose h6 { font-size: 1.15rem; }
1816
+ .squisq-page-section--prose[data-hint-drop-cap] .squisq-page-prose > p:first-child::first-letter {
1817
+ font-family: var(--squisq-page-title-font);
1818
+ font-size: 3.4em;
1819
+ font-weight: 700;
1820
+ float: left;
1821
+ line-height: 0.85;
1822
+ padding-right: 0.12em;
1823
+ color: var(--squisq-page-accent);
1824
+ }
1825
+
1826
+ /* \u2500\u2500 Footer band \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1827
+ .squisq-page-section--footer { text-align: center; }
1828
+
1829
+ /* \u2500\u2500 Thin-margin embedding (chat bubbles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1830
+ .squisq-page--thin .squisq-page-section-inner { padding-inline: 0; }
1831
+ .squisq-page--thin .squisq-page-section { padding-block: 1.5rem; }
1832
+
1833
+ /* Thumbnail image mode */
1834
+ .squisq-page--thumbnail-images .squisq-page-prose img,
1835
+ .squisq-page--thumbnail-images .squisq-page-figure img { max-width: 100px; max-height: 100px; object-fit: cover; }
1836
+
1837
+ /* \u2500\u2500 Reveal animation (progressive enhancement) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1838
+ @media (prefers-reduced-motion: no-preference) {
1839
+ .squisq-page-reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.55s ease, transform 0.55s ease; }
1840
+ .squisq-page-reveal--in { opacity: 1; transform: none; }
1841
+ }
1842
+
1843
+ /* \u2500\u2500 Responsive \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
1844
+ @container squisq-page (max-width: 720px) {
1845
+ ${NARROW_RULES}
1846
+ }
1847
+ @supports not (container-type: inline-size) {
1848
+ @media (max-width: 720px) {
1849
+ ${NARROW_RULES}
1850
+ }
1851
+ }
1852
+ `;
1853
+ function buildPageCss(theme) {
1854
+ const vars = buildPageCssVars(theme);
1855
+ const varLines = Object.entries(vars).map(([name, value]) => ` ${name}: ${value};`).join("\n");
1856
+ return `.squisq-page {
1857
+ ${varLines}
1858
+ }
1859
+ ${PAGE_BASE_CSS}`;
1860
+ }
1861
+
482
1862
  // src/doc/applyNarrationTiming.ts
483
1863
  var MIN_BLOCK_SIMILARITY = 0.5;
484
1864
  var MIN_V1_SCRIPT_SIMILARITY = 0.8;
485
1865
  var PIN_CONFLICT_TOLERANCE_SEC = 1;
486
1866
  function blockSpokenText(block) {
487
- const title = block.title ? block.title.trim() : "";
1867
+ const title2 = block.title ? block.title.trim() : "";
488
1868
  const body = getBlockBodyText(block);
489
- if (title && body) return `${title}
1869
+ if (title2 && body) return `${title2}
490
1870
  ${body}`;
491
- return title || body;
1871
+ return title2 || body;
492
1872
  }
493
1873
  function matchSidecarBlocks(flat, timing) {
494
1874
  const ranges = /* @__PURE__ */ new Map();
@@ -716,10 +2096,11 @@ async function discoverNarrationAudio(container) {
716
2096
  let timing = null;
717
2097
  if (consolidatedSections) {
718
2098
  const audioBase = stripAudioExtension(filename);
2099
+ let matchedName = "";
719
2100
  for (const [sectionName, sectionTiming] of Object.entries(consolidatedSections)) {
720
- if (audioBase.endsWith(`-${sectionName}`)) {
2101
+ if (audioBase.endsWith(`-${sectionName}`) && sectionName.length > matchedName.length) {
2102
+ matchedName = sectionName;
721
2103
  timing = sectionTiming;
722
- break;
723
2104
  }
724
2105
  }
725
2106
  }
@@ -1131,8 +2512,8 @@ function checkAssets(markdownDoc, blocks, hasAsset, diagnostics) {
1131
2512
  }
1132
2513
  }
1133
2514
  const images = source["images"];
1134
- const list = typeof images === "string" ? images.split(",").map((s) => s.trim()) : Array.isArray(images) ? images.filter((i) => typeof i === "string") : [];
1135
- for (const img of list) {
2515
+ const list2 = typeof images === "string" ? images.split(",").map((s) => s.trim()) : Array.isArray(images) ? images.filter((i) => typeof i === "string") : [];
2516
+ for (const img of list2) {
1136
2517
  report(img, block.sourceHeading?.position?.start.line, block.id);
1137
2518
  }
1138
2519
  }
@@ -1156,17 +2537,28 @@ function truncate(text, max = 40) {
1156
2537
  }
1157
2538
 
1158
2539
  // src/doc/asciiDiagram/render.ts
2540
+ function normalizeLabelLines(label) {
2541
+ return label.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
2542
+ }
2543
+ function normalizeEdgeLabel(label) {
2544
+ if (label === void 0) return void 0;
2545
+ const collapsed = label.replace(/\s+/gu, " ").trim();
2546
+ return collapsed.length > 0 ? collapsed : void 0;
2547
+ }
2548
+ function edgeLabelFitsBridge(text) {
2549
+ return text.length <= MAX_BRIDGE_GAP;
2550
+ }
1159
2551
  var SIDE_MARGIN = 1;
1160
- function renderAsciiDiagram(diagram, options = {}) {
1161
- const vocab = (options.style ?? diagram.style) === "ascii" ? ASCII_VOCAB : UNICODE_VOCAB;
1162
- if (diagram.nodes.length === 0) return "";
1163
- const placed = layoutNodes(diagram.nodes, diagram.edges);
2552
+ function renderAsciiDiagram(diagram2, options = {}) {
2553
+ const vocab = (options.style ?? diagram2.style) === "ascii" ? ASCII_VOCAB : UNICODE_VOCAB;
2554
+ if (diagram2.nodes.length === 0) return "";
2555
+ const placed = layoutNodes(diagram2.nodes, diagram2.edges);
1164
2556
  const canvas = new Canvas();
1165
2557
  const drawOrder = [...placed.values()].sort(
1166
2558
  (a, b) => a.depth - b.depth || a.rect.r0 - b.rect.r0 || a.rect.c0 - b.rect.c0
1167
2559
  );
1168
2560
  for (const p of drawOrder) drawBox(canvas, p, vocab);
1169
- drawEdges(canvas, diagram.edges, placed, vocab);
2561
+ drawEdges(canvas, diagram2.edges, placed, vocab);
1170
2562
  return canvas.emit();
1171
2563
  }
1172
2564
  function computeSideDegrees(nodes, edges) {
@@ -1197,9 +2589,9 @@ function layoutNodes(nodes, edges) {
1197
2589
  const roots = [];
1198
2590
  for (const node of nodes) {
1199
2591
  if (node.containerId && byId.has(node.containerId) && node.containerId !== node.id) {
1200
- const list = childIds.get(node.containerId) ?? [];
1201
- list.push(node.id);
1202
- childIds.set(node.containerId, list);
2592
+ const list2 = childIds.get(node.containerId) ?? [];
2593
+ list2.push(node.id);
2594
+ childIds.set(node.containerId, list2);
1203
2595
  } else {
1204
2596
  roots.push(node.id);
1205
2597
  }
@@ -1239,10 +2631,10 @@ function layoutNodes(nodes, edges) {
1239
2631
  };
1240
2632
  const layoutSubtree = (id, depth) => {
1241
2633
  const node = byId.get(id);
1242
- const labelLines = node.label.length > 0 ? node.label.split("\n") : [];
2634
+ const labelLines = normalizeLabelLines(node.label);
1243
2635
  const children = childIds.get(id) ?? [];
1244
2636
  if (children.length === 0) {
1245
- const innerW = labelLines.reduce((w, l) => Math.max(w, l.length), 0);
2637
+ const innerW = labelLines.reduce((w, l) => Math.max(w, cellWidth(l)), 0);
1246
2638
  const deg = sideDeg.get(id) ?? { top: 0, bottom: 0, left: 0, right: 0 };
1247
2639
  const horizDeg = Math.max(deg.top, deg.bottom);
1248
2640
  const vertDeg = Math.max(deg.left, deg.right);
@@ -1265,14 +2657,15 @@ function layoutNodes(nodes, edges) {
1265
2657
  const childRects = placeSiblings(children, (childId) => layoutSubtree(childId, depth + 1));
1266
2658
  const bbox = unionRects(childRects);
1267
2659
  const extraRows = Math.max(0, labelLines.length - 1);
1268
- const titleLen = (labelLines[0] ?? "").length;
2660
+ const titleLen = cellWidth(labelLines[0] ?? "");
1269
2661
  const rect = {
1270
2662
  r0: bbox.r0 - 2 - extraRows,
1271
2663
  c0: bbox.c0 - 2,
1272
2664
  r1: bbox.r1 + 2,
1273
2665
  c1: bbox.c1 + 2
1274
2666
  };
1275
- const minW = titleLen > 0 ? titleLen + 6 : 3;
2667
+ const innerLinesW = labelLines.slice(1).reduce((w, l) => Math.max(w, cellWidth(l)), 0);
2668
+ const minW = Math.max(titleLen > 0 ? titleLen + 6 : 3, innerLinesW > 0 ? innerLinesW + 4 : 3);
1276
2669
  if (rect.c1 - rect.c0 + 1 < minW) rect.c1 = rect.c0 + minW - 1;
1277
2670
  if (rect.c1 - rect.c0 + 1 < node.wCols) rect.c1 = rect.c0 + node.wCols - 1;
1278
2671
  placed.set(id, { node, rect, labelLines, isContainer: true, depth });
@@ -1366,12 +2759,12 @@ function drawBox(canvas, p, vocab) {
1366
2759
  const innerW = rect.c1 - rect.c0 - 1;
1367
2760
  canvas.set(rect.r0, rect.c0, vocab.tl, "border");
1368
2761
  canvas.set(rect.r0, rect.c1, vocab.tr, "border");
1369
- const title = isContainer && labelLines.length > 0 ? ` ${labelLines[0]} ` : null;
1370
- if (title && title.length <= innerW - 2) {
1371
- const left = Math.floor((innerW - title.length) / 2);
2762
+ const title2 = isContainer && labelLines.length > 0 ? toCells(` ${labelLines[0]} `) : null;
2763
+ if (title2 && title2.length <= innerW - 2) {
2764
+ const left = Math.floor((innerW - title2.length) / 2);
1372
2765
  for (let i = 0; i < innerW; i++) {
1373
- const inTitle = i >= left && i < left + title.length;
1374
- const ch = inTitle ? title[i - left] : vocab.h;
2766
+ const inTitle = i >= left && i < left + title2.length;
2767
+ const ch = inTitle ? title2[i - left] : vocab.h;
1375
2768
  canvas.set(rect.r0, rect.c0 + 1 + i, ch, inTitle ? "label" : "border");
1376
2769
  }
1377
2770
  } else {
@@ -1389,9 +2782,10 @@ function drawBox(canvas, p, vocab) {
1389
2782
  const innerH = rect.r1 - rect.r0 - 1;
1390
2783
  const startRow = isContainer ? rect.r0 + 1 : rect.r0 + 1 + Math.max(0, Math.floor((innerH - interiorLines.length) / 2));
1391
2784
  interiorLines.forEach((line, i) => {
1392
- const pad = Math.max(0, Math.floor((innerW - line.length) / 2));
1393
- for (let j = 0; j < line.length && pad + j < innerW; j++) {
1394
- canvas.set(startRow + i, rect.c0 + 1 + pad + j, line[j], "label");
2785
+ const cells = toCells(line);
2786
+ const pad = Math.max(0, Math.floor((innerW - cells.length) / 2));
2787
+ for (let j = 0; j < cells.length && pad + j < innerW; j++) {
2788
+ canvas.set(startRow + i, rect.c0 + 1 + pad + j, cells[j], "label");
1395
2789
  }
1396
2790
  });
1397
2791
  }
@@ -1443,24 +2837,25 @@ function drawEdges(canvas, edges, placed, vocab) {
1443
2837
  )
1444
2838
  );
1445
2839
  for (const req of sideLabelRequests) {
2840
+ const cells = toCells(req.label);
1446
2841
  let done = false;
1447
2842
  for (const side of ["right", "left"]) {
1448
2843
  if (done) break;
1449
2844
  for (const { row, col } of req.candidates) {
1450
2845
  if (canvas.kindAt(row, col) !== "line-v") continue;
1451
- const startCol = side === "right" ? col + 2 : col - 1 - req.label.length;
2846
+ const startCol = side === "right" ? col + 2 : col - 1 - cells.length;
1452
2847
  if (startCol < 0) continue;
1453
2848
  const gapCol = side === "right" ? col + 1 : col - 1;
1454
2849
  let free = canvas.kindAt(row, gapCol) === "empty";
1455
- for (let i = 0; free && i < req.label.length; i++) {
2850
+ for (let i = 0; free && i < cells.length; i++) {
1456
2851
  if (canvas.kindAt(row, startCol + i) !== "empty") free = false;
1457
2852
  }
1458
2853
  if (free && side === "left" && startCol > 0) {
1459
2854
  free = canvas.kindAt(row, startCol - 1) === "empty";
1460
2855
  }
1461
2856
  if (!free) continue;
1462
- for (let i = 0; i < req.label.length; i++) {
1463
- canvas.set(row, startCol + i, req.label[i], "label");
2857
+ for (let i = 0; i < cells.length; i++) {
2858
+ canvas.set(row, startCol + i, cells[i], "label");
1464
2859
  }
1465
2860
  done = true;
1466
2861
  break;
@@ -1497,10 +2892,10 @@ function assignAttachments(plans, placed) {
1497
2892
  ]);
1498
2893
  });
1499
2894
  const result = /* @__PURE__ */ new Map();
1500
- for (const [sideKey, list] of [...bySide.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
2895
+ for (const [sideKey, list2] of [...bySide.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
1501
2896
  const [nodeId, side] = sideKey.split("|");
1502
2897
  const node = placed.get(nodeId);
1503
- list.sort((a, b) => {
2898
+ list2.sort((a, b) => {
1504
2899
  const ra = placed.get(a.otherId).rect;
1505
2900
  const rb = placed.get(b.otherId).rect;
1506
2901
  return ra.r0 - rb.r0 || ra.c0 - rb.c0 || a.otherId.localeCompare(b.otherId);
@@ -1509,13 +2904,13 @@ function assignAttachments(plans, placed) {
1509
2904
  const from = horizontal ? node.rect.c0 + 1 : node.rect.r0 + 1;
1510
2905
  const to = horizontal ? node.rect.c1 - 1 : node.rect.r1 - 1;
1511
2906
  const inner = Math.max(1, to - from + 1);
1512
- const k = list.length;
2907
+ const k = list2.length;
1513
2908
  if (k === 1) {
1514
- result.set(list[0].key, { pos: from + Math.floor((inner - 1) / 2), index: 0, count: 1 });
2909
+ result.set(list2[0].key, { pos: from + Math.floor((inner - 1) / 2), index: 0, count: 1 });
1515
2910
  } else {
1516
2911
  const span = 2 * k - 1;
1517
2912
  const start = from + Math.max(0, Math.floor((inner - span) / 2));
1518
- list.forEach((req, i) => {
2913
+ list2.forEach((req, i) => {
1519
2914
  result.set(req.key, { pos: Math.min(to, start + 2 * i), index: i, count: k });
1520
2915
  });
1521
2916
  }
@@ -1539,7 +2934,7 @@ function routeEdge(canvas, plan, planIdx, placed, attachment, vocab, deferSideLa
1539
2934
  canvas,
1540
2935
  directed: plan.edge.directed,
1541
2936
  biDir: plan.biDir,
1542
- label: plan.edge.label,
2937
+ label: normalizeEdgeLabel(plan.edge.label),
1543
2938
  vocab,
1544
2939
  junction,
1545
2940
  stagger,
@@ -1637,8 +3032,8 @@ function drawVertical(args, s, t, exitCol, enterCol, dir) {
1637
3032
  const hi = Math.max(exitCol, enterCol);
1638
3033
  let segment = [];
1639
3034
  for (let c = lo + 1; c <= hi - 1; c++) segment.push(vocab.h);
1640
- if (label && segment.length >= label.length + 4) {
1641
- const text = ` ${label} `;
3035
+ const text = label ? toCells(` ${label} `) : null;
3036
+ if (text && edgeLabelFitsBridge(text) && segment.length >= text.length + 2) {
1642
3037
  const left = Math.floor((segment.length - text.length) / 2);
1643
3038
  segment = segment.map((ch, i) => i >= left && i < left + text.length ? text[i - left] : ch);
1644
3039
  labelEmbedded = true;
@@ -1693,15 +3088,22 @@ function drawHorizontal(args, s, t, exitRow, enterRow, dir) {
1693
3088
  const firstFree = exitCol + dir;
1694
3089
  const lastFree = enterCol - dir;
1695
3090
  const gap = (lastFree - firstFree) * dir + 1;
1696
- const drawH = (row, cA, cB, hostLabel) => {
3091
+ const drawH = (row, cA, cB, hostLabel, reserveLo = 0, reserveHi = 0) => {
1697
3092
  const lo = Math.min(cA, cB);
1698
3093
  const hi = Math.max(cA, cB);
1699
3094
  let segment = [];
1700
3095
  for (let c = lo; c <= hi; c++) segment.push(vocab.h);
1701
- if (hostLabel && label && segment.length >= label.length + 4) {
1702
- const text = ` ${label} `;
1703
- const left = Math.floor((segment.length - text.length) / 2);
1704
- segment = segment.map((ch, i) => i >= left && i < left + text.length ? text[i - left] : ch);
3096
+ const text = hostLabel && label ? toCells(` ${label} `) : null;
3097
+ if (text && edgeLabelFitsBridge(text)) {
3098
+ const from = reserveLo;
3099
+ const to = segment.length - 1 - reserveHi;
3100
+ const room = to - from + 1;
3101
+ if (room >= text.length + 2) {
3102
+ const left = from + Math.floor((room - text.length) / 2);
3103
+ segment = segment.map(
3104
+ (ch, i) => i >= left && i < left + text.length ? text[i - left] : ch
3105
+ );
3106
+ }
1705
3107
  }
1706
3108
  segment.forEach((ch, i) => {
1707
3109
  canvas.drawEdgeCell(row, lo + i, ch, ch === vocab.h ? "line-h" : "label", vocab);
@@ -1714,7 +3116,14 @@ function drawHorizontal(args, s, t, exitRow, enterRow, dir) {
1714
3116
  junction(sRow, exitCol, dir === 1 ? "right" : "left");
1715
3117
  junction(tRow, enterCol, dir === 1 ? "left" : "right");
1716
3118
  if (sRow === tRow && gap >= 1) {
1717
- drawH(sRow, firstFree, lastFree, true);
3119
+ drawH(
3120
+ sRow,
3121
+ firstFree,
3122
+ lastFree,
3123
+ true,
3124
+ (dir === 1 ? biDir : directed) ? 1 : 0,
3125
+ (dir === 1 ? directed : biDir) ? 1 : 0
3126
+ );
1718
3127
  if (directed) {
1719
3128
  canvas.drawEdgeCell(
1720
3129
  sRow,
@@ -1743,7 +3152,16 @@ function drawHorizontal(args, s, t, exitRow, enterRow, dir) {
1743
3152
  );
1744
3153
  junction(exitRow, exitCol, dir === 1 ? "right" : "left");
1745
3154
  junction(enterRow, enterCol, dir === 1 ? "left" : "right");
1746
- if (Math.abs(midCol - exitCol) >= 2) drawH(exitRow, firstFree, midCol - dir, true);
3155
+ if (Math.abs(midCol - exitCol) >= 2) {
3156
+ drawH(
3157
+ exitRow,
3158
+ firstFree,
3159
+ midCol - dir,
3160
+ true,
3161
+ dir === 1 && biDir ? 1 : 0,
3162
+ dir === -1 && biDir ? 1 : 0
3163
+ );
3164
+ }
1747
3165
  if (Math.abs(enterCol - midCol) >= 2) drawH(enterRow, midCol + dir, lastFree, false);
1748
3166
  if (exitRow === enterRow) {
1749
3167
  canvas.drawEdgeCell(exitRow, midCol, vocab.h, "line-h", vocab);
@@ -1848,8 +3266,8 @@ function repairAsciiDiagram(text) {
1848
3266
  const nodes = buildNodes(grid, rects);
1849
3267
  const edges = recoverEdges(grid, rects, nodes);
1850
3268
  const style = detectGridStyle(grid);
1851
- const diagram = { nodes, edges, style, warnings: ["repaired"] };
1852
- return { diagram, art: renderAsciiDiagram(diagram) };
3269
+ const diagram2 = { nodes, edges, style, warnings: ["repaired"] };
3270
+ return { diagram: diagram2, art: renderAsciiDiagram(diagram2) };
1853
3271
  }
1854
3272
  function dedupeRects(rects) {
1855
3273
  const seen = /* @__PURE__ */ new Set();
@@ -2090,10 +3508,10 @@ var MIN_AXIS_WIDTH = 48;
2090
3508
  var MAX_COORDINATE_AXIS_WIDTH = 64;
2091
3509
  var EVENT_SPACING = 3;
2092
3510
  var TERMINAL_RAIL_LENGTH = 3;
2093
- function renderAsciiTimeline(timeline, options = {}) {
2094
- const style = options.style ?? timeline.style;
3511
+ function renderAsciiTimeline(timeline2, options = {}) {
3512
+ const style = options.style ?? timeline2.style;
2095
3513
  const vocab = style === "ascii" ? ASCII_VOCAB2 : UNICODE_VOCAB2;
2096
- const { tracks, links } = prepareTimeline(timeline, style);
3514
+ const { tracks, links } = prepareTimeline(timeline2, style);
2097
3515
  if (tracks.length === 0) return "";
2098
3516
  const globalStart = Math.min(...tracks.map((track) => track.startColumn));
2099
3517
  const globalEnd = Math.max(...tracks.map((track) => track.endColumn));
@@ -2200,8 +3618,8 @@ function renderLink(link, style) {
2200
3618
  const arrow = style === "ascii" ? "->" : "\u2192";
2201
3619
  return `branch: ${link.source} ${arrow} ${link.target}${link.label ? ` : ${link.label}` : ""}`;
2202
3620
  }
2203
- function prepareTimeline(timeline, style) {
2204
- const sourceTracks = timeline.tracks.map((track, index) => ({ track, index })).filter(({ track }) => Array.isArray(track.events) && track.events.length > 0).sort(
3621
+ function prepareTimeline(timeline2, style) {
3622
+ const sourceTracks = timeline2.tracks.map((track, index) => ({ track, index })).filter(({ track }) => Array.isArray(track.events) && track.events.length > 0).sort(
2205
3623
  (a, b) => finiteOr(a.track.row, a.index) - finiteOr(b.track.row, b.index) || a.index - b.index || a.track.id.localeCompare(b.track.id)
2206
3624
  );
2207
3625
  const usedTrackIds = /* @__PURE__ */ new Set();
@@ -2260,7 +3678,7 @@ function prepareTimeline(timeline, style) {
2260
3678
  }
2261
3679
  const resolveEndpoint = (value) => endpointIds.get(value) ?? labelIds.get(slug(value));
2262
3680
  const links = [];
2263
- for (const link of Array.isArray(timeline.links) ? timeline.links : []) {
3681
+ for (const link of Array.isArray(timeline2.links) ? timeline2.links : []) {
2264
3682
  const source = resolveEndpoint(link.source);
2265
3683
  const target = resolveEndpoint(link.target);
2266
3684
  if (!source || !target) continue;
@@ -2318,10 +3736,17 @@ function formatCoordinate(value) {
2318
3736
  }
2319
3737
 
2320
3738
  // src/doc/treeview/render.ts
2321
- function renderTree(tree, options = {}) {
2322
- const vocab = (options.style ?? tree.style) === "ascii" ? ASCII_TREE_VOCAB : UNICODE_TREE_VOCAB;
3739
+ function normalizeText(text) {
3740
+ return text.replace(/\s+/gu, " ").trim();
3741
+ }
3742
+ function renderTree(tree2, options = {}) {
3743
+ const vocab = (options.style ?? tree2.style) === "ascii" ? ASCII_TREE_VOCAB : UNICODE_TREE_VOCAB;
2323
3744
  const lines = [];
2324
- const label = (node) => node.comment ? `${node.label} # ${node.comment}` : node.label;
3745
+ const label = (node) => {
3746
+ const text = normalizeText(node.label);
3747
+ const comment = node.comment ? normalizeText(node.comment) : "";
3748
+ return comment ? `${text} # ${comment}` : text;
3749
+ };
2325
3750
  const walk = (nodes, prefix) => {
2326
3751
  nodes.forEach((node, i) => {
2327
3752
  const last = i === nodes.length - 1;
@@ -2329,7 +3754,7 @@ function renderTree(tree, options = {}) {
2329
3754
  walk(node.children, prefix + (last ? vocab.gap : vocab.rail));
2330
3755
  });
2331
3756
  };
2332
- for (const root of tree.roots) {
3757
+ for (const root of tree2.roots) {
2333
3758
  lines.push(label(root));
2334
3759
  walk(root.children, "");
2335
3760
  }
@@ -2344,6 +3769,16 @@ export {
2344
3769
  cssFilterForTreatment,
2345
3770
  docToMarkdown,
2346
3771
  resolveThemeForDoc,
3772
+ isTemplatedPageBlock,
3773
+ resolvePageBlock,
3774
+ sectionExtractors,
3775
+ resolvePageStyle,
3776
+ materializePageSection,
3777
+ materializePageSections,
3778
+ buildPageCssVars,
3779
+ pageStyleDataAttributes,
3780
+ PAGE_BASE_CSS,
3781
+ buildPageCss,
2347
3782
  applyNarrationTiming,
2348
3783
  scoreTextSimilarity,
2349
3784
  resolveAudioMapping,
@@ -2355,4 +3790,3 @@ export {
2355
3790
  renderAsciiTimeline,
2356
3791
  renderTree
2357
3792
  };
2358
- //# sourceMappingURL=chunk-TFJVXUHH.js.map