@openpresentation/opf 0.13.0 → 0.14.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 (417) hide show
  1. package/README.md +28 -23
  2. package/dist/{catalogs-ywCamd8C.d.ts → catalogs-D-yyQWCQ.d.ts} +86 -208
  3. package/dist/catalogs.d.ts +2 -2
  4. package/dist/catalogs.js +1 -1
  5. package/dist/{chart-data-Cdr6rRVV.d.ts → chart-data-B_3z9VTb.d.ts} +16 -5
  6. package/dist/chunk-4LDGKLUC.js +192 -0
  7. package/dist/{chunk-II5EYKZU.js → chunk-4VJDTF55.js} +2 -92
  8. package/dist/chunk-5ZU6JAPP.js +83 -0
  9. package/dist/{chunk-MPM7NRG7.js → chunk-6OXY2CP3.js} +1716 -744
  10. package/dist/{chunk-IS2CPNVJ.js → chunk-BFLVSVA7.js} +26 -26
  11. package/dist/chunk-CSQHPVGL.js +94 -0
  12. package/dist/{chunk-GJKJL4YY.js → chunk-D3TY4TT6.js} +34 -412
  13. package/dist/chunk-JDJBDYSR.js +4167 -0
  14. package/dist/{chunk-7QBCWNWL.js → chunk-LS2FMPI5.js} +1086 -1092
  15. package/dist/{chunk-ATGDDJPX.js → chunk-Q2TCMN56.js} +3 -3
  16. package/dist/chunk-UPQQD7MA.js +1840 -0
  17. package/dist/{chunk-RAYB46AB.js → chunk-XIZUK2XM.js} +32 -30
  18. package/dist/{chunk-E34DJ5LL.js → chunk-XOZ4KMSR.js} +2427 -10820
  19. package/dist/chunk-Z65B2B77.js +601 -0
  20. package/dist/{composition-D7we69Tr.d.ts → composition-_WEwBe2a.d.ts} +738 -27
  21. package/dist/composition.d.ts +2 -2
  22. package/dist/composition.js +2 -2
  23. package/dist/convert.d.ts +9 -7
  24. package/dist/convert.js +33 -19
  25. package/dist/data.d.ts +4 -4
  26. package/dist/data.js +3 -3
  27. package/dist/diff.d.ts +4 -4
  28. package/dist/diff.js +6 -604
  29. package/dist/docs.js +54 -42
  30. package/dist/examples.d.ts +1 -1
  31. package/dist/examples.js +1366 -2908
  32. package/dist/finding-C_por275.d.ts +212 -0
  33. package/dist/format.d.ts +4 -4
  34. package/dist/format.js +2 -83
  35. package/dist/index.d.ts +318 -284
  36. package/dist/index.js +530 -943
  37. package/dist/markdown.d.ts +28 -27
  38. package/dist/markdown.js +8 -1940
  39. package/dist/pagination-BZpXLvFL.d.ts +119 -0
  40. package/dist/pagination.d.ts +5 -61
  41. package/dist/pagination.js +5 -5
  42. package/dist/patch.d.ts +12 -23
  43. package/dist/patch.js +5 -5
  44. package/dist/{presentation-mG-IYErQ.d.ts → presentation-C5eHkevA.d.ts} +350 -506
  45. package/dist/repo-readme.js +1 -1
  46. package/dist/{schemas-BbPonsTz.d.ts → schemas-DDpqAgyS.d.ts} +31 -17
  47. package/dist/schemas.d.ts +1 -1
  48. package/dist/schemas.js +1 -1
  49. package/dist/spec/README.md +10 -5
  50. package/dist/spec/catalogs/audiences/index.json +2 -50
  51. package/dist/spec/catalogs/chart-types/100pct-stacked-area.json +21 -0
  52. package/dist/spec/catalogs/chart-types/100pct-stacked-bar.json +22 -0
  53. package/dist/spec/catalogs/chart-types/100pct-stacked-column.json +22 -0
  54. package/dist/spec/catalogs/chart-types/area.json +2 -60
  55. package/dist/spec/catalogs/chart-types/bar.json +2 -48
  56. package/dist/spec/catalogs/chart-types/box-and-whisker.json +2 -132
  57. package/dist/spec/catalogs/chart-types/column.json +2 -52
  58. package/dist/spec/catalogs/chart-types/combo.json +37 -0
  59. package/dist/spec/catalogs/chart-types/doughnut.json +2 -40
  60. package/dist/spec/catalogs/chart-types/filled-radar.json +2 -52
  61. package/dist/spec/catalogs/chart-types/funnel.json +2 -46
  62. package/dist/spec/catalogs/chart-types/histogram.json +2 -149
  63. package/dist/spec/catalogs/chart-types/index.json +50 -520
  64. package/dist/spec/catalogs/chart-types/line-with-markers.json +2 -60
  65. package/dist/spec/catalogs/chart-types/line.json +2 -60
  66. package/dist/spec/catalogs/chart-types/pareto.json +2 -50
  67. package/dist/spec/catalogs/chart-types/pie.json +2 -40
  68. package/dist/spec/catalogs/chart-types/radar-with-markers.json +2 -52
  69. package/dist/spec/catalogs/chart-types/radar.json +2 -52
  70. package/dist/spec/catalogs/chart-types/scatter.json +2 -73
  71. package/dist/spec/catalogs/chart-types/stacked-area.json +21 -0
  72. package/dist/spec/catalogs/chart-types/stacked-bar.json +22 -0
  73. package/dist/spec/catalogs/chart-types/stacked-column.json +22 -0
  74. package/dist/spec/catalogs/chart-types/stacked-line-with-markers.json +22 -0
  75. package/dist/spec/catalogs/chart-types/stacked-line.json +21 -0
  76. package/dist/spec/catalogs/chart-types/treemap.json +2 -48
  77. package/dist/spec/catalogs/chart-types/waterfall.json +2 -52
  78. package/dist/spec/catalogs/chart-types/world.json +2 -64
  79. package/dist/spec/catalogs/font-schemes/angsana-new.json +2 -2
  80. package/dist/spec/catalogs/font-schemes/aparajita.json +3 -3
  81. package/dist/spec/catalogs/font-schemes/aptos.json +1 -1
  82. package/dist/spec/catalogs/font-schemes/arabic-typesetting.json +2 -2
  83. package/dist/spec/catalogs/font-schemes/arial.json +1 -1
  84. package/dist/spec/catalogs/font-schemes/batang.json +2 -2
  85. package/dist/spec/catalogs/font-schemes/bookman.json +1 -1
  86. package/dist/spec/catalogs/font-schemes/calibri.json +1 -1
  87. package/dist/spec/catalogs/font-schemes/century-schoolbook.json +1 -1
  88. package/dist/spec/catalogs/font-schemes/consolas.json +2 -4
  89. package/dist/spec/catalogs/font-schemes/constantia.json +1 -1
  90. package/dist/spec/catalogs/font-schemes/courier-new.json +2 -4
  91. package/dist/spec/catalogs/font-schemes/daunpenh.json +2 -2
  92. package/dist/spec/catalogs/font-schemes/david.json +2 -2
  93. package/dist/spec/catalogs/font-schemes/dilleniaupc.json +2 -2
  94. package/dist/spec/catalogs/font-schemes/fangsong.json +2 -2
  95. package/dist/spec/catalogs/font-schemes/garamond.json +1 -1
  96. package/dist/spec/catalogs/font-schemes/gautami.json +2 -2
  97. package/dist/spec/catalogs/font-schemes/georgia.json +1 -1
  98. package/dist/spec/catalogs/font-schemes/gisha.json +3 -3
  99. package/dist/spec/catalogs/font-schemes/grandview.json +1 -1
  100. package/dist/spec/catalogs/font-schemes/gungsuh.json +2 -2
  101. package/dist/spec/catalogs/font-schemes/impact.json +1 -1
  102. package/dist/spec/catalogs/font-schemes/index.json +1 -1
  103. package/dist/spec/catalogs/font-schemes/kalinga.json +2 -2
  104. package/dist/spec/catalogs/font-schemes/kartika.json +2 -2
  105. package/dist/spec/catalogs/font-schemes/khmer-ui.json +2 -2
  106. package/dist/spec/catalogs/font-schemes/latha.json +2 -2
  107. package/dist/spec/catalogs/font-schemes/lucida-sans.json +1 -1
  108. package/dist/spec/catalogs/font-schemes/malgun-gothic.json +2 -2
  109. package/dist/spec/catalogs/font-schemes/mangal.json +4 -5
  110. package/dist/spec/catalogs/font-schemes/meiryo.json +2 -2
  111. package/dist/spec/catalogs/font-schemes/microsoft-jhenghei.json +2 -2
  112. package/dist/spec/catalogs/font-schemes/microsoft-yahei.json +5 -5
  113. package/dist/spec/catalogs/font-schemes/mingliu.json +2 -2
  114. package/dist/spec/catalogs/font-schemes/miriam.json +2 -2
  115. package/dist/spec/catalogs/font-schemes/montserrat.json +1 -1
  116. package/dist/spec/catalogs/font-schemes/ms-mincho.json +2 -2
  117. package/dist/spec/catalogs/font-schemes/nirmala-ui.json +2 -2
  118. package/dist/spec/catalogs/font-schemes/noto-naksh-arabic.json +2 -2
  119. package/dist/spec/catalogs/font-schemes/noto-nastaliq-urdu.json +3 -3
  120. package/dist/spec/catalogs/font-schemes/noto-sans-arabic.json +4 -4
  121. package/dist/spec/catalogs/font-schemes/noto-sans-armenian.json +2 -2
  122. package/dist/spec/catalogs/font-schemes/noto-sans-bengali.json +3 -3
  123. package/dist/spec/catalogs/font-schemes/noto-sans-devangari.json +3 -3
  124. package/dist/spec/catalogs/font-schemes/noto-sans-ethiopic.json +2 -2
  125. package/dist/spec/catalogs/font-schemes/noto-sans-georgian.json +2 -2
  126. package/dist/spec/catalogs/font-schemes/noto-sans-gujarati.json +2 -2
  127. package/dist/spec/catalogs/font-schemes/noto-sans-gurmukhi.json +2 -2
  128. package/dist/spec/catalogs/font-schemes/noto-sans-hebrew.json +2 -2
  129. package/dist/spec/catalogs/font-schemes/noto-sans-jp.json +2 -2
  130. package/dist/spec/catalogs/font-schemes/noto-sans-kannada.json +2 -2
  131. package/dist/spec/catalogs/font-schemes/noto-sans-khmer.json +2 -2
  132. package/dist/spec/catalogs/font-schemes/noto-sans-kr.json +2 -2
  133. package/dist/spec/catalogs/font-schemes/noto-sans-malayalam.json +2 -2
  134. package/dist/spec/catalogs/font-schemes/noto-sans-mongolian.json +2 -2
  135. package/dist/spec/catalogs/font-schemes/noto-sans-oriya.json +2 -2
  136. package/dist/spec/catalogs/font-schemes/noto-sans-sc.json +5 -5
  137. package/dist/spec/catalogs/font-schemes/noto-sans-tamil.json +2 -2
  138. package/dist/spec/catalogs/font-schemes/noto-sans-tc.json +2 -2
  139. package/dist/spec/catalogs/font-schemes/noto-sans-telugu.json +2 -2
  140. package/dist/spec/catalogs/font-schemes/noto-sans-thai.json +2 -2
  141. package/dist/spec/catalogs/font-schemes/noto-sans.json +5 -5
  142. package/dist/spec/catalogs/font-schemes/nyala.json +2 -2
  143. package/dist/spec/catalogs/font-schemes/open-sans.json +1 -1
  144. package/dist/spec/catalogs/font-schemes/pmingliu.json +2 -2
  145. package/dist/spec/catalogs/font-schemes/poppins.json +1 -1
  146. package/dist/spec/catalogs/font-schemes/pt-serif.json +1 -1
  147. package/dist/spec/catalogs/font-schemes/raavi.json +2 -2
  148. package/dist/spec/catalogs/font-schemes/raleway.json +1 -1
  149. package/dist/spec/catalogs/font-schemes/roboto.json +1 -1
  150. package/dist/spec/catalogs/font-schemes/rockwell.json +1 -1
  151. package/dist/spec/catalogs/font-schemes/sakkal-majalla.json +4 -4
  152. package/dist/spec/catalogs/font-schemes/seaford.json +1 -1
  153. package/dist/spec/catalogs/font-schemes/segoe-ui-light.json +1 -1
  154. package/dist/spec/catalogs/font-schemes/segoe-ui.json +1 -1
  155. package/dist/spec/catalogs/font-schemes/shonar-bangla.json +3 -3
  156. package/dist/spec/catalogs/font-schemes/shruti.json +2 -2
  157. package/dist/spec/catalogs/font-schemes/simsun.json +2 -2
  158. package/dist/spec/catalogs/font-schemes/skeena.json +1 -1
  159. package/dist/spec/catalogs/font-schemes/sylfaen.json +3 -3
  160. package/dist/spec/catalogs/font-schemes/tahoma.json +1 -1
  161. package/dist/spec/catalogs/font-schemes/tenorite.json +1 -1
  162. package/dist/spec/catalogs/font-schemes/times-new-roman.json +1 -1
  163. package/dist/spec/catalogs/font-schemes/traditional-arabic.json +4 -4
  164. package/dist/spec/catalogs/font-schemes/trebuchet-ms.json +1 -1
  165. package/dist/spec/catalogs/font-schemes/tunga.json +2 -2
  166. package/dist/spec/catalogs/font-schemes/verdana.json +1 -1
  167. package/dist/spec/catalogs/font-schemes/vrinda.json +2 -2
  168. package/dist/spec/catalogs/font-schemes/yu-gothic.json +2 -2
  169. package/dist/spec/catalogs/layouts/action-plan.json +9 -15
  170. package/dist/spec/catalogs/layouts/agenda.json +8 -15
  171. package/dist/spec/catalogs/layouts/appendix-index.json +7 -15
  172. package/dist/spec/catalogs/layouts/architecture-stack.json +9 -15
  173. package/dist/spec/catalogs/layouts/assumptions-dependencies.json +9 -15
  174. package/dist/spec/catalogs/layouts/before-after.json +9 -15
  175. package/dist/spec/catalogs/layouts/benchmark-target-table.json +9 -15
  176. package/dist/spec/catalogs/layouts/blank.json +11 -1
  177. package/dist/spec/catalogs/layouts/bullet-list.json +9 -15
  178. package/dist/spec/catalogs/layouts/business-model-canvas.json +9 -15
  179. package/dist/spec/catalogs/layouts/capability-map.json +14 -16
  180. package/dist/spec/catalogs/layouts/case-study.json +9 -15
  181. package/dist/spec/catalogs/layouts/chapter-recap.json +8 -15
  182. package/dist/spec/catalogs/layouts/chart-1x.json +15 -0
  183. package/dist/spec/catalogs/layouts/chart-2x.json +15 -0
  184. package/dist/spec/catalogs/layouts/chart-3x.json +15 -0
  185. package/dist/spec/catalogs/layouts/circular-lifecycle.json +9 -15
  186. package/dist/spec/catalogs/layouts/code-1x.json +10 -0
  187. package/dist/spec/catalogs/layouts/comparison.json +9 -15
  188. package/dist/spec/catalogs/layouts/competitive-landscape.json +14 -16
  189. package/dist/spec/catalogs/layouts/customer-journey.json +14 -16
  190. package/dist/spec/catalogs/layouts/customer-logos.json +9 -15
  191. package/dist/spec/catalogs/layouts/dashboard.json +9 -15
  192. package/dist/spec/catalogs/layouts/data-visualization.json +9 -15
  193. package/dist/spec/catalogs/layouts/decision-tree.json +14 -16
  194. package/dist/spec/catalogs/layouts/detailed-data-table.json +9 -15
  195. package/dist/spec/catalogs/layouts/ecosystem-map.json +14 -16
  196. package/dist/spec/catalogs/layouts/executive-decision.json +9 -15
  197. package/dist/spec/catalogs/layouts/executive-summary.json +9 -15
  198. package/dist/spec/catalogs/layouts/extract/canonical.json +8 -8
  199. package/dist/spec/catalogs/layouts/faq.json +9 -15
  200. package/dist/spec/catalogs/layouts/feature-comparison-matrix.json +9 -15
  201. package/dist/spec/catalogs/layouts/forecast-scenario.json +9 -15
  202. package/dist/spec/catalogs/layouts/funnel-pyramid.json +9 -15
  203. package/dist/spec/catalogs/layouts/gantt-project-plan.json +9 -15
  204. package/dist/spec/catalogs/layouts/geographic-map.json +13 -15
  205. package/dist/spec/catalogs/layouts/heatmap-cohort.json +9 -15
  206. package/dist/spec/catalogs/layouts/hub-and-spoke.json +9 -15
  207. package/dist/spec/catalogs/layouts/icon-grid.json +14 -16
  208. package/dist/spec/catalogs/layouts/image-1x.json +11 -1
  209. package/dist/spec/catalogs/layouts/image-2x.json +12 -2
  210. package/dist/spec/catalogs/layouts/image-3x.json +13 -3
  211. package/dist/spec/catalogs/layouts/image-bleed.json +12 -2
  212. package/dist/spec/catalogs/layouts/image-focus.json +14 -16
  213. package/dist/spec/catalogs/layouts/index.json +1 -1
  214. package/dist/spec/catalogs/layouts/key-takeaway.json +8 -15
  215. package/dist/spec/catalogs/layouts/kpi-scorecard.json +9 -15
  216. package/dist/spec/catalogs/layouts/list-1x.json +17 -1
  217. package/dist/spec/catalogs/layouts/list-2x.json +16 -0
  218. package/dist/spec/catalogs/layouts/list-3x.json +16 -0
  219. package/dist/spec/catalogs/layouts/list-4x.json +16 -0
  220. package/dist/spec/catalogs/layouts/list-5x.json +16 -0
  221. package/dist/spec/catalogs/layouts/list-6x.json +16 -0
  222. package/dist/spec/catalogs/layouts/logic-tree.json +9 -15
  223. package/dist/spec/catalogs/layouts/market-size.json +9 -15
  224. package/dist/spec/catalogs/layouts/matrix-quadrant.json +9 -15
  225. package/dist/spec/catalogs/layouts/media-1x.json +11 -1
  226. package/dist/spec/catalogs/layouts/network-dependency-map.json +13 -15
  227. package/dist/spec/catalogs/layouts/number-1x.json +16 -1
  228. package/dist/spec/catalogs/layouts/number-2x.json +15 -0
  229. package/dist/spec/catalogs/layouts/number-3x.json +15 -0
  230. package/dist/spec/catalogs/layouts/number-4x.json +15 -0
  231. package/dist/spec/catalogs/layouts/number-5x.json +15 -0
  232. package/dist/spec/catalogs/layouts/number-6x.json +15 -0
  233. package/dist/spec/catalogs/layouts/one-column-explainer.json +9 -15
  234. package/dist/spec/catalogs/layouts/org-chart.json +9 -15
  235. package/dist/spec/catalogs/layouts/persona-grid.json +14 -16
  236. package/dist/spec/catalogs/layouts/photo-grid.json +17 -19
  237. package/dist/spec/catalogs/layouts/pricing-table.json +9 -15
  238. package/dist/spec/catalogs/layouts/process-flow.json +9 -15
  239. package/dist/spec/catalogs/layouts/product-feature.json +14 -16
  240. package/dist/spec/catalogs/layouts/pros-cons.json +9 -15
  241. package/dist/spec/catalogs/layouts/qa-discussion.json +7 -15
  242. package/dist/spec/catalogs/layouts/quote-1x.json +11 -1
  243. package/dist/spec/catalogs/layouts/quote-highlight.json +9 -15
  244. package/dist/spec/catalogs/layouts/raci-matrix.json +9 -15
  245. package/dist/spec/catalogs/layouts/risk-heatmap.json +9 -15
  246. package/dist/spec/catalogs/layouts/roadmap.json +9 -15
  247. package/dist/spec/catalogs/layouts/screenshot-walkthrough.json +14 -16
  248. package/dist/spec/catalogs/layouts/section-divider.json +8 -15
  249. package/dist/spec/catalogs/layouts/single-message-statement.json +8 -15
  250. package/dist/spec/catalogs/layouts/stats-metrics.json +9 -15
  251. package/dist/spec/catalogs/layouts/status-rag.json +9 -15
  252. package/dist/spec/catalogs/layouts/swimlane-process.json +14 -16
  253. package/dist/spec/catalogs/layouts/swot-analysis.json +9 -15
  254. package/dist/spec/catalogs/layouts/table-1x.json +10 -0
  255. package/dist/spec/catalogs/layouts/team-bio.json +14 -16
  256. package/dist/spec/catalogs/layouts/testimonial-grid.json +9 -15
  257. package/dist/spec/catalogs/layouts/text-1x.json +11 -1
  258. package/dist/spec/catalogs/layouts/text-2x.json +10 -0
  259. package/dist/spec/catalogs/layouts/text-3x.json +10 -0
  260. package/dist/spec/catalogs/layouts/thank-you-cta.json +8 -15
  261. package/dist/spec/catalogs/layouts/three-column.json +9 -15
  262. package/dist/spec/catalogs/layouts/timeline-1x.json +11 -1
  263. package/dist/spec/catalogs/layouts/timeline.json +9 -15
  264. package/dist/spec/catalogs/layouts/title-slide.json +8 -15
  265. package/dist/spec/catalogs/layouts/title-subtitle.json +11 -1
  266. package/dist/spec/catalogs/layouts/title.json +11 -1
  267. package/dist/spec/catalogs/layouts/two-column.json +9 -15
  268. package/dist/spec/catalogs/layouts/venn-overlap.json +9 -15
  269. package/dist/spec/catalogs/layouts/waterfall-bridge.json +9 -15
  270. package/dist/spec/catalogs/layouts/wheel-radial.json +9 -15
  271. package/dist/spec/catalogs/manifest.json +8 -8
  272. package/dist/spec/catalogs/narratives/board-meeting.json +45 -45
  273. package/dist/spec/catalogs/narratives/business-narrative.json +19 -19
  274. package/dist/spec/catalogs/narratives/business-review.json +27 -27
  275. package/dist/spec/catalogs/narratives/capacity-planning.json +19 -19
  276. package/dist/spec/catalogs/narratives/challenge-resolution.json +17 -17
  277. package/dist/spec/catalogs/narratives/change-story.json +13 -13
  278. package/dist/spec/catalogs/narratives/classic-story.json +17 -17
  279. package/dist/spec/catalogs/narratives/company-intro.json +21 -21
  280. package/dist/spec/catalogs/narratives/conference-talk.json +4 -4
  281. package/dist/spec/catalogs/narratives/data-story.json +13 -14
  282. package/dist/spec/catalogs/narratives/early-startup-pitch.json +27 -27
  283. package/dist/spec/catalogs/narratives/educate.json +21 -21
  284. package/dist/spec/catalogs/narratives/employee-review.json +19 -19
  285. package/dist/spec/catalogs/narratives/failure-analysis.json +23 -23
  286. package/dist/spec/catalogs/narratives/focus.json +27 -27
  287. package/dist/spec/catalogs/narratives/golden-circle.json +4 -4
  288. package/dist/spec/catalogs/narratives/heros-journey.json +13 -13
  289. package/dist/spec/catalogs/narratives/index.json +145 -145
  290. package/dist/spec/catalogs/narratives/innovation.json +21 -21
  291. package/dist/spec/catalogs/narratives/justice.json +25 -25
  292. package/dist/spec/catalogs/narratives/marketing-strategy.json +25 -25
  293. package/dist/spec/catalogs/narratives/performance-improvement-plan.json +19 -19
  294. package/dist/spec/catalogs/narratives/performance-review.json +25 -25
  295. package/dist/spec/catalogs/narratives/persuade.json +17 -17
  296. package/dist/spec/catalogs/narratives/persuasive-sales.json +19 -19
  297. package/dist/spec/catalogs/narratives/pitch-deck.json +6 -6
  298. package/dist/spec/catalogs/narratives/problem-solution.json +5 -5
  299. package/dist/spec/catalogs/narratives/product-launch.json +23 -23
  300. package/dist/spec/catalogs/narratives/project-proposal.json +23 -23
  301. package/dist/spec/catalogs/narratives/pyramid-principle.json +9 -9
  302. package/dist/spec/catalogs/narratives/qbr.json +8 -8
  303. package/dist/spec/catalogs/narratives/rags-to-riches.json +17 -17
  304. package/dist/spec/catalogs/narratives/reveal.json +19 -19
  305. package/dist/spec/catalogs/narratives/scqa.json +4 -4
  306. package/dist/spec/catalogs/narratives/situation-complication-resolution.json +11 -11
  307. package/dist/spec/catalogs/narratives/sparkline.json +11 -11
  308. package/dist/spec/catalogs/narratives/star-method.json +11 -11
  309. package/dist/spec/catalogs/narratives/status-update.json +15 -15
  310. package/dist/spec/catalogs/narratives/strategic-advisory.json +17 -17
  311. package/dist/spec/catalogs/narratives/strategic-narrative.json +4 -4
  312. package/dist/spec/catalogs/narratives/survey-analysis.json +23 -23
  313. package/dist/spec/catalogs/narratives/survival-story.json +23 -23
  314. package/dist/spec/catalogs/narratives/transformation-arc.json +4 -4
  315. package/dist/spec/catalogs/narratives/trend-analysis.json +17 -17
  316. package/dist/spec/catalogs/narratives/underdog-victory.json +19 -19
  317. package/dist/spec/catalogs/narratives/venture-pitch.json +27 -27
  318. package/dist/spec/catalogs/narratives/vision-roadmap.json +13 -13
  319. package/dist/spec/catalogs/narratives/weekly-progress.json +23 -23
  320. package/dist/spec/catalogs/narratives/what-so-what-now-what.json +9 -9
  321. package/dist/spec/openapi.yaml +2 -5
  322. package/dist/spec/reference/engine-defaults.json +2 -2
  323. package/dist/spec/schemas/audience.schema.json +1 -1
  324. package/dist/spec/schemas/catalog-index.schema.json +2 -2
  325. package/dist/spec/schemas/chart-type.schema.json +19 -290
  326. package/dist/spec/schemas/color-scheme.schema.json +20 -12
  327. package/dist/spec/schemas/finding.schema.json +191 -0
  328. package/dist/spec/schemas/font-scheme.schema.json +19 -46
  329. package/dist/spec/schemas/layout.schema.json +100 -159
  330. package/dist/spec/schemas/narrative.schema.json +17 -25
  331. package/dist/spec/schemas/opf.schema.json +286 -340
  332. package/dist/spec/schemas/social-platform.schema.json +1 -26
  333. package/dist/spec/schemas/theme.schema.json +4 -1
  334. package/dist/spec-files.d.ts +1 -1
  335. package/dist/spec-files.js +1 -1
  336. package/dist/symbol-font-encodings.js +18448 -1
  337. package/dist/types.d.ts +4 -4
  338. package/dist/validation-types-zh03LeZy.d.ts +276 -0
  339. package/dist/validator.d.ts +60 -4
  340. package/dist/validator.js +4 -4
  341. package/dist/yaml.d.ts +87 -0
  342. package/dist/yaml.js +321 -0
  343. package/package.json +5 -9
  344. package/dist/audit.d.ts +0 -35
  345. package/dist/audit.js +0 -7
  346. package/dist/chunk-7N4VMAT4.js +0 -1694
  347. package/dist/chunk-FYLJVF7X.js +0 -18448
  348. package/dist/chunk-INU7ZNSB.js +0 -670
  349. package/dist/chunk-IYCJUKWD.js +0 -951
  350. package/dist/lint-B7azdiuE.d.ts +0 -197
  351. package/dist/lint.d.ts +0 -7
  352. package/dist/lint.js +0 -6
  353. package/dist/spec/catalogs/audiences/customers.json +0 -27
  354. package/dist/spec/catalogs/audiences/executives.json +0 -27
  355. package/dist/spec/catalogs/audiences/investors.json +0 -27
  356. package/dist/spec/catalogs/audiences/marketing-team.json +0 -27
  357. package/dist/spec/catalogs/audiences/regulators.json +0 -27
  358. package/dist/spec/catalogs/audiences/sales-team.json +0 -27
  359. package/dist/spec/catalogs/chart-types/100pct-bullet-bar-2x.json +0 -91
  360. package/dist/spec/catalogs/chart-types/100pct-bullet-bar-3x.json +0 -103
  361. package/dist/spec/catalogs/chart-types/100pct-bullet-bar.json +0 -79
  362. package/dist/spec/catalogs/chart-types/100pct-bullet-column-2x.json +0 -91
  363. package/dist/spec/catalogs/chart-types/100pct-bullet-column-3x.json +0 -103
  364. package/dist/spec/catalogs/chart-types/100pct-bullet-column.json +0 -79
  365. package/dist/spec/catalogs/chart-types/100pct-progress-bar.json +0 -105
  366. package/dist/spec/catalogs/chart-types/100pct-stacked-area-2x.json +0 -106
  367. package/dist/spec/catalogs/chart-types/100pct-stacked-area-3x.json +0 -123
  368. package/dist/spec/catalogs/chart-types/100pct-stacked-bar-2x.json +0 -89
  369. package/dist/spec/catalogs/chart-types/100pct-stacked-bar-3x.json +0 -100
  370. package/dist/spec/catalogs/chart-types/100pct-stacked-column-2x.json +0 -95
  371. package/dist/spec/catalogs/chart-types/100pct-stacked-column-3x.json +0 -108
  372. package/dist/spec/catalogs/chart-types/australia.json +0 -76
  373. package/dist/spec/catalogs/chart-types/box-and-whisker-2x.json +0 -136
  374. package/dist/spec/catalogs/chart-types/box-and-whisker-3x.json +0 -168
  375. package/dist/spec/catalogs/chart-types/bullet-bar-2x.json +0 -89
  376. package/dist/spec/catalogs/chart-types/bullet-bar-3x.json +0 -101
  377. package/dist/spec/catalogs/chart-types/bullet-bar.json +0 -77
  378. package/dist/spec/catalogs/chart-types/bullet-column-2x.json +0 -89
  379. package/dist/spec/catalogs/chart-types/bullet-column-3x.json +0 -101
  380. package/dist/spec/catalogs/chart-types/bullet-column.json +0 -77
  381. package/dist/spec/catalogs/chart-types/canada.json +0 -86
  382. package/dist/spec/catalogs/chart-types/clustered-bar-2x.json +0 -89
  383. package/dist/spec/catalogs/chart-types/clustered-column.json +0 -95
  384. package/dist/spec/catalogs/chart-types/dot-plot-2x.json +0 -99
  385. package/dist/spec/catalogs/chart-types/dot-plot-3x.json +0 -124
  386. package/dist/spec/catalogs/chart-types/dot-plot-4x.json +0 -149
  387. package/dist/spec/catalogs/chart-types/dot-plot-5x.json +0 -174
  388. package/dist/spec/catalogs/chart-types/dot-plot-6x.json +0 -199
  389. package/dist/spec/catalogs/chart-types/dot-plot.json +0 -74
  390. package/dist/spec/catalogs/chart-types/dumbbell.json +0 -120
  391. package/dist/spec/catalogs/chart-types/line-2x.json +0 -105
  392. package/dist/spec/catalogs/chart-types/line-3x.json +0 -127
  393. package/dist/spec/catalogs/chart-types/line-with-high-low-and-markers.json +0 -144
  394. package/dist/spec/catalogs/chart-types/line-with-high-low.json +0 -144
  395. package/dist/spec/catalogs/chart-types/line-with-markers-2x.json +0 -106
  396. package/dist/spec/catalogs/chart-types/line-with-markers-3x.json +0 -128
  397. package/dist/spec/catalogs/chart-types/sparkline-2x.json +0 -138
  398. package/dist/spec/catalogs/chart-types/sparkline-3x.json +0 -174
  399. package/dist/spec/catalogs/chart-types/sparkline-4x.json +0 -210
  400. package/dist/spec/catalogs/chart-types/sparkline-5x.json +0 -246
  401. package/dist/spec/catalogs/chart-types/sparkline-6x.json +0 -282
  402. package/dist/spec/catalogs/chart-types/sparkline.json +0 -102
  403. package/dist/spec/catalogs/chart-types/stacked-area-2x.json +0 -106
  404. package/dist/spec/catalogs/chart-types/stacked-area-3x.json +0 -123
  405. package/dist/spec/catalogs/chart-types/stacked-bar-2x.json +0 -89
  406. package/dist/spec/catalogs/chart-types/stacked-bar-3x.json +0 -100
  407. package/dist/spec/catalogs/chart-types/stacked-column-2x.json +0 -95
  408. package/dist/spec/catalogs/chart-types/stacked-column-3x.json +0 -108
  409. package/dist/spec/catalogs/chart-types/stacked-line-2x.json +0 -106
  410. package/dist/spec/catalogs/chart-types/stacked-line-3x.json +0 -123
  411. package/dist/spec/catalogs/chart-types/stacked-line-with-markers-2x.json +0 -107
  412. package/dist/spec/catalogs/chart-types/stacked-line-with-markers-3x.json +0 -124
  413. package/dist/spec/catalogs/chart-types/treemap-2x.json +0 -101
  414. package/dist/spec/catalogs/chart-types/treemap-3x.json +0 -122
  415. package/dist/spec/catalogs/chart-types/united-kingdom.json +0 -68
  416. package/dist/spec/catalogs/chart-types/united-states.json +0 -82
  417. package/dist/validator-CIylxoIm.d.ts +0 -172
@@ -1,4 +1,4 @@
1
- import { catalogs } from './chunk-E34DJ5LL.js';
1
+ import { catalogs } from './chunk-XOZ4KMSR.js';
2
2
 
3
3
  // src/table.ts
4
4
  var record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
@@ -7,7 +7,7 @@ function tableGrid(value, path = "table") {
7
7
  const values = [...hasHeaders ? [table.columns] : [], ...Array.isArray(table.rows) ? table.rows : []];
8
8
  const columnCount = values.reduce((count, row) => Math.max(count, Array.isArray(row) ? row.length : 0), 1), rowCount = values.length;
9
9
  const owners = Array.from({ length: rowCount }, () => Array(columnCount));
10
- const rows2 = Array.from({ length: rowCount }, () => []), issues = [];
10
+ const rows3 = Array.from({ length: rowCount }, () => []), issues = [];
11
11
  const location = (r, c) => `${path}.${hasHeaders && r === 0 ? "columns" : `rows.${r - Number(hasHeaders)}`}.${c}`;
12
12
  for (let r = 0; r < rowCount; r++) for (let c = 0; c < columnCount; c++) {
13
13
  const input = values[r]?.[c], cellPath = location(r, c), existing = owners[r][c];
@@ -15,21 +15,21 @@ function tableGrid(value, path = "table") {
15
15
  if (input !== null) issues.push({ path: cellPath, message: "A position covered by a spanning cell must explicitly contain null; content cannot be hidden." });
16
16
  continue;
17
17
  }
18
- const object = record(input), styled = Object.hasOwn(object, "value");
19
- const column = !styled && hasHeaders && r === 0 && typeof object.name === "string";
20
- const rowSpan = styled ? object.rowSpan ?? 1 : 1, colSpan = styled ? object.colSpan ?? 1 : 1;
18
+ const object2 = record(input), styled = Object.hasOwn(object2, "value");
19
+ const column = !styled && hasHeaders && r === 0 && typeof object2.name === "string";
20
+ const rowSpan = styled ? object2.rowSpan ?? 1 : 1, colSpan = styled ? object2.colSpan ?? 1 : 1;
21
21
  if (!Number.isSafeInteger(rowSpan) || !Number.isSafeInteger(colSpan) || rowSpan < 1 || colSpan < 1 || r + rowSpan > rowCount || c + colSpan > columnCount || hasHeaders && r === 0 && rowSpan > 1) {
22
22
  issues.push({ path: cellPath, message: "Cell spans must be positive integers within the table grid and cannot cross from headers into body rows." });
23
23
  continue;
24
24
  }
25
- const cell = { input, value: styled ? object.value : column ? object.name : input, style: styled ? record(object.style) : {}, row: r, column: c, rowSpan, colSpan, header: hasHeaders && r === 0, path: cellPath, valuePath: styled ? cellPath + ".value" : column ? cellPath + ".name" : cellPath };
26
- rows2[r].push(cell);
25
+ const cell = { input, value: styled ? object2.value : column ? object2.name : input, style: styled ? record(object2.style) : {}, row: r, column: c, rowSpan, colSpan, header: hasHeaders && r === 0, path: cellPath, valuePath: styled ? cellPath + ".value" : column ? cellPath + ".name" : cellPath };
26
+ rows3[r].push(cell);
27
27
  for (let y = r; y < r + rowSpan; y++) for (let x = c; x < c + colSpan; x++) {
28
28
  if (owners[y][x]) issues.push({ path: cellPath, message: "Cell spans cannot overlap another spanning cell." });
29
29
  else owners[y][x] = cell;
30
30
  }
31
31
  }
32
- return { rows: rows2, columnCount, rowCount, hasHeaders, owners, issues };
32
+ return { rows: rows3, columnCount, rowCount, hasHeaders, owners, issues };
33
33
  }
34
34
  function tableRowBoundaries(value) {
35
35
  const grid = tableGrid(value), offset = Number(grid.hasHeaders), count = grid.rowCount - offset;
@@ -38,562 +38,6 @@ function tableRowBoundaries(value) {
38
38
  return [...allowed];
39
39
  }
40
40
 
41
- // src/generated/catalog-ids.ts
42
- var catalogIds = {
43
- audiences: [
44
- "executives",
45
- "board",
46
- "engineering-team",
47
- "investors",
48
- "customers",
49
- "sales-team",
50
- "marketing-team",
51
- "all-hands",
52
- "candidates",
53
- "regulators",
54
- "executive",
55
- "investor",
56
- "technical",
57
- "sales",
58
- "marketing",
59
- "academic",
60
- "internal-team",
61
- "customer",
62
- "general-public",
63
- "media",
64
- "partner",
65
- "regulatory"
66
- ],
67
- purposes: [
68
- "inform",
69
- "decide",
70
- "align",
71
- "persuade",
72
- "educate",
73
- "report",
74
- "pitch",
75
- "sell",
76
- "plan"
77
- ],
78
- tones: [
79
- "formal",
80
- "casual",
81
- "inspirational",
82
- "technical",
83
- "persuasive",
84
- "authoritative",
85
- "conversational"
86
- ],
87
- themes: [
88
- "minimal",
89
- "classic",
90
- "dark",
91
- "bold"
92
- ],
93
- layouts: [
94
- "blank",
95
- "chart-1x",
96
- "chart-2x",
97
- "chart-3x",
98
- "code-1x",
99
- "image-1x",
100
- "image-2x",
101
- "image-3x",
102
- "image-bleed",
103
- "list-1x",
104
- "list-2x",
105
- "list-3x",
106
- "list-4x",
107
- "list-5x",
108
- "list-6x",
109
- "media-1x",
110
- "number-1x",
111
- "number-2x",
112
- "number-3x",
113
- "number-4x",
114
- "number-5x",
115
- "number-6x",
116
- "quote-1x",
117
- "table-1x",
118
- "text-1x",
119
- "text-2x",
120
- "text-3x",
121
- "timeline-1x",
122
- "title",
123
- "title-subtitle",
124
- "title-slide",
125
- "two-column",
126
- "image-focus",
127
- "data-visualization",
128
- "quote-highlight",
129
- "section-divider",
130
- "agenda",
131
- "thank-you-cta",
132
- "bullet-list",
133
- "three-column",
134
- "icon-grid",
135
- "faq",
136
- "stats-metrics",
137
- "comparison",
138
- "swot-analysis",
139
- "matrix-quadrant",
140
- "funnel-pyramid",
141
- "timeline",
142
- "process-flow",
143
- "photo-grid",
144
- "before-after",
145
- "testimonial-grid",
146
- "team-bio",
147
- "pricing-table",
148
- "roadmap",
149
- "product-feature",
150
- "executive-summary",
151
- "key-takeaway",
152
- "chapter-recap",
153
- "qa-discussion",
154
- "single-message-statement",
155
- "one-column-explainer",
156
- "case-study",
157
- "pros-cons",
158
- "feature-comparison-matrix",
159
- "venn-overlap",
160
- "decision-tree",
161
- "kpi-scorecard",
162
- "dashboard",
163
- "waterfall-bridge",
164
- "benchmark-target-table",
165
- "heatmap-cohort",
166
- "risk-heatmap",
167
- "forecast-scenario",
168
- "swimlane-process",
169
- "gantt-project-plan",
170
- "circular-lifecycle",
171
- "customer-journey",
172
- "org-chart",
173
- "capability-map",
174
- "logic-tree",
175
- "hub-and-spoke",
176
- "architecture-stack",
177
- "ecosystem-map",
178
- "network-dependency-map",
179
- "wheel-radial",
180
- "geographic-map",
181
- "screenshot-walkthrough",
182
- "market-size",
183
- "persona-grid",
184
- "competitive-landscape",
185
- "business-model-canvas",
186
- "customer-logos",
187
- "executive-decision",
188
- "status-rag",
189
- "raci-matrix",
190
- "action-plan",
191
- "assumptions-dependencies",
192
- "appendix-index",
193
- "detailed-data-table"
194
- ],
195
- chartTypes: [
196
- "100pct-stacked-area-3x",
197
- "100pct-stacked-bar-3x",
198
- "100pct-stacked-column-3x",
199
- "area",
200
- "bar",
201
- "box-and-whisker",
202
- "column",
203
- "doughnut",
204
- "filled-radar",
205
- "funnel",
206
- "histogram",
207
- "line",
208
- "line-with-markers",
209
- "pareto",
210
- "pie",
211
- "radar",
212
- "radar-with-markers",
213
- "scatter",
214
- "stacked-area-3x",
215
- "stacked-bar-3x",
216
- "stacked-column-3x",
217
- "stacked-line-3x",
218
- "stacked-line-with-markers-3x",
219
- "treemap",
220
- "waterfall",
221
- "world",
222
- "100pct-bullet-bar",
223
- "100pct-bullet-bar-2x",
224
- "100pct-bullet-bar-3x",
225
- "100pct-bullet-column",
226
- "100pct-bullet-column-2x",
227
- "100pct-bullet-column-3x",
228
- "100pct-progress-bar",
229
- "100pct-stacked-area-2x",
230
- "100pct-stacked-bar-2x",
231
- "100pct-stacked-column-2x",
232
- "australia",
233
- "box-and-whisker-2x",
234
- "box-and-whisker-3x",
235
- "bullet-bar",
236
- "bullet-bar-2x",
237
- "bullet-bar-3x",
238
- "bullet-column",
239
- "bullet-column-2x",
240
- "bullet-column-3x",
241
- "canada",
242
- "clustered-bar-2x",
243
- "clustered-column",
244
- "dot-plot",
245
- "dot-plot-2x",
246
- "dot-plot-3x",
247
- "dot-plot-4x",
248
- "dot-plot-5x",
249
- "dot-plot-6x",
250
- "dumbbell",
251
- "line-2x",
252
- "line-3x",
253
- "line-with-high-low",
254
- "line-with-high-low-and-markers",
255
- "line-with-markers-2x",
256
- "line-with-markers-3x",
257
- "sparkline",
258
- "sparkline-2x",
259
- "sparkline-3x",
260
- "sparkline-4x",
261
- "sparkline-5x",
262
- "sparkline-6x",
263
- "stacked-area-2x",
264
- "stacked-bar-2x",
265
- "stacked-column-2x",
266
- "stacked-line-2x",
267
- "stacked-line-with-markers-2x",
268
- "treemap-2x",
269
- "treemap-3x",
270
- "united-kingdom",
271
- "united-states"
272
- ],
273
- narratives: [
274
- "problem-solution",
275
- "scqa",
276
- "pyramid-principle",
277
- "situation-complication-resolution",
278
- "what-so-what-now-what",
279
- "strategic-narrative",
280
- "golden-circle",
281
- "conference-talk",
282
- "transformation-arc",
283
- "pitch-deck",
284
- "early-startup-pitch",
285
- "venture-pitch",
286
- "persuasive-sales",
287
- "sparkline",
288
- "company-intro",
289
- "marketing-strategy",
290
- "product-launch",
291
- "strategic-advisory",
292
- "challenge-resolution",
293
- "project-proposal",
294
- "vision-roadmap",
295
- "failure-analysis",
296
- "star-method",
297
- "classic-story",
298
- "heros-journey",
299
- "business-narrative",
300
- "change-story",
301
- "rags-to-riches",
302
- "underdog-victory",
303
- "survival-story",
304
- "educate",
305
- "persuade",
306
- "reveal",
307
- "justice",
308
- "innovation",
309
- "focus",
310
- "qbr",
311
- "business-review",
312
- "board-meeting",
313
- "weekly-progress",
314
- "status-update",
315
- "performance-review",
316
- "survey-analysis",
317
- "trend-analysis",
318
- "data-story",
319
- "employee-review",
320
- "performance-improvement-plan",
321
- "capacity-planning"
322
- ],
323
- socialPlatforms: [
324
- "linkedin",
325
- "x",
326
- "github",
327
- "youtube",
328
- "instagram",
329
- "facebook",
330
- "tiktok",
331
- "threads",
332
- "mastodon",
333
- "bluesky"
334
- ],
335
- languages: [
336
- "afrikaans",
337
- "albanian",
338
- "amharic",
339
- "arabic",
340
- "armenian",
341
- "aymara",
342
- "azerbaijani",
343
- "bengali",
344
- "berber-latin",
345
- "bosnian-latin",
346
- "bulgarian",
347
- "catalan",
348
- "cebuano",
349
- "chinese-simplified",
350
- "chinese-traditional",
351
- "chittagonian",
352
- "croatian",
353
- "czech",
354
- "danish",
355
- "dutch",
356
- "english",
357
- "english-au",
358
- "english-ca",
359
- "english-gb",
360
- "english-in",
361
- "english-us",
362
- "estonian",
363
- "filipino",
364
- "finnish",
365
- "french",
366
- "fulfulde",
367
- "galician",
368
- "georgian",
369
- "german",
370
- "greek",
371
- "gujarati",
372
- "hausa",
373
- "hebrew",
374
- "hindi",
375
- "hungarian",
376
- "igbo",
377
- "indonesian",
378
- "italian",
379
- "japanese",
380
- "kannada",
381
- "kazakh",
382
- "khmer",
383
- "kinyarwanda",
384
- "korean",
385
- "kurmanji",
386
- "latvian",
387
- "lithuanian",
388
- "macedonian",
389
- "malagasy",
390
- "malay",
391
- "malayalam",
392
- "maori",
393
- "marathi",
394
- "mongolian",
395
- "nepali",
396
- "norwegian",
397
- "odia",
398
- "oromo",
399
- "pashto",
400
- "persian",
401
- "polish",
402
- "portuguese",
403
- "punjabi-gurmukhi",
404
- "punjabi-shahmukhi",
405
- "romanian",
406
- "russian",
407
- "serbian-cyrillic",
408
- "serbian-latin",
409
- "shona",
410
- "slovak",
411
- "slovenian",
412
- "somali",
413
- "spanish",
414
- "swahili",
415
- "swedish",
416
- "tagalog",
417
- "tajik",
418
- "tamil",
419
- "telugu",
420
- "thai",
421
- "turkish",
422
- "ukrainian",
423
- "urdu",
424
- "uzbek-latin",
425
- "vietnamese-quoc-ngu",
426
- "xhosa",
427
- "yoruba",
428
- "zulu"
429
- ],
430
- colorSchemes: [
431
- "black-and-white",
432
- "bold-red",
433
- "boost",
434
- "burnt-orange",
435
- "cool-horizon",
436
- "corporate-blue",
437
- "deep-purple",
438
- "forest-green",
439
- "golden-yellow",
440
- "luxury",
441
- "pastel-red",
442
- "slate-gray",
443
- "steel-blue",
444
- "vibes"
445
- ],
446
- fontSchemes: [
447
- "consolas",
448
- "courier-new",
449
- "arial",
450
- "calibri",
451
- "impact",
452
- "lucida-sans",
453
- "segoe-ui",
454
- "segoe-ui-light",
455
- "tahoma",
456
- "trebuchet-ms",
457
- "verdana",
458
- "bookman",
459
- "century-schoolbook",
460
- "constantia",
461
- "garamond",
462
- "rockwell",
463
- "times-new-roman",
464
- "aptos",
465
- "grandview",
466
- "seaford",
467
- "skeena",
468
- "tenorite",
469
- "georgia",
470
- "microsoft-yahei",
471
- "simsun",
472
- "fangsong",
473
- "yu-gothic",
474
- "pmingliu",
475
- "mingliu",
476
- "ms-mincho",
477
- "malgun-gothic",
478
- "batang",
479
- "gungsuh",
480
- "mangal",
481
- "nirmala-ui",
482
- "latha",
483
- "david",
484
- "miriam",
485
- "gisha",
486
- "vrinda",
487
- "shruti",
488
- "tunga",
489
- "kartika",
490
- "kalinga",
491
- "raavi",
492
- "gautami",
493
- "arabic-typesetting",
494
- "microsoft-jhenghei",
495
- "meiryo",
496
- "angsana-new",
497
- "aparajita",
498
- "dilleniaupc",
499
- "sakkal-majalla",
500
- "shonar-bangla",
501
- "sylfaen",
502
- "traditional-arabic",
503
- "montserrat",
504
- "open-sans",
505
- "poppins",
506
- "pt-serif",
507
- "raleway",
508
- "roboto",
509
- "noto-sans-arabic",
510
- "noto-sans-armenian",
511
- "noto-sans-bengali",
512
- "noto-sans-devangari",
513
- "noto-sans-georgian",
514
- "noto-sans-gujarati",
515
- "noto-sans-gurmukhi",
516
- "noto-sans-hebrew",
517
- "noto-sans-jp",
518
- "noto-sans-kannada",
519
- "noto-sans-kr",
520
- "noto-sans-malayalam",
521
- "noto-sans-mongolian",
522
- "noto-sans-oriya",
523
- "noto-sans-sc",
524
- "noto-sans-tamil",
525
- "noto-sans-tc",
526
- "noto-sans-telugu",
527
- "noto-sans",
528
- "noto-sans-thai",
529
- "noto-nastaliq-urdu",
530
- "noto-naksh-arabic",
531
- "noto-sans-ethiopic",
532
- "noto-sans-khmer",
533
- "nyala",
534
- "daunpenh",
535
- "khmer-ui"
536
- ]
537
- };
538
- var deprecatedCatalogIds = {
539
- "audiences/executives": "executive",
540
- "audiences/investors": "investor",
541
- "audiences/customers": "customer",
542
- "audiences/sales-team": "sales",
543
- "audiences/marketing-team": "marketing",
544
- "audiences/regulators": "regulatory",
545
- "chartTypes/100pct-bullet-bar": "100pct-stacked-bar-3x",
546
- "chartTypes/100pct-bullet-bar-2x": "100pct-stacked-bar-3x",
547
- "chartTypes/100pct-bullet-bar-3x": "100pct-stacked-bar-3x",
548
- "chartTypes/100pct-bullet-column": "100pct-stacked-column-3x",
549
- "chartTypes/100pct-bullet-column-2x": "100pct-stacked-column-3x",
550
- "chartTypes/100pct-bullet-column-3x": "100pct-stacked-column-3x",
551
- "chartTypes/100pct-progress-bar": "100pct-stacked-bar-3x",
552
- "chartTypes/100pct-stacked-area-2x": "100pct-stacked-area-3x",
553
- "chartTypes/100pct-stacked-bar-2x": "100pct-stacked-bar-3x",
554
- "chartTypes/100pct-stacked-column-2x": "100pct-stacked-column-3x",
555
- "chartTypes/australia": "world",
556
- "chartTypes/box-and-whisker-2x": "box-and-whisker",
557
- "chartTypes/box-and-whisker-3x": "box-and-whisker",
558
- "chartTypes/bullet-bar": "bar",
559
- "chartTypes/bullet-bar-2x": "bar",
560
- "chartTypes/bullet-bar-3x": "bar",
561
- "chartTypes/bullet-column": "column",
562
- "chartTypes/bullet-column-2x": "column",
563
- "chartTypes/bullet-column-3x": "column",
564
- "chartTypes/canada": "world",
565
- "chartTypes/clustered-bar-2x": "bar",
566
- "chartTypes/clustered-column": "column",
567
- "chartTypes/dot-plot": "scatter",
568
- "chartTypes/dot-plot-2x": "scatter",
569
- "chartTypes/dot-plot-3x": "scatter",
570
- "chartTypes/dot-plot-4x": "scatter",
571
- "chartTypes/dot-plot-5x": "scatter",
572
- "chartTypes/dot-plot-6x": "scatter",
573
- "chartTypes/dumbbell": "scatter",
574
- "chartTypes/line-2x": "line",
575
- "chartTypes/line-3x": "line",
576
- "chartTypes/line-with-high-low": "line",
577
- "chartTypes/line-with-high-low-and-markers": "line-with-markers",
578
- "chartTypes/line-with-markers-2x": "line-with-markers",
579
- "chartTypes/line-with-markers-3x": "line-with-markers",
580
- "chartTypes/sparkline": "line",
581
- "chartTypes/sparkline-2x": "line",
582
- "chartTypes/sparkline-3x": "line",
583
- "chartTypes/sparkline-4x": "line",
584
- "chartTypes/sparkline-5x": "line",
585
- "chartTypes/sparkline-6x": "line",
586
- "chartTypes/stacked-area-2x": "stacked-area-3x",
587
- "chartTypes/stacked-bar-2x": "stacked-bar-3x",
588
- "chartTypes/stacked-column-2x": "stacked-column-3x",
589
- "chartTypes/stacked-line-2x": "stacked-line-3x",
590
- "chartTypes/stacked-line-with-markers-2x": "stacked-line-with-markers-3x",
591
- "chartTypes/treemap-2x": "treemap",
592
- "chartTypes/treemap-3x": "treemap",
593
- "chartTypes/united-kingdom": "world",
594
- "chartTypes/united-states": "world"
595
- };
596
-
597
41
  // src/chart-options.ts
598
42
  var END_POSITIONS = ["center", "inside-end", "inside-base", "outside-end"];
599
43
  var STACKED_POSITIONS = ["center", "inside-end", "inside-base"];
@@ -602,9 +46,12 @@ var PIE_POSITIONS = ["center", "inside-end", "outside-end"];
602
46
  var NONE = [];
603
47
  var VALUE_CATEGORY = ["category", "value"];
604
48
  var ALL_CONTENT = ["category", "value", "percent"];
605
- var categoryKinds = /* @__PURE__ */ new Set(["bar", "line", "area", "scatter", "histogram", "pareto", "box", "waterfall", "funnel"]);
606
- var valueKinds = /* @__PURE__ */ new Set(["bar", "line", "area", "scatter", "histogram", "pareto", "box", "waterfall"]);
607
- var legendKinds = /* @__PURE__ */ new Set(["bar", "line", "area", "pie", "doughnut", "scatter", "radar", "box"]);
49
+ var COMBO_POSITIONS = ["center", "inside-end", "inside-base", "outside-end", "above", "below", "left", "right"];
50
+ var categoryKinds = /* @__PURE__ */ new Set(["bar", "line", "area", "scatter", "histogram", "pareto", "box", "waterfall", "funnel", "combo"]);
51
+ var valueKinds = /* @__PURE__ */ new Set(["bar", "line", "area", "scatter", "histogram", "pareto", "box", "waterfall", "combo"]);
52
+ var legendKinds = /* @__PURE__ */ new Set(["bar", "line", "area", "pie", "doughnut", "scatter", "radar", "box", "combo"]);
53
+ var highlightSeriesKinds = /* @__PURE__ */ new Set(["bar", "line", "area", "scatter", "radar"]);
54
+ var highlightCategoryKinds = /* @__PURE__ */ new Set(["bar", "line", "pie", "doughnut"]);
608
55
  function labelSupport(target) {
609
56
  const none = { supported: true, content: VALUE_CATEGORY, positions: NONE, defaultPosition: null, defaultOn: false };
610
57
  switch (target.kind) {
@@ -613,6 +60,9 @@ function labelSupport(target) {
613
60
  case "line":
614
61
  case "scatter":
615
62
  return { ...none, positions: POINT_POSITIONS, defaultPosition: "above" };
63
+ // Columns take the clustered positions and lines the point positions ('center' fits both); each part falls back to its own default.
64
+ case "combo":
65
+ return { ...none, positions: COMBO_POSITIONS, defaultPosition: "outside-end" };
616
66
  case "pie":
617
67
  return { ...none, content: ALL_CONTENT, positions: PIE_POSITIONS, defaultPosition: "outside-end" };
618
68
  case "doughnut":
@@ -634,25 +84,26 @@ function labelSupport(target) {
634
84
  }
635
85
  function chartOptionSupport(target) {
636
86
  return {
637
- axisTitles: { category: categoryKinds.has(target.kind), value: valueKinds.has(target.kind) },
87
+ axisTitles: { category: categoryKinds.has(target.kind), value: valueKinds.has(target.kind), secondary: target.kind === "combo" },
638
88
  legend: legendKinds.has(target.kind),
89
+ highlight: { series: highlightSeriesKinds.has(target.kind), categories: highlightCategoryKinds.has(target.kind) },
639
90
  dataLabels: labelSupport(target)
640
91
  };
641
92
  }
642
93
  var KEPT = {
643
94
  column: { kind: "bar" },
644
- "stacked-column-3x": { kind: "bar", stacked: true },
645
- "100pct-stacked-column-3x": { kind: "bar", stacked: true },
95
+ "stacked-column": { kind: "bar", stacked: true },
96
+ "100pct-stacked-column": { kind: "bar", stacked: true },
646
97
  bar: { kind: "bar" },
647
- "stacked-bar-3x": { kind: "bar", stacked: true },
648
- "100pct-stacked-bar-3x": { kind: "bar", stacked: true },
98
+ "stacked-bar": { kind: "bar", stacked: true },
99
+ "100pct-stacked-bar": { kind: "bar", stacked: true },
649
100
  line: { kind: "line" },
650
101
  "line-with-markers": { kind: "line" },
651
- "stacked-line-3x": { kind: "line", stacked: true },
652
- "stacked-line-with-markers-3x": { kind: "line", stacked: true },
102
+ "stacked-line": { kind: "line", stacked: true },
103
+ "stacked-line-with-markers": { kind: "line", stacked: true },
653
104
  area: { kind: "area" },
654
- "stacked-area-3x": { kind: "area", stacked: true },
655
- "100pct-stacked-area-3x": { kind: "area", stacked: true },
105
+ "stacked-area": { kind: "area", stacked: true },
106
+ "100pct-stacked-area": { kind: "area", stacked: true },
656
107
  pie: { kind: "pie" },
657
108
  doughnut: { kind: "doughnut" },
658
109
  scatter: { kind: "scatter" },
@@ -665,14 +116,14 @@ var KEPT = {
665
116
  "box-and-whisker": { kind: "box" },
666
117
  waterfall: { kind: "waterfall" },
667
118
  funnel: { kind: "funnel" },
668
- world: { kind: "map" }
119
+ world: { kind: "map" },
120
+ combo: { kind: "combo" }
669
121
  };
670
122
  function chartOptionTarget(typeId) {
671
123
  if (typeof typeId !== "string") return void 0;
672
124
  const raw = typeId.trim().toLowerCase();
673
125
  const id = raw === "donut" ? "doughnut" : raw;
674
- const kept = deprecatedCatalogIds[`chartTypes/${id}`] ?? id;
675
- const target = Object.hasOwn(KEPT, kept) ? KEPT[kept] : void 0;
126
+ const target = Object.hasOwn(KEPT, id) ? KEPT[id] : void 0;
676
127
  return target ? { ...target } : void 0;
677
128
  }
678
129
  var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -686,11 +137,25 @@ function resolveChartOptions(chart, target) {
686
137
  const support = target ? chartOptionSupport(target) : void 0;
687
138
  const adapt = (option, reason, message) => result.diagnostics.push({ code: "chart-option-adapted", option, reason, message });
688
139
  const kind2 = target?.kind ?? "unknown";
140
+ const combo = target?.kind === "combo";
141
+ if (!combo) {
142
+ for (const option of ["line", "secondaryAxis"]) {
143
+ if (chart[option] !== void 0) adapt(option, "unsupported-type", `Only a 'combo' chart draws line series${option === "secondaryAxis" ? " on a secondary axis" : ""}; ${option} is ignored on a '${kind2}' chart.`);
144
+ }
145
+ }
689
146
  if (record2(chart.axisTitles)) {
690
- for (const axis of ["category", "value"]) {
147
+ for (const axis of ["category", "value", "secondary"]) {
691
148
  const raw = chart.axisTitles[axis];
692
149
  if (typeof raw !== "string" || !raw.trim()) continue;
693
- if (support && !support.axisTitles[axis]) {
150
+ if (axis === "secondary" && support && !support.axisTitles.secondary) {
151
+ adapt("axisTitles.secondary", "unsupported-type", `Only a 'combo' chart has a secondary value axis; the secondary axis title is not drawn or exported on a '${kind2}' chart.`);
152
+ continue;
153
+ }
154
+ if (axis === "secondary" && combo && !(Array.isArray(chart.secondaryAxis) && chart.secondaryAxis.some((name) => typeof name === "string"))) {
155
+ adapt("axisTitles.secondary", "unsupported-type", "This combo chart plots no series on a secondary axis (secondaryAxis is absent); the secondary axis title is not drawn or exported.");
156
+ continue;
157
+ }
158
+ if (axis !== "secondary" && support && !support.axisTitles[axis]) {
694
159
  adapt(`axisTitles.${axis}`, "unsupported-type", `A '${kind2}' chart has no ${axis} axis to title; the ${axis} axis title is not drawn or exported.`);
695
160
  continue;
696
161
  }
@@ -717,8 +182,18 @@ function resolveChartOptions(chart, target) {
717
182
  if (!content.length) content.push("value");
718
183
  const positions = support?.dataLabels.positions ?? NONE;
719
184
  let position = support?.dataLabels.defaultPosition ?? null;
720
- if (typeof options.position === "string" && POSITIONS.has(options.position) && options.position !== "auto") {
721
- if (!support || positions.includes(options.position)) position = options.position;
185
+ let linePosition;
186
+ const requestedPosition = typeof options.position === "string" && POSITIONS.has(options.position) && options.position !== "auto" ? options.position : void 0;
187
+ if (combo) {
188
+ linePosition = "above";
189
+ if (requestedPosition) {
190
+ if (END_POSITIONS.includes(requestedPosition)) position = requestedPosition;
191
+ else adapt("dataLabels.position", "unsupported-position", `The column series of a combo chart cannot place data labels '${requestedPosition}'; they use outside-end.`);
192
+ if (POINT_POSITIONS.includes(requestedPosition)) linePosition = requestedPosition;
193
+ else adapt("dataLabels.position", "unsupported-position", `The line series of a combo chart cannot place data labels '${requestedPosition}'; they use above.`);
194
+ }
195
+ } else if (requestedPosition) {
196
+ if (!support || positions.includes(requestedPosition)) position = requestedPosition;
722
197
  else adapt("dataLabels.position", "unsupported-position", `A '${kind2}'${target?.stacked ? " stacked" : ""} chart cannot place data labels '${options.position}'; the type's default position is used.`);
723
198
  }
724
199
  let separator = typeof options.separator === "string" ? options.separator : DEFAULT_CHART_LABEL_SEPARATOR;
@@ -726,10 +201,23 @@ function resolveChartOptions(chart, target) {
726
201
  separator = separator.replace(/[\r\n]+/g, " ");
727
202
  adapt("dataLabels.separator", "unsupported-content", "A data label is one line; the line break in the separator is replaced with a space.");
728
203
  }
729
- result.dataLabels = { content, position, separator };
204
+ result.dataLabels = { content, position, separator, ...linePosition ? { linePosition } : {} };
730
205
  }
731
206
  }
732
- result.active = result.legend !== void 0 || result.dataLabels !== void 0 || result.dataLabelsOff === true || result.axisTitles.category !== void 0 || result.axisTitles.value !== void 0;
207
+ if (record2(chart.highlight)) {
208
+ const names = (value) => Array.isArray(value) ? [...new Set(value.filter((entry) => typeof entry === "string"))] : [];
209
+ const kept = { series: [], categories: [] };
210
+ for (const part of ["series", "categories"]) {
211
+ const requested = names(chart.highlight[part]);
212
+ if (!requested.length) continue;
213
+ if (support && !support.highlight[part]) {
214
+ const alternative = part === "series" ? support.highlight.categories ? " (name categories instead)" : "" : support.highlight.series ? " (name series instead)" : "";
215
+ adapt(`highlight.${part}`, "unsupported-type", `A '${kind2}' chart cannot highlight ${part}${alternative}; the highlighted ${part} are ignored.`);
216
+ } else kept[part] = requested;
217
+ }
218
+ if (kept.series.length || kept.categories.length) result.highlight = kept;
219
+ }
220
+ result.active = result.legend !== void 0 || result.dataLabels !== void 0 || result.dataLabelsOff === true || result.axisTitles.category !== void 0 || result.axisTitles.value !== void 0 || result.axisTitles.secondary !== void 0;
733
221
  return result;
734
222
  }
735
223
  function formatChartLabelNumber(value) {
@@ -741,6 +229,14 @@ function formatChartLabelPercent(share) {
741
229
  function chartLabelText(parts, content, separator = DEFAULT_CHART_LABEL_SEPARATOR) {
742
230
  return CONTENT_ORDER.filter((part) => content.includes(part) && parts[part] !== void 0).map((part) => parts[part]).join(separator);
743
231
  }
232
+ function chartHighlightMarks(highlight, data) {
233
+ if (!highlight) return void 0;
234
+ const first = data.columns.length > 1 ? data.hasX ? 2 : 1 : 0;
235
+ const series = data.columns.slice(first).map((name) => highlight.series.includes(name));
236
+ const label = (cell) => cell === null || cell === void 0 ? "" : String(cell);
237
+ const categories = data.columns.length > 1 ? data.rows.map((row) => highlight.categories.includes(label(row[0]))) : data.rows.map(() => false);
238
+ return series.some(Boolean) || categories.some(Boolean) ? { series, categories } : void 0;
239
+ }
744
240
 
745
241
  // src/content-walk.ts
746
242
  function isRecord(value) {
@@ -928,6 +424,24 @@ function formatSlideNumber(format, current, total) {
928
424
  return { text: text2, fields: fields2 };
929
425
  }
930
426
 
427
+ // src/deck-metadata.ts
428
+ function recordsOf(value) {
429
+ return (Array.isArray(value) ? value : value === void 0 || value === null ? [] : [value]).filter(isRecord);
430
+ }
431
+ function speakersOf(presentation) {
432
+ return isRecord(presentation) ? recordsOf(presentation.speaker) : [];
433
+ }
434
+ function organizationsOf(presentation) {
435
+ return isRecord(presentation) ? recordsOf(presentation.organization) : [];
436
+ }
437
+ function primarySpeaker(presentation) {
438
+ return speakersOf(presentation)[0];
439
+ }
440
+ function primaryOrganization(presentation) {
441
+ const organizations = organizationsOf(presentation);
442
+ return organizations.find((item) => item.role === "primary") ?? organizations[0];
443
+ }
444
+
931
445
  // src/variables.ts
932
446
  var VARIABLE_KINDS = ["color", "text", "number", "date", "image", "url", "list"];
933
447
  var DEFAULT_VARIABLE_DATE_FORMAT = "MMMM d, yyyy";
@@ -941,12 +455,15 @@ var OPFVariableError = class extends Error {
941
455
  }
942
456
  };
943
457
  var idPattern = /^[a-z][a-z0-9-]*$/;
944
- var referencePattern = /^var:([a-z][a-z0-9-]*)$/;
458
+ var nameSource = String.raw`[a-z][a-z0-9-]*|(?:deck|speaker|organization)(?:\.[A-Za-z0-9_-]+){1,2}`;
459
+ var referencePattern = new RegExp(String.raw`^var:(${nameSource})$`);
460
+ var builtinNamePattern = /^(?:speakers|(?:deck|speaker|organization)(?:\.[A-Za-z0-9_-]+){1,2})$/;
461
+ var builtinUsePattern = /\{\{\s*(?:speakers\b|(?:deck|speaker|organization)\.)|^var:(?:speakers$|(?:deck|speaker|organization)\.)/;
945
462
  var hexPattern = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
946
463
  var urlPattern = /^(?:https?:\/\/|mailto:|tel:)\S+$/;
947
464
  var datePrefixPattern = /^(\d{4}-\d{2}-\d{2})(?:[T ].*)?$/;
948
465
  var decimalPattern = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
949
- var tokenPattern = /\\\{\{|\{\{\s*([a-z][a-z0-9-]*)\s*(?:\|([^{}]*))?\}\}/g;
466
+ var tokenPattern = new RegExp(String.raw`\\\{\{|\{\{\s*(${nameSource})\s*(?:\|([^{}]*))?\}\}`, "g");
950
467
  var SAMPLES = {
951
468
  color: "#000000",
952
469
  text: "Sample text",
@@ -1039,8 +556,18 @@ function variableDeclarations(presentation) {
1039
556
  }
1040
557
  return out;
1041
558
  }
559
+ function usesBuiltins(value, root = true) {
560
+ if (typeof value === "string") return value.length >= 6 && builtinUsePattern.test(value);
561
+ if (Array.isArray(value)) return value.some((entry) => usesBuiltins(entry, false));
562
+ if (!isRecord(value)) return false;
563
+ for (const [key, entry] of Object.entries(value)) {
564
+ if (skippedKeys.has(key) || root && skippedRootKeys.has(key)) continue;
565
+ if (usesBuiltins(entry, false)) return true;
566
+ }
567
+ return false;
568
+ }
1042
569
  function hasContentVariables(presentation) {
1043
- return isTemplate(presentation) || variableDeclarations(presentation).some((declaration) => declaration.kind !== "color");
570
+ return isTemplate(presentation) || variableDeclarations(presentation).some((declaration) => declaration.kind !== "color") || usesBuiltins(presentation);
1044
571
  }
1045
572
  var POSITIVE_ZERO = "0";
1046
573
  function formatVariableNumber(value, pattern) {
@@ -1127,6 +654,93 @@ function inlineText(effective, format, path, context) {
1127
654
  return value.join(format ?? ", ");
1128
655
  }
1129
656
  }
657
+ var DECK_FIELDS = { name: "text", description: "text", author: "text" };
658
+ var SPEAKER_FIELDS = { name: "text", title: "text", email: "text", phone: "text", bio: "text", photo: "image" };
659
+ var ORGANIZATION_FIELDS = { name: "text", legalName: "text", tagline: "text", domain: "text", email: "text", phone: "text", logo: "image" };
660
+ function isBuiltinName(name) {
661
+ return builtinNamePattern.test(name);
662
+ }
663
+ function builtinFields(root) {
664
+ return root === "deck" ? DECK_FIELDS : root === "speaker" ? SPEAKER_FIELDS : ORGANIZATION_FIELDS;
665
+ }
666
+ function present(value) {
667
+ if (typeof value === "string") return value.trim() === "" ? void 0 : value;
668
+ if (isRecord(value)) return typeof value.src === "string" && value.src.trim() ? value : void 0;
669
+ return void 0;
670
+ }
671
+ function builtinSource(name, doc) {
672
+ if (name === "speakers") {
673
+ const names = speakersOf(doc).map((speaker) => present(speaker.name)).filter((entry) => typeof entry === "string");
674
+ return { ok: true, kind: "list", raw: names.length ? names : void 0 };
675
+ }
676
+ const parts = name.split(".");
677
+ const root = parts[0];
678
+ const fields2 = builtinFields(root);
679
+ const list = (names) => names.map((entry) => `'${entry}'`).join(", ");
680
+ if (root === "deck") {
681
+ const field2 = parts[1];
682
+ if (parts.length !== 2 || !Object.hasOwn(fields2, field2)) return { ok: false, message: `'${name}' is not a built-in variable; the deck built-ins are ${list(Object.keys(fields2).map((key) => `deck.${key}`))}.` };
683
+ const value = doc[field2];
684
+ return { ok: true, kind: "text", raw: field2 === "author" && Array.isArray(value) ? present(value.filter((entry) => typeof entry === "string").join(", ")) : present(value) };
685
+ }
686
+ const field = parts[parts.length - 1];
687
+ if (!Object.hasOwn(fields2, field)) {
688
+ return { ok: false, message: `'${name}' is not a built-in variable: '${field}' is not a ${root} field; the fields are ${list(Object.keys(fields2))}.` };
689
+ }
690
+ let entity;
691
+ if (parts.length === 2) entity = root === "speaker" ? primarySpeaker(doc) : primaryOrganization(doc);
692
+ else {
693
+ const id = parts[1];
694
+ const entries = root === "speaker" ? speakersOf(doc) : organizationsOf(doc);
695
+ entity = entries.find((entry) => entry.id === id);
696
+ if (!entity) return { ok: false, message: `'${name}' names no ${root} with id '${id}'.` };
697
+ }
698
+ return { ok: true, kind: fields2[field], raw: present(entity?.[field]) };
699
+ }
700
+ function builtinEffective(name, path, context) {
701
+ if (context.resolvingBuiltins.has(name)) return void 0;
702
+ const cached = context.builtins.get(name);
703
+ if (cached !== void 0) {
704
+ if (cached === null) diag(context, unknownBuiltin(name, path, context), `ubi:${name}:${path}`);
705
+ else if (cached.status === "unfilled") diag(context, missingBuiltin(name, path), `bim:${name}:${path}`);
706
+ return cached ?? void 0;
707
+ }
708
+ const source = builtinSource(name, context.doc);
709
+ if (!source.ok) {
710
+ context.builtins.set(name, null);
711
+ diag(context, unknownBuiltin(name, path, context), `ubi:${name}:${path}`);
712
+ return void 0;
713
+ }
714
+ const declaration = { id: name, kind: source.kind, path: "", required: context.keepMissingBuiltins };
715
+ let effective;
716
+ const coerced = source.raw === void 0 ? void 0 : coerceVariableValue(source.kind, source.raw);
717
+ if (coerced?.ok) {
718
+ let value = coerced.value;
719
+ if (typeof value === "string" && value.includes("{{")) {
720
+ context.resolvingBuiltins.add(name);
721
+ value = interpolate(value, path, context).value;
722
+ context.resolvingBuiltins.delete(name);
723
+ }
724
+ effective = { declaration: { ...declaration, value }, status: "filled", value, provided: false };
725
+ } else {
726
+ effective = { declaration, status: "unfilled", provided: false };
727
+ diag(context, missingBuiltin(name, path), `bim:${name}:${path}`);
728
+ }
729
+ context.builtins.set(name, effective);
730
+ return effective;
731
+ }
732
+ function unknownBuiltin(name, path, context) {
733
+ const source = builtinSource(name, context.doc);
734
+ return { code: "variable-unknown-builtin", severity: "error", path, id: name, message: source.ok ? `'${name}' is not a built-in variable.` : source.message };
735
+ }
736
+ function missingBuiltin(name, path) {
737
+ return { code: "variable-builtin-missing", severity: "warning", path, id: name, message: `Built-in '${name}' has no value in this document, so it resolves to nothing; add the field it reads (see docs/templates-and-variables.md).` };
738
+ }
739
+ function lookupVariable(id, path, context) {
740
+ const declared = context.effective.get(id);
741
+ if (declared || !isBuiltinName(id)) return declared;
742
+ return builtinEffective(id, path, context);
743
+ }
1130
744
  function interpolate(text2, path, context) {
1131
745
  let changed = false;
1132
746
  const value = text2.replace(tokenPattern, (match, id, format) => {
@@ -1138,9 +752,9 @@ function interpolate(text2, path, context) {
1138
752
  return match;
1139
753
  }
1140
754
  context.uses.push({ id, path, form: "token" });
1141
- const effective = context.effective.get(id);
755
+ const effective = lookupVariable(id, path, context);
1142
756
  if (!effective) {
1143
- diag(context, { code: "variable-unknown", severity: "warning", path, id, message: `'{{${id}}}' names no declared variable; declare '${id}' in the top-level variables map, or write '\\{{' for literal braces.` }, `unk:${id}:${path}`);
757
+ if (!isBuiltinName(id)) diag(context, { code: "variable-unknown", severity: "warning", path, id, message: `'{{${id}}}' names no declared variable; declare '${id}' in the top-level variables map, or write '\\{{' for literal braces.` }, `unk:${id}:${path}`);
1144
758
  return match;
1145
759
  }
1146
760
  if (effective.status === "unfilled" && !context.shape) {
@@ -1168,7 +782,7 @@ function reduceString(text2, path, parentIsArray, context) {
1168
782
  const reference = referencePattern.exec(text2);
1169
783
  if (reference) {
1170
784
  const id = reference[1];
1171
- const effective = context.effective.get(id);
785
+ const effective = lookupVariable(id, path, context);
1172
786
  if (effective && effective.declaration.kind !== "color") {
1173
787
  context.uses.push({ id, path, form: "reference" });
1174
788
  if (effective.status === "unfilled" && !context.shape) {
@@ -1250,7 +864,11 @@ function plan(presentation, values, options) {
1250
864
  unescape: false,
1251
865
  shape: options.shape === true,
1252
866
  content: hasContentVariables(presentation) || template,
1253
- seen: /* @__PURE__ */ new Set()
867
+ seen: /* @__PURE__ */ new Set(),
868
+ doc: presentation,
869
+ keepMissingBuiltins: options.examples === true,
870
+ builtins: /* @__PURE__ */ new Map(),
871
+ resolvingBuiltins: /* @__PURE__ */ new Set()
1254
872
  };
1255
873
  const unfilled = [];
1256
874
  const examplesUsed = [];
@@ -1374,6 +992,32 @@ function listVariables(presentation, values = {}) {
1374
992
  };
1375
993
  });
1376
994
  }
995
+ var FIELD_LABELS = { name: "name", legalName: "legal name", tagline: "tagline", domain: "domain", email: "email", phone: "phone", logo: "logo", title: "title", bio: "bio", photo: "photo", description: "description", author: "author" };
996
+ function listBuiltinVariables(presentation) {
997
+ if (!isRecord(presentation)) return [];
998
+ const names = [];
999
+ for (const field of Object.keys(DECK_FIELDS)) names.push({ name: `deck.${field}`, label: `Deck ${FIELD_LABELS[field]}` });
1000
+ for (const field of Object.keys(SPEAKER_FIELDS)) names.push({ name: `speaker.${field}`, label: `Speaker ${FIELD_LABELS[field]}` });
1001
+ names.push({ name: "speakers", label: "All speaker names" });
1002
+ for (const field of Object.keys(ORGANIZATION_FIELDS)) names.push({ name: `organization.${field}`, label: `Organization ${FIELD_LABELS[field]}` });
1003
+ for (const [root, entries] of [["speaker", speakersOf(presentation)], ["organization", organizationsOf(presentation)]]) {
1004
+ for (const entry of entries) {
1005
+ if (typeof entry.id !== "string" || entry.id === "") continue;
1006
+ for (const field of Object.keys(builtinFields(root))) names.push({ name: `${root}.${entry.id}.${field}`, label: `${root === "speaker" ? "Speaker" : "Organization"} ${entry.id} ${FIELD_LABELS[field]}` });
1007
+ }
1008
+ }
1009
+ const built = plan(presentation, {}, { examples: false, partial: true, shape: true });
1010
+ built.context.content = true;
1011
+ walk(presentation, "", false, built.context);
1012
+ const out = [];
1013
+ for (const { name, label } of names) {
1014
+ const source = builtinSource(name, presentation);
1015
+ if (!source.ok) continue;
1016
+ const coerced = source.raw === void 0 ? void 0 : coerceVariableValue(source.kind, source.raw);
1017
+ out.push({ name, kind: source.kind, label, ...coerced?.ok ? { value: coerced.value } : {}, available: coerced?.ok === true, uses: built.context.uses.filter((use) => use.id === name) });
1018
+ }
1019
+ return out;
1020
+ }
1377
1021
 
1378
1022
  // src/chart-data.ts
1379
1023
  var record3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -1451,7 +1095,7 @@ function excelInteger(integer) {
1451
1095
  const placeholders = "#".repeat(width - zeros) + "0".repeat(zeros);
1452
1096
  return placeholders.replace(/\B(?=(.{3})+$)/g, ",");
1453
1097
  }
1454
- function excelNumberFormat(format) {
1098
+ function toExcelNumberFormat(format) {
1455
1099
  if (format === void 0 || format === "") return "General";
1456
1100
  const parts = formatParts(format);
1457
1101
  if (!parts) return "General";
@@ -1489,7 +1133,7 @@ function excelTokens(code) {
1489
1133
  }
1490
1134
  return tokens;
1491
1135
  }
1492
- function numberFormatFromExcel(code) {
1136
+ function fromExcelNumberFormat(code) {
1493
1137
  if (typeof code !== "string") return void 0;
1494
1138
  const trimmed = code.trim();
1495
1139
  if (trimmed === "" || /^general$/i.test(trimmed)) return void 0;
@@ -1580,8 +1224,8 @@ function inlinedData(ref, datasets) {
1580
1224
  const diagnostics = [];
1581
1225
  const selection = selectFields(dataset.columns, ref.fields, "", "", diagnostics);
1582
1226
  if (diagnostics.some((entry) => entry.code === "dataset-field-unknown")) return void 0;
1583
- const rows2 = dataset.rows.map((row) => selection.indices.map((index) => Array.isArray(row) && index < row.length ? structuredClone(row[index]) : null));
1584
- return { columns: selection.columns.map(inlineColumn), rows: rows2, ...record3(dataset.source) ? { source: structuredClone(dataset.source) } : {} };
1227
+ const rows3 = dataset.rows.map((row) => selection.indices.map((index) => Array.isArray(row) && index < row.length ? structuredClone(row[index]) : null));
1228
+ return { columns: selection.columns.map(inlineColumn), rows: rows3, ...record3(dataset.source) ? { source: structuredClone(dataset.source) } : {} };
1585
1229
  }
1586
1230
  function inlineDatasets(document) {
1587
1231
  if (!record3(document)) return document;
@@ -1655,7 +1299,7 @@ function resolveChartData(chart, document, options = {}) {
1655
1299
  const data = record3(chart) ? chart.data : void 0;
1656
1300
  if (!record3(data)) return fail("no-columns", "The chart has no data.");
1657
1301
  let columns2;
1658
- let rows2;
1302
+ let rows3;
1659
1303
  let columnsPath;
1660
1304
  let rowsPath;
1661
1305
  let source;
@@ -1675,15 +1319,12 @@ function resolveChartData(chart, document, options = {}) {
1675
1319
  const selection = selectFields(dataset.columns, data.fields, at(base, "data", "fields"), columnsPath, diagnostics);
1676
1320
  columns2 = selection.columns;
1677
1321
  selected = selection.indices;
1678
- rows2 = dataset.rows;
1322
+ rows3 = dataset.rows;
1679
1323
  if (record3(dataset.source)) source = dataset.source;
1680
- } else if (typeof data.src === "string") {
1681
- diagnostics.push({ code: "chart-data-source-unresolved", severity: "warning", path: at(base, "data", "src"), message: `chart data source '${data.src}' is not loaded by any engine; the preview and export draw a placeholder. Import the data inline (columns and rows, with a 'source' for provenance) or reference a dataset` });
1682
- return fail("data-not-inline", "The chart reads an external data source, which no engine resolves.");
1683
1324
  } else {
1684
1325
  if (!Array.isArray(data.columns)) return fail("no-columns", "The chart data has no columns.");
1685
1326
  columns2 = data.columns;
1686
- rows2 = Array.isArray(data.rows) ? data.rows : [];
1327
+ rows3 = Array.isArray(data.rows) ? data.rows : [];
1687
1328
  columnsPath = at(base, "data", "columns");
1688
1329
  rowsPath = at(base, "data", "rows");
1689
1330
  formatDiagnostics(columns2, columnsPath, diagnostics);
@@ -1741,10 +1382,46 @@ function resolveChartData(chart, document, options = {}) {
1741
1382
  series = [x];
1742
1383
  x = void 0;
1743
1384
  }
1385
+ let combo;
1386
+ if (record3(chart) && chartOptionTarget(chart.type)?.kind === "combo") {
1387
+ const listed = (option, problem) => {
1388
+ const found = /* @__PURE__ */ new Set();
1389
+ const value = chart[option];
1390
+ if (!Array.isArray(value)) return found;
1391
+ value.forEach((name, index) => {
1392
+ const path = at(base, option, index);
1393
+ const column = known(name, path);
1394
+ if (column === void 0) return;
1395
+ const reason = problem(column);
1396
+ if (reason) diagnostics.push({ code: "chart-mapping-adapted", severity: "warning", path, message: `${JSON.stringify(name)} ${reason}` });
1397
+ else found.add(column);
1398
+ });
1399
+ return found;
1400
+ };
1401
+ const notPlotted = "is not a plotted series of the chart";
1402
+ const lines = listed("line", (column) => series.includes(column) ? void 0 : `${notPlotted}; it is not drawn as a line`);
1403
+ if (chart.line === void 0 && series.length >= 2) lines.add(series[series.length - 1]);
1404
+ if (series.length && series.every((column) => lines.has(column))) {
1405
+ lines.delete(series[0]);
1406
+ diagnostics.push({ code: "chart-mapping-adapted", severity: "warning", path: at(base, chart.line === void 0 ? "type" : "line"), message: series.length === 1 ? `a combo chart needs at least two series, one drawn as columns and one as a line; its one series ${JSON.stringify(names[series[0]])} is drawn as columns` : `a combo chart keeps at least one column series; ${JSON.stringify(names[series[0]])} is drawn as columns, not as a line` });
1407
+ } else if (series.length === 1) {
1408
+ diagnostics.push({ code: "chart-mapping-adapted", severity: "warning", path: at(base, "type"), message: `a combo chart needs at least two series, one drawn as columns and one as a line; its one series ${JSON.stringify(names[series[0]])} is drawn as columns` });
1409
+ }
1410
+ const secondary = listed("secondaryAxis", (column) => !series.includes(column) ? `${notPlotted}; it has no axis to move to` : !lines.has(column) ? "is drawn as columns; only a line series can use the secondary axis, so it stays on the primary axis" : void 0);
1411
+ const bars = series.filter((column) => !lines.has(column));
1412
+ const primaryLines = series.filter((column) => lines.has(column) && !secondary.has(column));
1413
+ const secondaryLines = series.filter((column) => lines.has(column) && secondary.has(column));
1414
+ series = [...bars, ...primaryLines, ...secondaryLines];
1415
+ combo = [
1416
+ ...bars.map(() => ({ role: "bar", axis: "primary" })),
1417
+ ...primaryLines.map(() => ({ role: "line", axis: "primary" })),
1418
+ ...secondaryLines.map(() => ({ role: "line", axis: "secondary" }))
1419
+ ];
1420
+ }
1744
1421
  const order = [category, ...x === void 0 ? [] : [x], ...series];
1745
- if (!rows2.length) return fail("no-rows", "The chart data has no rows.");
1422
+ if (!rows3.length) return fail("no-rows", "The chart data has no rows.");
1746
1423
  const lone = names.length === 1 && !diagnostics.some((entry) => entry.code === "dataset-field-unknown");
1747
- const out = rows2.map((row, rowIndex) => order.map((column, position) => {
1424
+ const out = rows3.map((row, rowIndex) => order.map((column, position) => {
1748
1425
  const sourceIndex = selected ? selected[column] : column;
1749
1426
  const cell = Array.isArray(row) && sourceIndex < row.length ? row[sourceIndex] : null;
1750
1427
  if (position === 0 && !lone) return cell === void 0 ? null : cell;
@@ -1754,6 +1431,26 @@ function resolveChartData(chart, document, options = {}) {
1754
1431
  }
1755
1432
  return number;
1756
1433
  }));
1434
+ const highlight = record3(chart) && record3(chart.highlight) ? chart.highlight : void 0;
1435
+ if (highlight) {
1436
+ const plotted = order.slice(order.length - series.length).map((index) => names[index]);
1437
+ const labels = lone ? void 0 : new Set(out.map((row) => row[0] === null || row[0] === void 0 ? "" : String(row[0])));
1438
+ const listed = (value) => Array.isArray(value) ? value : [];
1439
+ const highlightPath = at(base, "highlight");
1440
+ listed(highlight.series).forEach((name, index) => {
1441
+ const path = at(highlightPath, "series", index);
1442
+ if (typeof name !== "string" || !names.includes(name)) {
1443
+ diagnostics.push({ code: "chart-highlight-unknown-name", severity: "error", path, message: `highlight names series ${JSON.stringify(name)}, which the chart data does not have as a column; use one of ${names.map((entry) => JSON.stringify(entry)).join(", ")}` });
1444
+ } else if (!plotted.includes(name)) {
1445
+ diagnostics.push({ code: "chart-highlight-adapted", severity: "warning", path, message: `highlight names column ${JSON.stringify(name)}, which is not plotted as a series (it is the category or X column, or the mapping leaves it out); it highlights nothing` });
1446
+ }
1447
+ });
1448
+ listed(highlight.categories).forEach((name, index) => {
1449
+ if (typeof name === "string" && labels?.has(name)) return;
1450
+ const shown = labels ? [...labels].slice(0, 12).map((entry) => JSON.stringify(entry)).join(", ") : "";
1451
+ diagnostics.push({ code: "chart-highlight-unknown-name", severity: "error", path: at(highlightPath, "categories", index), message: `highlight names category ${JSON.stringify(name)}, which no row of the chart data has as its label${shown ? `; the labels are ${shown}${labels.size > 12 ? ", ..." : ""}` : ""}` });
1452
+ });
1453
+ }
1757
1454
  return {
1758
1455
  ok: true,
1759
1456
  columns: order.map((index) => names[index]),
@@ -1762,6 +1459,7 @@ function resolveChartData(chart, document, options = {}) {
1762
1459
  rows: out,
1763
1460
  ...source ? { source } : {},
1764
1461
  ...datasetId !== void 0 ? { dataset: datasetId } : {},
1462
+ ...combo ? { combo } : {},
1765
1463
  diagnostics
1766
1464
  };
1767
1465
  }
@@ -1778,18 +1476,18 @@ function chartNumberFixes(chart, document, options) {
1778
1476
  if (!candidates.size) return fixes;
1779
1477
  const data = chart.data;
1780
1478
  let columns2;
1781
- let rows2;
1479
+ let rows3;
1782
1480
  let columnsPath;
1783
1481
  let rowsPath;
1784
1482
  if (isDatasetRef(data)) {
1785
1483
  const dataset = datasetsOf(document)[data.dataset];
1786
1484
  columns2 = dataset.columns;
1787
- rows2 = dataset.rows;
1485
+ rows3 = dataset.rows;
1788
1486
  columnsPath = at("/datasets", data.dataset, "columns");
1789
1487
  rowsPath = at("/datasets", data.dataset, "rows");
1790
1488
  } else {
1791
1489
  columns2 = data.columns;
1792
- rows2 = data.rows;
1490
+ rows3 = data.rows;
1793
1491
  columnsPath = at(options.path ?? "", "data", "columns");
1794
1492
  rowsPath = at(options.path ?? "", "data", "rows");
1795
1493
  }
@@ -1797,7 +1495,7 @@ function chartNumberFixes(chart, document, options) {
1797
1495
  const header = columns2[column];
1798
1496
  const name = columnName(header);
1799
1497
  if (name === void 0 || columnFormat(header) !== void 0) continue;
1800
- const fix = columnFix(rows2, column, rowsPath);
1498
+ const fix = columnFix(rows3, column, rowsPath);
1801
1499
  if (!fix) continue;
1802
1500
  fixes.set(column, {
1803
1501
  patches: [...fix.patches, { op: "replace", path: at(columnsPath, column), value: record3(header) ? { ...header, format: fix.format } : { name, format: fix.format } }],
@@ -1808,14 +1506,14 @@ function chartNumberFixes(chart, document, options) {
1808
1506
  }
1809
1507
  return fixes;
1810
1508
  }
1811
- function columnFix(rows2, column, rowsPath) {
1509
+ function columnFix(rows3, column, rowsPath) {
1812
1510
  const cells = [];
1813
1511
  let prefix;
1814
1512
  let suffix;
1815
1513
  let grouping = false;
1816
1514
  let wide = false;
1817
1515
  const decimals = [];
1818
- for (const [index, row] of rows2.entries()) {
1516
+ for (const [index, row] of rows3.entries()) {
1819
1517
  const cell = Array.isArray(row) && column < row.length ? row[column] : null;
1820
1518
  if (cell === null || cell === void 0 || cell === "") continue;
1821
1519
  const patch = chartNumber(cell) === null;
@@ -1870,12 +1568,12 @@ function resolveTableData(table, document, options = {}) {
1870
1568
  const columnsPath = at("/datasets", id, "columns");
1871
1569
  formatDiagnostics(dataset.columns, columnsPath, diagnostics);
1872
1570
  const selection = selectFields(dataset.columns, table.fields, at(base, "fields"), columnsPath, diagnostics);
1873
- const rows3 = dataset.rows.map((row) => selection.indices.map((index) => Array.isArray(row) && index < row.length ? row[index] : null));
1874
- return { columns: selection.columns, rows: rows3, formats: selection.formats, dataset: id, diagnostics };
1571
+ const rows4 = dataset.rows.map((row) => selection.indices.map((index) => Array.isArray(row) && index < row.length ? row[index] : null));
1572
+ return { columns: selection.columns, rows: rows4, formats: selection.formats, dataset: id, diagnostics };
1875
1573
  }
1876
1574
  const columns2 = Array.isArray(table.columns) ? table.columns : void 0;
1877
- const rows2 = Array.isArray(table.rows) ? table.rows.filter(Array.isArray) : [];
1878
- const width = Math.max(columns2?.length ?? 0, ...rows2.map((row) => row.length), 0);
1575
+ const rows3 = Array.isArray(table.rows) ? table.rows.filter(Array.isArray) : [];
1576
+ const width = Math.max(columns2?.length ?? 0, ...rows3.map((row) => row.length), 0);
1879
1577
  const formats = Array.from({ length: width }, (_, index) => {
1880
1578
  const header = columns2?.[index];
1881
1579
  return columnFormat(header) ?? cellFormat(header);
@@ -1893,7 +1591,7 @@ function resolveTableData(table, document, options = {}) {
1893
1591
  check(cell, at(base, "rows", rowIndex, index));
1894
1592
  });
1895
1593
  });
1896
- return { ...columns2 ? { columns: columns2 } : {}, rows: rows2, formats, diagnostics };
1594
+ return { ...columns2 ? { columns: columns2 } : {}, rows: rows3, formats, diagnostics };
1897
1595
  }
1898
1596
  function tableCellDisplayValue(cell, columnFormat2) {
1899
1597
  if (record3(cell) && own(cell, "value")) {
@@ -2019,6 +1717,38 @@ function intrinsicImageAspect(value, assets) {
2019
1717
  return size ? size.width / size.height : void 0;
2020
1718
  }
2021
1719
 
1720
+ // src/design-hints.ts
1721
+ var DESIGN_HINT_KEYS = ["titleAlignment", "contentAlignment", "contentBox", "contentDirection", "chartPrimary", "imageFill", "listBullet"];
1722
+ var ALIGNMENTS = ["left", "center", "right"];
1723
+ var VALUES = {
1724
+ titleAlignment: ALIGNMENTS,
1725
+ contentAlignment: ALIGNMENTS,
1726
+ contentBox: "boolean",
1727
+ contentDirection: ["horizontal", "vertical"],
1728
+ chartPrimary: ["none", "top", "bottom", "left", "right"],
1729
+ imageFill: ["crop", "fit"],
1730
+ listBullet: ["character", "image"]
1731
+ };
1732
+ var accepts = (key, value) => VALUES[key] === "boolean" ? typeof value === "boolean" : VALUES[key].includes(value);
1733
+ var object = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
1734
+ function resolveDesignHints(options = {}) {
1735
+ const slide = object(object(options.slide).design), host = object(options.deck), deck = object(object(options.presentation).design), layout = object(object(options.layout).design);
1736
+ const index = options.slideIndex ?? 0;
1737
+ const result = { sources: {}, paths: {} };
1738
+ const set2 = (key, value, source, path) => {
1739
+ result[key] = value;
1740
+ result.sources[key] = source;
1741
+ result.paths[key] = path;
1742
+ };
1743
+ for (const key of DESIGN_HINT_KEYS) {
1744
+ if (accepts(key, slide[key])) set2(key, slide[key], "slide", `slides.${index}.design.${key}`);
1745
+ else if (accepts(key, host[key])) set2(key, host[key], "deck", `design.${key}`);
1746
+ else if (accepts(key, deck[key])) set2(key, deck[key], "deck", `design.${key}`);
1747
+ else if (accepts(key, layout[key])) set2(key, layout[key], "layout", `slides.${index}.layout`);
1748
+ }
1749
+ return result;
1750
+ }
1751
+
2022
1752
  // src/reading-order.ts
2023
1753
  function visualReadingOrder(items, direction = "ltr") {
2024
1754
  const index = new Map(items.map((item, i) => [item, i]));
@@ -2028,18 +1758,18 @@ function visualReadingOrder(items, direction = "ltr") {
2028
1758
  function readingRows(items) {
2029
1759
  const index = new Map(items.map((item, i) => [item, i]));
2030
1760
  const sorted = [...items].sort((a, b) => a.box.y - b.box.y || a.box.x - b.box.x || index.get(a) - index.get(b));
2031
- const rows2 = [];
1761
+ const rows3 = [];
2032
1762
  for (const item of sorted) {
2033
1763
  const centre = item.box.y + item.box.height / 2;
2034
- const row = rows2.find((candidate) => centre >= candidate.top && centre <= candidate.bottom);
1764
+ const row = rows3.find((candidate) => centre >= candidate.top && centre <= candidate.bottom);
2035
1765
  if (row) {
2036
1766
  row.items.push(item);
2037
1767
  row.top = Math.min(row.top, item.box.y);
2038
1768
  row.bottom = Math.max(row.bottom, item.box.y + item.box.height);
2039
- } else rows2.push({ top: item.box.y, bottom: item.box.y + item.box.height, items: [item] });
1769
+ } else rows3.push({ top: item.box.y, bottom: item.box.y + item.box.height, items: [item] });
2040
1770
  }
2041
- rows2.sort((a, b) => a.top - b.top);
2042
- return rows2.map((row) => row.items.sort((a, b) => index.get(a) - index.get(b)));
1771
+ rows3.sort((a, b) => a.top - b.top);
1772
+ return rows3.map((row) => row.items.sort((a, b) => index.get(a) - index.get(b)));
2043
1773
  }
2044
1774
 
2045
1775
  // src/direction.ts
@@ -2083,6 +1813,12 @@ function paragraphDirectionAt(text2, deckDirection) {
2083
1813
  }
2084
1814
 
2085
1815
  // src/script-fonts.ts
1816
+ function normalizeLanguageFamily(value) {
1817
+ if (value === "latin") return "latin";
1818
+ if (value === "ea" || value === "eastAsian") return "ea";
1819
+ if (value === "cs" || value === "complexScript") return "cs";
1820
+ return void 0;
1821
+ }
2086
1822
  var eastAsianScripts = /* @__PURE__ */ new Set(["Hani", "Hans", "Hant", "Hanb", "Jpan", "Kore", "Hang", "Jamo", "Hira", "Kana", "Hrkt", "Bopo", "Yiii"]);
2087
1823
  var complexScripts = /* @__PURE__ */ new Set([
2088
1824
  "Arab",
@@ -2253,13 +1989,8 @@ function pairFamilies(value) {
2253
1989
  function schemeServesLanguage(scheme, language) {
2254
1990
  const entries = Array.isArray(scheme.languages) ? scheme.languages.filter((entry) => typeof entry === "string") : [];
2255
1991
  if (entries.length === 0) return true;
2256
- const name = text(language.name)?.toLowerCase();
2257
- if (!name) return false;
2258
- const base = name.replace(/\s*\([^)]*\)\s*$/, "");
2259
- return entries.some((entry) => {
2260
- const value = entry.trim().toLowerCase();
2261
- return value === name || value === base;
2262
- });
1992
+ const id = text(language.id);
1993
+ return id !== void 0 && entries.includes(id);
2263
1994
  }
2264
1995
  function resolveScriptFonts(input, options = {}) {
2265
1996
  const document = isRecord(input) ? input : {};
@@ -2291,16 +2022,16 @@ function resolveScriptFonts(input, options = {}) {
2291
2022
  const scriptRole = scriptFontRole(script);
2292
2023
  const declaredDirection = record6.direction;
2293
2024
  const direction = declaredDirection === "rtl" || declaredDirection === "ltr" ? declaredDirection : rtlScripts.has(script) ? "rtl" : "ltr";
2294
- const app = options.app ?? "PowerPoint";
2295
- const preferred = app === "Google Slides" ? record6.googleFontScheme : record6.fontScheme;
2296
- const alternate = app === "Google Slides" ? record6.fontScheme : record6.googleFontScheme;
2025
+ const app = options.app ?? "powerpoint";
2026
+ const preferred = app === "google-slides" ? record6.googleFontScheme : record6.fontScheme;
2027
+ const alternate = app === "google-slides" ? record6.fontScheme : record6.googleFontScheme;
2297
2028
  const languageScheme = resolveReference(lookup, "fontSchemes", preferred) ?? resolveReference(lookup, "fontSchemes", alternate);
2298
2029
  const languageFamilies = pairFamilies(languageScheme);
2299
2030
  const schemeAdmitsLanguage = schemeServesLanguage(scheme, record6);
2300
2031
  const slot = (role, family) => {
2301
2032
  const explicit = pairFamilies(scheme[role]);
2302
2033
  if (explicit) return { ...explicit, source: "fontScheme" };
2303
- if (scheme.languageFamily === family && schemeAdmitsLanguage) return { ...latin, source: "schemeFamily" };
2034
+ if (normalizeLanguageFamily(scheme.languageFamily) === family && schemeAdmitsLanguage) return { ...latin, source: "schemeFamily" };
2304
2035
  if (scriptRole === role && languageFamilies) return { ...languageFamilies, source: "language" };
2305
2036
  return { heading: latin.heading, body: latin.body, source: "latin" };
2306
2037
  };
@@ -2403,10 +2134,10 @@ function listNumbers(items, numbering) {
2403
2134
  const levels = resolveNumbering(numbering);
2404
2135
  const counters = [];
2405
2136
  return items.map((item, index) => {
2406
- const object = isObject(item) ? item : void 0;
2407
- const level = object?.level === void 0 ? 0 : object.level;
2137
+ const object2 = isObject(item) ? item : void 0;
2138
+ const level = object2?.level === void 0 ? 0 : object2.level;
2408
2139
  if (typeof level !== "number" || !Number.isInteger(level) || level < 0) throw new RangeError("List levels must be nonnegative integers.");
2409
- const own2 = object?.start;
2140
+ const own2 = object2?.start;
2410
2141
  if (own2 !== void 0 && (typeof own2 !== "number" || !Number.isInteger(own2) || own2 < 1 || own2 > MAX_NUMBERING_VALUE)) throw new RangeError(`A list item start must be an integer from 1 to ${MAX_NUMBERING_VALUE}.`);
2411
2142
  const { style: authored, start, suffix } = numberingAtLevel(levels, level);
2412
2143
  const previous = counters[level];
@@ -2425,8 +2156,8 @@ function sliceNumberedItems(items, numbering, from, to = items.length) {
2425
2156
  const wanted = whole[from + index].value;
2426
2157
  if (listNumbers(result.slice(0, index + 1), numbering)[index].value === wanted) continue;
2427
2158
  const item = result[index];
2428
- const object = isObject(item) ? item : { text: item };
2429
- result[index] = { ...object, start: wanted };
2159
+ const object2 = isObject(item) ? item : { text: item };
2160
+ result[index] = { ...object2, start: wanted };
2430
2161
  }
2431
2162
  return result;
2432
2163
  }
@@ -2479,6 +2210,7 @@ var schemeColorRoles = /* @__PURE__ */ new Set([
2479
2210
  "accent",
2480
2211
  "background",
2481
2212
  "surface",
2213
+ "surfaceAlt",
2482
2214
  "text",
2483
2215
  "textSecondary"
2484
2216
  ]);
@@ -2522,6 +2254,11 @@ function resolveColorRef(reference, options) {
2522
2254
  const roleKey = reference;
2523
2255
  const fromRoles = roles?.[roleKey];
2524
2256
  if (fromRoles) return normalizeHexColor(fromRoles) ?? fallback;
2257
+ if (reference === "surfaceAlt") {
2258
+ const surface = resolveColorRef("surface", { colorScheme, roles, variables, fallback: "#FFFFFF" });
2259
+ const text2 = resolveColorRef("text", { colorScheme, roles, variables, fallback: textColorForFill(surface, "#000000") });
2260
+ return surfaceAltColor(surface, text2);
2261
+ }
2525
2262
  const fromScheme = normalizeHexColor(colorScheme[reference]);
2526
2263
  if (fromScheme) return fromScheme;
2527
2264
  const slot = defaultRoleSlots[reference];
@@ -2530,6 +2267,52 @@ function resolveColorRef(reference, options) {
2530
2267
  if (schemeColorSlots.has(reference)) return schemeSlot(colorScheme, reference, fallback);
2531
2268
  return fallback;
2532
2269
  }
2270
+ var DARK_BACKGROUND_LUMINANCE = 0.179;
2271
+ function isDarkColor(color) {
2272
+ const hex = normalizeHexColor(color);
2273
+ const value = hex ? luminance(hex) : void 0;
2274
+ return value !== void 0 && value < DARK_BACKGROUND_LUMINANCE;
2275
+ }
2276
+ function defaultSlideBackground(colorScheme) {
2277
+ return keepAlpha(colorScheme.background) ?? slotKeepingAlpha(colorScheme, "light1", "#FFFFFF");
2278
+ }
2279
+ function keepAlpha(value) {
2280
+ if (typeof value !== "string") return void 0;
2281
+ const hex = value.trim();
2282
+ if (/^#[0-9a-f]{8}$/i.test(hex)) return hex.toUpperCase();
2283
+ return normalizeHexColor(hex);
2284
+ }
2285
+ function slotKeepingAlpha(colorScheme, slot, fallback) {
2286
+ return keepAlpha(colorScheme[slot]) ?? fallback;
2287
+ }
2288
+ var DEFAULT_HYPERLINK = "#0563C1";
2289
+ var DEFAULT_FOLLOWED_HYPERLINK = "#954F72";
2290
+ var MIN_LINK_CONTRAST = 4.5;
2291
+ function readableLink(link, background, text2) {
2292
+ const linkHex = normalizeHexColor(link), backgroundHex = normalizeHexColor(background);
2293
+ const contrast2 = linkHex && backgroundHex ? colorContrast(linkHex, backgroundHex) : void 0;
2294
+ return contrast2 !== void 0 && contrast2 < MIN_LINK_CONTRAST ? text2 : link;
2295
+ }
2296
+ function resolveColorRoles(colorScheme, options = {}) {
2297
+ const slot = (name, fallback) => slotKeepingAlpha(colorScheme, name, fallback);
2298
+ const background = keepAlpha(options.background) ?? defaultSlideBackground(colorScheme);
2299
+ const dark = isDarkColor(background);
2300
+ const text2 = dark ? slot("light1", "#FFFFFF") : keepAlpha(colorScheme.text) ?? slot("dark1", "#111827");
2301
+ const surface = keepAlpha(colorScheme.surface) ?? (dark ? slot("dark2", "#1E293B") : slot("light2", "#F8FAFC"));
2302
+ return {
2303
+ primary: keepAlpha(colorScheme.primary) ?? slot("accent1", "#2563EB"),
2304
+ secondary: keepAlpha(colorScheme.secondary) ?? slot("accent2", "#0F766E"),
2305
+ accent: keepAlpha(colorScheme.accent) ?? slot("accent3", "#F59E0B"),
2306
+ background,
2307
+ surface,
2308
+ surfaceAlt: surfaceAltColor(surface, text2),
2309
+ text: text2,
2310
+ textSecondary: keepAlpha(colorScheme.textSecondary) ?? (dark ? slot("light2", "#E2E8F0") : slot("dark2", "#334155")),
2311
+ hyperlink: readableLink(slot("hyperlink", DEFAULT_HYPERLINK), background, text2),
2312
+ followedHyperlink: slot("followedHyperlink", DEFAULT_FOLLOWED_HYPERLINK),
2313
+ dark
2314
+ };
2315
+ }
2533
2316
  function luminance(value) {
2534
2317
  if (typeof value !== "string") return void 0;
2535
2318
  let hex = value.trim();
@@ -2547,19 +2330,19 @@ function colorContrast(foreground, background) {
2547
2330
  return a === void 0 || b === void 0 ? void 0 : (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
2548
2331
  }
2549
2332
  function textColorForFill(fill, preferred) {
2550
- const background = luminance(fill), contrast = colorContrast(preferred, fill);
2551
- if (background === void 0 || contrast === void 0 || contrast >= 4.5) return preferred;
2333
+ const background = luminance(fill), contrast2 = colorContrast(preferred, fill);
2334
+ if (background === void 0 || contrast2 === void 0 || contrast2 >= 4.5) return preferred;
2552
2335
  return (background + 0.05) / 0.05 >= 1.05 / (background + 0.05) ? "#000000" : "#FFFFFF";
2553
2336
  }
2554
2337
  function chartColorForFill(fill, preferred) {
2555
- const contrast = colorContrast(preferred, fill);
2556
- if (contrast === void 0 || contrast >= 3) return preferred;
2338
+ const contrast2 = colorContrast(preferred, fill);
2339
+ if (contrast2 === void 0 || contrast2 >= 3) return preferred;
2557
2340
  let hex = preferred.trim();
2558
2341
  if (hex.length === 4) hex = `#${[...hex.slice(1)].map((c) => c + c).join("")}`;
2559
- const channels = [1, 3, 5].map((offset) => Number.parseInt(hex.slice(offset, offset + 2), 16));
2342
+ const channels2 = [1, 3, 5].map((offset) => Number.parseInt(hex.slice(offset, offset + 2), 16));
2560
2343
  for (let step = 1; step <= 255; step++) {
2561
2344
  const candidates = [0, 255].map((target) => {
2562
- const color = `#${channels.map((channel) => Math.round(channel + (target - channel) * step / 255).toString(16).padStart(2, "0")).join("")}`.toUpperCase();
2345
+ const color = `#${channels2.map((channel) => Math.round(channel + (target - channel) * step / 255).toString(16).padStart(2, "0")).join("")}`.toUpperCase();
2563
2346
  return { color, contrast: colorContrast(color, fill) ?? 0 };
2564
2347
  }).sort((a, b) => b.contrast - a.contrast);
2565
2348
  const best = candidates[0];
@@ -2581,8 +2364,8 @@ var toLinear = (channel) => {
2581
2364
  return n <= 0.04045 ? n / 12.92 : ((n + 0.055) / 1.055) ** 2.4;
2582
2365
  };
2583
2366
  var fromLinear = (value) => 255 * (value <= 31308e-7 ? value * 12.92 : 1.055 * value ** (1 / 2.4) - 0.055);
2584
- function labOf(channels) {
2585
- const [r, g, b] = channels.map(toLinear);
2367
+ function labOf(channels2) {
2368
+ const [r, g, b] = channels2.map(toLinear);
2586
2369
  const f = (t) => t > 216 / 24389 ? Math.cbrt(t) : (24389 / 27 * t + 16) / 116;
2587
2370
  const fx = f((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / D65[0]), fy = f(0.2126729 * r + 0.7151522 * g + 0.072175 * b), fz = f((0.0193339 * r + 0.119192 * g + 0.9503041 * b) / D65[2]);
2588
2371
  return [116 * fy - 16, 500 * (fx - fy), 200 * (fy - fz)];
@@ -2598,21 +2381,21 @@ function labToLinear([l, a, b]) {
2598
2381
  ];
2599
2382
  return rgb.every((channel) => channel >= -5e-4 && channel <= 1.0005) ? rgb : void 0;
2600
2383
  }
2601
- var hexOfChannels = (channels) => `#${channels.map((channel) => Math.max(0, Math.min(255, Math.round(channel))).toString(16).padStart(2, "0")).join("").toUpperCase()}`;
2384
+ var hexOfChannels = (channels2) => `#${channels2.map((channel) => Math.max(0, Math.min(255, Math.round(channel))).toString(16).padStart(2, "0")).join("").toUpperCase()}`;
2602
2385
  function labWithLightness(l, a, b) {
2603
2386
  const chroma = Math.hypot(a, b), hue = Math.atan2(b, a);
2604
2387
  const at3 = (scale) => labToLinear([l, Math.cos(hue) * chroma * scale, Math.sin(hue) * chroma * scale]);
2605
- let linear = at3(1);
2606
- if (!linear) {
2388
+ let linear2 = at3(1);
2389
+ if (!linear2) {
2607
2390
  let low = 0, high = 1;
2608
2391
  for (let step = 0; step < 24; step++) {
2609
2392
  const mid = (low + high) / 2;
2610
2393
  if (at3(mid)) low = mid;
2611
2394
  else high = mid;
2612
2395
  }
2613
- linear = at3(low) ?? [0, 0, 0];
2396
+ linear2 = at3(low) ?? [0, 0, 0];
2614
2397
  }
2615
- return hexOfChannels(linear.map((channel) => fromLinear(Math.max(0, Math.min(1, channel)))));
2398
+ return hexOfChannels(linear2.map((channel) => fromLinear(Math.max(0, Math.min(1, channel)))));
2616
2399
  }
2617
2400
  function labDifference(a, b) {
2618
2401
  return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);
@@ -2621,15 +2404,15 @@ var CHART_SERIES_SHORTFALL_WEIGHT = 8;
2621
2404
  function chartPaletteForFill(fill, palette) {
2622
2405
  const opaqueFill = colorContrast(fill, fill) !== void 0;
2623
2406
  const preferredLab = palette.map((color) => {
2624
- const channels = opaqueChannels(color);
2625
- return channels ? labOf(channels) : void 0;
2407
+ const channels2 = opaqueChannels(color);
2408
+ return channels2 ? labOf(channels2) : void 0;
2626
2409
  });
2627
2410
  const adjusted = palette.map((color) => chartColorForFill(fill, color));
2628
2411
  const kept = palette.map((color, index) => opaqueFill && preferredLab[index] !== void 0 && adjusted[index] === color);
2629
2412
  const placed = palette.map((_, index) => kept[index] || !opaqueFill || !preferredLab[index] ? adjusted[index] : void 0);
2630
2413
  const placedLab = placed.map((color) => {
2631
- const channels = color === void 0 ? void 0 : opaqueChannels(color);
2632
- return channels ? labOf(channels) : void 0;
2414
+ const channels2 = color === void 0 ? void 0 : opaqueChannels(color);
2415
+ return channels2 ? labOf(channels2) : void 0;
2633
2416
  });
2634
2417
  palette.forEach((_, index) => {
2635
2418
  const wanted = preferredLab[index], base = adjusted[index];
@@ -2653,8 +2436,8 @@ function chartPaletteForFill(fill, palette) {
2653
2436
  }
2654
2437
  let best = { color: base, lab: baseLab, cost: cost({ moved: 0, ...start }), moved: 0 };
2655
2438
  for (let step = 0; step <= 400; step++) {
2656
- const color = labWithLightness(step / 4, wanted[1], wanted[2]), contrast = colorContrast(color, fill);
2657
- if (contrast === void 0 || contrast < 3) continue;
2439
+ const color = labWithLightness(step / 4, wanted[1], wanted[2]), contrast2 = colorContrast(color, fill);
2440
+ if (contrast2 === void 0 || contrast2 < 3) continue;
2658
2441
  const lab = labOf(opaqueChannels(color)), moved = Math.abs(lab[0] - baseLab[0]), total = cost({ moved, ...shortfall(lab) });
2659
2442
  if (total < best.cost - 1e-9 || Math.abs(total - best.cost) <= 1e-9 && moved < best.moved) best = { color, lab, cost: total, moved };
2660
2443
  }
@@ -2663,6 +2446,1113 @@ function chartPaletteForFill(fill, palette) {
2663
2446
  });
2664
2447
  return placed;
2665
2448
  }
2449
+ var CHART_HIGHLIGHT_MUTED_MIX = 0.3;
2450
+ var CHART_HIGHLIGHT_MUTED_MIN_CONTRAST = 1.6;
2451
+ var mixChannels = (from, to, amount) => hexOfChannels(from.map((channel, index) => channel + (to[index] - channel) * amount));
2452
+ function chartHighlightColors(surface, primary, text2) {
2453
+ const fill = normalizeHexColor(surface) ?? "#FFFFFF";
2454
+ const accent = chartColorForFill(fill, normalizeHexColor(primary) ?? "#000000");
2455
+ const ink = normalizeHexColor(text2) ?? textColorForFill(fill, "#000000");
2456
+ const from = opaqueChannels(fill), to = opaqueChannels(ink);
2457
+ let muted = mixChannels(from, to, CHART_HIGHLIGHT_MUTED_MIX);
2458
+ for (let amount = CHART_HIGHLIGHT_MUTED_MIX; (colorContrast(muted, fill) ?? Infinity) < CHART_HIGHLIGHT_MUTED_MIN_CONTRAST && amount < 1; ) {
2459
+ amount = Math.min(1, amount + 0.02);
2460
+ muted = mixChannels(from, to, amount);
2461
+ }
2462
+ return { accent, muted };
2463
+ }
2464
+ var SURFACE_ALT_MIX = 0.1;
2465
+ var SURFACE_ALT_MIN_CONTRAST = 1.1;
2466
+ function surfaceAltColor(surface, text2) {
2467
+ const fill = normalizeHexColor(surface) ?? "#FFFFFF";
2468
+ const ink = normalizeHexColor(text2) ?? textColorForFill(fill, "#000000");
2469
+ const from = opaqueChannels(fill), toText = opaqueChannels(ink);
2470
+ const step = (color) => (colorContrast(color, fill) ?? 1) >= SURFACE_ALT_MIN_CONTRAST;
2471
+ const readable = (color) => (colorContrast(ink, color) ?? 0) >= 4.5 || (colorContrast(ink, color) ?? 0) >= (colorContrast(ink, fill) ?? 0);
2472
+ for (let amount = SURFACE_ALT_MIX; amount <= 0.5 + 1e-9; amount += 0.02) {
2473
+ const band = mixChannels(from, toText, amount);
2474
+ if (!readable(band)) break;
2475
+ if (step(band)) return band;
2476
+ }
2477
+ const away = (luminance(ink) ?? 0) > (luminance(fill) ?? 0) ? [0, 0, 0] : [255, 255, 255];
2478
+ for (let amount = SURFACE_ALT_MIX; amount <= 1 + 1e-9; amount += 0.02) {
2479
+ const band = mixChannels(from, away, Math.min(1, amount));
2480
+ if (step(band)) return band;
2481
+ }
2482
+ return mixChannels(from, toText, SURFACE_ALT_MIX);
2483
+ }
2484
+
2485
+ // src/legible-color.ts
2486
+ var channels = (hex) => [1, 3, 5].map((offset) => Number.parseInt(hex.slice(offset, offset + 2), 16));
2487
+ var toHex = (values) => `#${values.map((value) => Math.max(0, Math.min(255, Math.round(value))).toString(16).padStart(2, "0")).join("").toUpperCase()}`;
2488
+ var linear = (value) => {
2489
+ const n = value / 255;
2490
+ return n <= 0.04045 ? n / 12.92 : ((n + 0.055) / 1.055) ** 2.4;
2491
+ };
2492
+ var luminance2 = (hex) => {
2493
+ const [r, g, b] = channels(hex);
2494
+ return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);
2495
+ };
2496
+ var contrast = (a, b) => {
2497
+ const x = luminance2(a), y = luminance2(b);
2498
+ return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05);
2499
+ };
2500
+ var normalize = (value) => {
2501
+ if (typeof value !== "string") return void 0;
2502
+ const text2 = value.trim();
2503
+ if (/^#[0-9a-f]{3}$/i.test(text2)) return `#${[...text2.slice(1)].map((c) => c + c).join("")}`.toUpperCase();
2504
+ return /^#[0-9a-f]{6}([0-9a-f]{2})?$/i.test(text2) ? text2.slice(0, 7).toUpperCase() : void 0;
2505
+ };
2506
+ function toHsl(hex) {
2507
+ const [r, g, b] = channels(hex).map((value) => value / 255);
2508
+ const max = Math.max(r, g, b), min = Math.min(r, g, b), l = (max + min) / 2, d = max - min;
2509
+ if (d === 0) return [0, 0, l];
2510
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
2511
+ const h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
2512
+ return [h * 60, s, l];
2513
+ }
2514
+ function fromHsl(h, s, l) {
2515
+ const hue = (h % 360 + 360) % 360, c = (1 - Math.abs(2 * l - 1)) * s, x = c * (1 - Math.abs(hue / 60 % 2 - 1)), m = l - c / 2;
2516
+ const [r, g, b] = hue < 60 ? [c, x, 0] : hue < 120 ? [x, c, 0] : hue < 180 ? [0, c, x] : hue < 240 ? [0, x, c] : hue < 300 ? [x, 0, c] : [c, 0, x];
2517
+ return toHex([(r + m) * 255, (g + m) * 255, (b + m) * 255]);
2518
+ }
2519
+ function legible(foreground, background, minimum) {
2520
+ if (contrast(foreground, background) >= minimum) return foreground;
2521
+ const [h, s, l] = toHsl(foreground), preferred = luminance2(background) < 0.5 ? 1 : -1;
2522
+ for (const direction of [preferred, -preferred]) {
2523
+ for (let step = 1; step <= 100; step++) {
2524
+ const lightness = l + direction * step / 100;
2525
+ if (lightness < 0 || lightness > 1) break;
2526
+ const candidate = fromHsl(h, s, lightness);
2527
+ if (contrast(candidate, background) >= minimum) return candidate;
2528
+ }
2529
+ }
2530
+ return contrast("#FFFFFF", background) >= contrast("#000000", background) ? "#FFFFFF" : "#000000";
2531
+ }
2532
+
2533
+ // src/code-syntax.ts
2534
+ var CODE_HIGHLIGHT_MAX_LENGTH = 2e5;
2535
+ var CODE_SYNTAX_MIN_CONTRAST = 4.5;
2536
+ var CODE_PANEL_BACKGROUND = "#111827";
2537
+ var CODE_PANEL_FOREGROUND = "#E5E7EB";
2538
+ var set = (words) => new Set((words ?? "").split(/\s+/).filter(Boolean));
2539
+ var JS_KEYWORDS = "break case catch class const continue debugger default delete do else enum export extends finally for from function if import in instanceof let new of return static super switch this throw try typeof var void while with yield async await as get set declare namespace module abstract implements interface private protected public readonly override keyof satisfies type is infer";
2540
+ var JS = { line: ["//"], block: [["/*", "*/"]], strings: "'\"`", keywords: JS_KEYWORDS, literals: "true false null undefined NaN Infinity", types: "string number boolean object symbol bigint never unknown any void", defs: { function: "function", class: "type", interface: "type", enum: "type", type: "type" }, capsTypes: true, calls: true, decorators: true };
2541
+ var C_LIKE_KEYWORDS = "auto break case catch char class const constexpr continue default delete do double else enum explicit extern false final float for friend goto if inline int long mutable namespace new noexcept nullptr operator override private protected public register return short signed sizeof static struct switch template this throw true try typedef typename union unsigned using virtual void volatile while";
2542
+ var LANGUAGES = {
2543
+ javascript: JS,
2544
+ typescript: JS,
2545
+ python: { line: ["#"], strings: `'"`, triple: ['"""', "'''"], keywords: "and as assert async await break class continue def del elif else except finally for from global if import in is lambda nonlocal not or pass raise return try while with yield match case self cls", literals: "True False None", types: "int float str bool bytes list dict set tuple object type", defs: { def: "function", class: "type" }, capsTypes: true, calls: true, decorators: true },
2546
+ rust: { line: ["//"], block: [["/*", "*/"]], strings: '"', rawStrings: "r", keywords: "as async await break const continue crate dyn else enum extern fn for if impl in let loop match mod move mut pub ref return self Self static struct super trait type unsafe use where while", literals: "true false", types: "i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 bool char str String Vec Option Result Box", defs: { fn: "function", struct: "type", enum: "type", trait: "type", type: "type", mod: "type" }, capsTypes: true, calls: true, macros: true },
2547
+ go: { line: ["//"], block: [["/*", "*/"]], strings: "\"'`", noEscapes: "`", keywords: "break case chan const continue default defer else fallthrough for func go goto if import interface map package range return select struct switch type var", literals: "true false nil iota", types: "int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr float32 float64 complex64 complex128 string bool byte rune error any", defs: { func: "function", type: "type" }, capsTypes: true, calls: true },
2548
+ bash: { line: ["#"], strings: `'"`, noEscapes: "'", keywords: "if then else elif fi for while until do done case esac in function select time return exit break continue export local readonly declare unset set shift source alias trap eval exec", literals: "true false", variables: true, calls: false },
2549
+ json: { line: ["//"], block: [["/*", "*/"]], strings: '"', literals: "true false null", quotedKeys: true },
2550
+ yaml: { kind: "yaml" },
2551
+ toml: { kind: "ini", line: ["#"] },
2552
+ ini: { kind: "ini", line: ["#", ";"] },
2553
+ markup: { kind: "markup" },
2554
+ css: { kind: "css" },
2555
+ sql: { line: ["--"], block: [["/*", "*/"]], strings: `'"`, ci: true, keywords: "add all alter and any as asc between by case check column commit constraint create cross database default delete desc distinct drop else end exists foreign from full group having if in index inner insert into is join key left like limit not null offset on or order outer primary references replace right rollback select set table then top union unique update values view when where with", literals: "true false", types: "int integer bigint smallint decimal numeric float real double varchar char text date time timestamp boolean serial uuid json" },
2556
+ java: { line: ["//"], block: [["/*", "*/"]], strings: `"'`, keywords: "abstract assert break case catch class const continue default do else enum extends final finally for goto if implements import instanceof interface native new package private protected public return static strictfp super switch synchronized this throw throws transient try var volatile while record sealed permits", literals: "true false null", types: "boolean byte char double float int long short void String Object", defs: { class: "type", interface: "type", enum: "type", record: "type" }, capsTypes: true, calls: true, decorators: true },
2557
+ csharp: { line: ["//"], block: [["/*", "*/"]], strings: `"'`, keywords: "abstract as async await base break case catch checked class const continue default delegate do else enum event explicit extern finally fixed for foreach goto if implicit in interface internal is lock namespace new operator out override params private protected public readonly ref return sealed sizeof stackalloc static struct switch this throw try typeof unchecked unsafe using var virtual volatile while record init required", literals: "true false null", types: "bool byte char decimal double float int long object sbyte short string uint ulong ushort void dynamic", defs: { class: "type", interface: "type", struct: "type", enum: "type", record: "type" }, capsTypes: true, calls: true, decorators: false },
2558
+ kotlin: { line: ["//"], block: [["/*", "*/"]], strings: `"'`, triple: ['"""'], keywords: "abstract actual annotation as break by catch class companion const constructor continue crossinline data do else enum expect external final finally for fun get if import in infix init inline inner interface internal is it lateinit lazy noinline object open operator out override package private protected public reified return sealed set super suspend tailrec this throw try typealias val var vararg when where while", literals: "true false null", types: "Int Long Short Byte Float Double Boolean Char String Unit Any Nothing", defs: { fun: "function", class: "type", interface: "type", object: "type" }, capsTypes: true, calls: true, decorators: true },
2559
+ swift: { line: ["//"], block: [["/*", "*/"]], strings: '"', triple: ['"""'], keywords: "actor as associatedtype async await break case catch class continue default defer deinit do else enum extension fallthrough fileprivate for func guard if import in init inout internal is let nonisolated open operator private protocol public repeat rethrows return self Self static struct subscript super switch throw throws try typealias var where while", literals: "true false nil", types: "Int Double Float Bool String Character Array Dictionary Set Optional Any", defs: { func: "function", class: "type", struct: "type", enum: "type", protocol: "type", extension: "type" }, capsTypes: true, calls: true, decorators: true },
2560
+ ruby: { line: ["#"], strings: `'"`, keywords: "alias and begin break case class def defined do else elsif end ensure for if in module next not or redo rescue retry return self super then undef unless until when while yield require require_relative include extend attr_accessor attr_reader attr_writer private protected public", literals: "true false nil", defs: { def: "function", class: "type", module: "type" }, capsTypes: true, calls: true },
2561
+ php: { line: ["//", "#"], block: [["/*", "*/"]], strings: `'"`, keywords: "abstract and array as break callable case catch class clone const continue declare default do echo else elseif empty enddeclare endfor endforeach endif endswitch endwhile extends final finally fn for foreach function global goto if implements include include_once instanceof insteadof interface isset list match namespace new or print private protected public readonly require require_once return static switch throw trait try unset use var while xor yield", literals: "true false null TRUE FALSE NULL", defs: { function: "function", class: "type", interface: "type", trait: "type" }, capsTypes: true, calls: true, variables: true },
2562
+ c: { line: ["//"], block: [["/*", "*/"]], strings: `"'`, keywords: C_LIKE_KEYWORDS, literals: "true false NULL nullptr", types: "size_t ssize_t int8_t int16_t int32_t int64_t uint8_t uint16_t uint32_t uint64_t bool FILE", calls: true, capsTypes: false, directives: true, defs: { struct: "type", enum: "type", union: "type", class: "type" } },
2563
+ hcl: { line: ["#", "//"], block: [["/*", "*/"]], strings: '"', keywords: "resource data variable output locals module provider terraform for in if else dynamic content backend required_providers lifecycle", literals: "true false null", types: "string number bool list map set object tuple any", calls: true },
2564
+ dockerfile: { line: ["#"], strings: `'"`, keywords: "FROM RUN CMD LABEL MAINTAINER EXPOSE ENV ADD COPY ENTRYPOINT VOLUME USER WORKDIR ARG ONBUILD STOPSIGNAL HEALTHCHECK SHELL AS", variables: true }
2565
+ };
2566
+ var ALIASES = {
2567
+ js: "javascript",
2568
+ javascript: "javascript",
2569
+ mjs: "javascript",
2570
+ cjs: "javascript",
2571
+ jsx: "javascript",
2572
+ node: "javascript",
2573
+ nodejs: "javascript",
2574
+ ts: "typescript",
2575
+ typescript: "typescript",
2576
+ tsx: "typescript",
2577
+ mts: "typescript",
2578
+ cts: "typescript",
2579
+ python: "python",
2580
+ py: "python",
2581
+ python3: "python",
2582
+ py3: "python",
2583
+ rust: "rust",
2584
+ rs: "rust",
2585
+ go: "go",
2586
+ golang: "go",
2587
+ bash: "bash",
2588
+ sh: "bash",
2589
+ shell: "bash",
2590
+ zsh: "bash",
2591
+ console: "bash",
2592
+ shellscript: "bash",
2593
+ fish: "bash",
2594
+ json: "json",
2595
+ jsonc: "json",
2596
+ json5: "json",
2597
+ yaml: "yaml",
2598
+ yml: "yaml",
2599
+ toml: "toml",
2600
+ ini: "ini",
2601
+ conf: "ini",
2602
+ cfg: "ini",
2603
+ properties: "ini",
2604
+ env: "ini",
2605
+ markup: "markup",
2606
+ html: "markup",
2607
+ xml: "markup",
2608
+ svg: "markup",
2609
+ xhtml: "markup",
2610
+ vue: "markup",
2611
+ plist: "markup",
2612
+ css: "css",
2613
+ scss: "css",
2614
+ less: "css",
2615
+ sass: "css",
2616
+ sql: "sql",
2617
+ postgres: "sql",
2618
+ postgresql: "sql",
2619
+ mysql: "sql",
2620
+ sqlite: "sql",
2621
+ pgsql: "sql",
2622
+ java: "java",
2623
+ csharp: "csharp",
2624
+ cs: "csharp",
2625
+ "c#": "csharp",
2626
+ kotlin: "kotlin",
2627
+ kt: "kotlin",
2628
+ swift: "swift",
2629
+ ruby: "ruby",
2630
+ rb: "ruby",
2631
+ php: "php",
2632
+ c: "c",
2633
+ h: "c",
2634
+ cpp: "c",
2635
+ "c++": "c",
2636
+ cc: "c",
2637
+ cxx: "c",
2638
+ hpp: "c",
2639
+ hh: "c",
2640
+ objc: "c",
2641
+ hcl: "hcl",
2642
+ terraform: "hcl",
2643
+ tf: "hcl",
2644
+ tfvars: "hcl",
2645
+ dockerfile: "dockerfile",
2646
+ docker: "dockerfile"
2647
+ };
2648
+ var CODE_HIGHLIGHT_LANGUAGES = Object.freeze(Object.keys(LANGUAGES));
2649
+ function resolveCodeLanguage(language) {
2650
+ if (typeof language !== "string") return void 0;
2651
+ const key = language.trim().toLowerCase().replace(/^(?:language|lang)[-:]/, "").replace(/^\./, "");
2652
+ return Object.hasOwn(ALIASES, key) ? ALIASES[key] : void 0;
2653
+ }
2654
+ var IDENT = /[\p{L}_$][\p{L}\p{N}_$]*/uy;
2655
+ var NUMBER = /(?:0[xX][\da-fA-F_]+|0[bB][01_]+|0[oO][0-7_]+|\d[\d_]*(?:\.\d[\d_]*)?(?:[eE][+-]?\d[\d_]*)?)[a-zA-Z]{0,4}/y;
2656
+ var isIdentChar = (character) => character !== void 0 && /[\p{L}\p{N}_$]/u.test(character);
2657
+ function endOfLine(source, from) {
2658
+ const index = source.slice(from).search(/\r\n|\r|\n/);
2659
+ return index < 0 ? source.length : from + index;
2660
+ }
2661
+ function pushToken(tokens, start, end, kind2) {
2662
+ if (end <= start) return;
2663
+ const last = tokens[tokens.length - 1];
2664
+ if (last && last.kind === kind2 && last.end === start && kind2 !== "function" && kind2 !== "property") last.end = end;
2665
+ else tokens.push({ start, end, kind: kind2 });
2666
+ }
2667
+ function scanQuoted(source, from, quote, escapes, multiline) {
2668
+ let index = from + 1;
2669
+ while (index < source.length) {
2670
+ const character = source[index];
2671
+ if (escapes && character === "\\") {
2672
+ index += 2;
2673
+ continue;
2674
+ }
2675
+ if (character === quote) return index + 1;
2676
+ if (!multiline && (character === "\n" || character === "\r")) return index;
2677
+ index++;
2678
+ }
2679
+ return source.length;
2680
+ }
2681
+ function scanGeneric(source, def) {
2682
+ const tokens = [];
2683
+ const keywords = set(def.keywords), literals = set(def.literals), types = set(def.types);
2684
+ const fold = (word) => def.ci ? word.toLowerCase() : word;
2685
+ if (def.ci) for (const list of [keywords, literals, types]) for (const word of [...list]) {
2686
+ list.delete(word);
2687
+ list.add(word.toLowerCase());
2688
+ }
2689
+ const strings = def.strings ?? "", lineComments = def.line ?? [], blocks = def.block ?? [], triples = def.triple ?? [];
2690
+ let index = 0, pendingDef;
2691
+ const atLineStart = (position) => {
2692
+ let at3 = position - 1;
2693
+ while (at3 >= 0 && (source[at3] === " " || source[at3] === " ")) at3--;
2694
+ return at3 < 0 || source[at3] === "\n" || source[at3] === "\r";
2695
+ };
2696
+ while (index < source.length) {
2697
+ const character = source[index];
2698
+ if (/\s/.test(character)) {
2699
+ index++;
2700
+ continue;
2701
+ }
2702
+ const lineComment = lineComments.find((opener) => source.startsWith(opener, index));
2703
+ if (lineComment && !(lineComment === "#" && def.directives) && !(lineComment === "#" && def.variables && source[index - 1] === "$") && !(def.variables && lineComment === "#" && index > 0 && !/[\s;&|(]/.test(source[index - 1]))) {
2704
+ const end = endOfLine(source, index);
2705
+ pushToken(tokens, index, end, "comment");
2706
+ index = end;
2707
+ continue;
2708
+ }
2709
+ const block = blocks.find(([opener]) => source.startsWith(opener, index));
2710
+ if (block) {
2711
+ const close = source.indexOf(block[1], index + block[0].length);
2712
+ const end = close < 0 ? source.length : close + block[1].length;
2713
+ pushToken(tokens, index, end, "comment");
2714
+ index = end;
2715
+ continue;
2716
+ }
2717
+ if (def.directives && character === "#" && atLineStart(index)) {
2718
+ const match = /#[ \t]*\w+/y;
2719
+ match.lastIndex = index;
2720
+ const found = match.exec(source);
2721
+ if (found) {
2722
+ pushToken(tokens, index, index + found[0].length, "keyword");
2723
+ index += found[0].length;
2724
+ if (/include/.test(found[0])) {
2725
+ const header = /[ \t]*(<[^>\n]*>)/y;
2726
+ header.lastIndex = index;
2727
+ const matched = header.exec(source);
2728
+ if (matched) {
2729
+ const start = index + matched[0].length - matched[1].length;
2730
+ pushToken(tokens, start, start + matched[1].length, "string");
2731
+ index += matched[0].length;
2732
+ }
2733
+ }
2734
+ continue;
2735
+ }
2736
+ }
2737
+ const triple = triples.find((opener) => source.startsWith(opener, index));
2738
+ if (triple) {
2739
+ const close = source.indexOf(triple, index + 3);
2740
+ const end = close < 0 ? source.length : close + 3;
2741
+ pushToken(tokens, index, end, "string");
2742
+ index = end;
2743
+ pendingDef = void 0;
2744
+ continue;
2745
+ }
2746
+ if (def.rawStrings && character === def.rawStrings && /^r#*"/.test(source.slice(index, index + 8)) && !isIdentChar(source[index - 1])) {
2747
+ const hashes = /^r(#*)"/.exec(source.slice(index, index + 8))[1];
2748
+ const close = source.indexOf(`"${hashes}`, index + 2 + hashes.length);
2749
+ const end = close < 0 ? source.length : close + 1 + hashes.length;
2750
+ pushToken(tokens, index, end, "string");
2751
+ index = end;
2752
+ continue;
2753
+ }
2754
+ if (strings.includes(character)) {
2755
+ if (def === LANGUAGES.rust && character === "'" && !/^'(?:\\.[^']*|[^\\'])'/.test(source.slice(index, index + 12))) {
2756
+ const match = /'[\p{L}_][\p{L}\p{N}_]*/uy;
2757
+ match.lastIndex = index;
2758
+ const found = match.exec(source);
2759
+ const end2 = index + (found ? found[0].length : 1);
2760
+ if (found) pushToken(tokens, index, end2, "type");
2761
+ index = end2;
2762
+ continue;
2763
+ }
2764
+ const escapes = !(def.noEscapes ?? "").includes(character);
2765
+ const multiline = character === "`";
2766
+ const end = scanQuoted(source, index, character, escapes, multiline);
2767
+ let kind2 = "string";
2768
+ if (def.quotedKeys) {
2769
+ const after = /^[ \t]*:/.exec(source.slice(end, end + 40));
2770
+ if (after) kind2 = "property";
2771
+ }
2772
+ pushToken(tokens, index, end, kind2);
2773
+ index = end;
2774
+ pendingDef = void 0;
2775
+ continue;
2776
+ }
2777
+ if (def.variables && character === "$") {
2778
+ const match = /\$(?:\{[^}\n]*\}|[A-Za-z_]\w*|[0-9@#?!$*-])/y;
2779
+ match.lastIndex = index;
2780
+ const found = match.exec(source);
2781
+ if (found) {
2782
+ pushToken(tokens, index, index + found[0].length, "property");
2783
+ index += found[0].length;
2784
+ continue;
2785
+ }
2786
+ }
2787
+ if (def.decorators && character === "@" && /[\p{L}_]/u.test(source[index + 1] ?? "")) {
2788
+ const match = /@[\p{L}_][\p{L}\p{N}_$.]*/uy;
2789
+ match.lastIndex = index;
2790
+ const found = match.exec(source);
2791
+ pushToken(tokens, index, index + found[0].length, "function");
2792
+ index += found[0].length;
2793
+ continue;
2794
+ }
2795
+ if (/\d/.test(character) && !isIdentChar(source[index - 1])) {
2796
+ NUMBER.lastIndex = index;
2797
+ const found = NUMBER.exec(source);
2798
+ if (found) {
2799
+ pushToken(tokens, index, index + found[0].length, "number");
2800
+ index += found[0].length;
2801
+ pendingDef = void 0;
2802
+ continue;
2803
+ }
2804
+ }
2805
+ if (def === LANGUAGES.python && /[rRbBfFuU]/.test(character) && /^[rRbBfFuU]{1,2}['"]/.test(source.slice(index, index + 3)) && !isIdentChar(source[index - 1])) {
2806
+ const prefix = /^[rRbBfFuU]{1,2}/.exec(source.slice(index, index + 3))[0].length;
2807
+ const quote = source[index + prefix];
2808
+ const triple2 = source.startsWith(quote.repeat(3), index + prefix);
2809
+ let end;
2810
+ if (triple2) {
2811
+ const close = source.indexOf(quote.repeat(3), index + prefix + 3);
2812
+ end = close < 0 ? source.length : close + 3;
2813
+ } else end = scanQuoted(source, index + prefix, quote, !/[rR]/.test(source.slice(index, index + prefix)), false);
2814
+ pushToken(tokens, index, end, "string");
2815
+ index = end;
2816
+ pendingDef = void 0;
2817
+ continue;
2818
+ }
2819
+ IDENT.lastIndex = index;
2820
+ const identifier = IDENT.exec(source);
2821
+ if (identifier) {
2822
+ const word = identifier[0], end = index + word.length, folded = fold(word);
2823
+ let kind2;
2824
+ if (pendingDef && !keywords.has(folded)) kind2 = pendingDef;
2825
+ else if (keywords.has(folded)) {
2826
+ kind2 = "keyword";
2827
+ pendingDef = def.defs && Object.hasOwn(def.defs, folded) ? def.defs[folded] : void 0;
2828
+ pushToken(tokens, index, end, kind2);
2829
+ index = end;
2830
+ continue;
2831
+ } else if (literals.has(word) || literals.has(folded)) kind2 = "number";
2832
+ else if (types.has(folded)) kind2 = "type";
2833
+ else if (def.calls && source[end] === "(") kind2 = "function";
2834
+ else if (def.macros && source[end] === "!" && /[([{]/.test(source[end + 1] ?? "")) kind2 = "function";
2835
+ else if (def.capsTypes && /^[A-Z]/.test(word) && /[a-z]/.test(word)) kind2 = "type";
2836
+ pendingDef = void 0;
2837
+ if (kind2) pushToken(tokens, index, end, kind2);
2838
+ index = end;
2839
+ continue;
2840
+ }
2841
+ pendingDef = void 0;
2842
+ index++;
2843
+ }
2844
+ return tokens;
2845
+ }
2846
+ var YAML_LITERALS = /* @__PURE__ */ new Set(["true", "false", "null", "yes", "no", "on", "off", "~", "True", "False", "Null", "TRUE", "FALSE", "NULL"]);
2847
+ function scanYamlValue(source, start, end, tokens, comments) {
2848
+ let index = start;
2849
+ while (index < end) {
2850
+ const character = source[index];
2851
+ if (character === "#" && (index === start || /\s/.test(source[index - 1])) && comments.includes("#")) {
2852
+ pushToken(tokens, index, end, "comment");
2853
+ return;
2854
+ }
2855
+ if (character === ";" && comments.includes(";") && (index === start || /\s/.test(source[index - 1]))) {
2856
+ pushToken(tokens, index, end, "comment");
2857
+ return;
2858
+ }
2859
+ if (character === '"' || character === "'") {
2860
+ const close = scanQuoted(source, index, character, character === '"', false);
2861
+ pushToken(tokens, index, Math.min(close, end), "string");
2862
+ index = Math.min(close, end);
2863
+ continue;
2864
+ }
2865
+ if ((character === "&" || character === "*") && /[\w-]/.test(source[index + 1] ?? "")) {
2866
+ const match = /[&*][\w-]+/y;
2867
+ match.lastIndex = index;
2868
+ const found2 = match.exec(source);
2869
+ pushToken(tokens, index, index + found2[0].length, "type");
2870
+ index += found2[0].length;
2871
+ continue;
2872
+ }
2873
+ if (!isIdentChar(source[index - 1]) && /[\d-]/.test(character)) {
2874
+ const match = /-?\d[\d_]*(?:\.\d+)?(?:[eE][+-]?\d+)?(?=[\s,\]}]|$)/y;
2875
+ match.lastIndex = index;
2876
+ const found2 = match.exec(source);
2877
+ if (found2 && index + found2[0].length <= end) {
2878
+ pushToken(tokens, index, index + found2[0].length, "number");
2879
+ index += found2[0].length;
2880
+ continue;
2881
+ }
2882
+ }
2883
+ const word = /[\w.~-]+/y;
2884
+ word.lastIndex = index;
2885
+ const found = word.exec(source);
2886
+ if (found) {
2887
+ if (YAML_LITERALS.has(found[0]) && !/[\w.-]/.test(source[index + found[0].length] ?? "")) pushToken(tokens, index, index + found[0].length, "number");
2888
+ index += found[0].length;
2889
+ continue;
2890
+ }
2891
+ index++;
2892
+ }
2893
+ }
2894
+ function lineRanges(source) {
2895
+ const ranges = [];
2896
+ let cursor = 0;
2897
+ const pattern = /\r\n|\r|\n/g;
2898
+ for (let match = pattern.exec(source); match; match = pattern.exec(source)) {
2899
+ ranges.push({ start: cursor, end: match.index });
2900
+ cursor = match.index + match[0].length;
2901
+ }
2902
+ ranges.push({ start: cursor, end: source.length });
2903
+ return ranges;
2904
+ }
2905
+ function yamlKey(source, from, to) {
2906
+ const first = source[from];
2907
+ if (first === void 0 || from >= to) return void 0;
2908
+ let index = from;
2909
+ if (first === '"' || first === "'") {
2910
+ index = Math.min(scanQuoted(source, from, first, first === '"', false), to);
2911
+ let at3 = index;
2912
+ while (at3 < to && (source[at3] === " " || source[at3] === " ")) at3++;
2913
+ return source[index - 1] === first && source[at3] === ":" && (at3 + 1 >= to || /\s/.test(source[at3 + 1])) ? { nameEnd: index, colon: at3 } : void 0;
2914
+ }
2915
+ if (/[\s#:{}[\],&*!|>%@`]/.test(first) || first === "-" && /[\s#:]/.test(source[from + 1] ?? " ")) return void 0;
2916
+ for (; index < to; index++) {
2917
+ const character = source[index];
2918
+ if (character === "#" && /\s/.test(source[index - 1])) return void 0;
2919
+ if (character === ":" && (index + 1 >= to || /\s/.test(source[index + 1]))) {
2920
+ let nameEnd = index;
2921
+ while (nameEnd > from && /\s/.test(source[nameEnd - 1])) nameEnd--;
2922
+ return nameEnd > from ? { nameEnd, colon: index } : void 0;
2923
+ }
2924
+ }
2925
+ return void 0;
2926
+ }
2927
+ function scanYaml(source) {
2928
+ const tokens = [];
2929
+ let blockIndent = -1;
2930
+ for (const { start, end } of lineRanges(source)) {
2931
+ const text2 = source.slice(start, end), indent = /^ */.exec(text2)[0].length;
2932
+ if (blockIndent >= 0) {
2933
+ if (text2.trim() === "" || indent > blockIndent) {
2934
+ if (text2.trim() !== "") pushToken(tokens, start + indent, end, "string");
2935
+ continue;
2936
+ }
2937
+ blockIndent = -1;
2938
+ }
2939
+ if (/^\s*#/.test(text2)) {
2940
+ pushToken(tokens, start + indent, end, "comment");
2941
+ continue;
2942
+ }
2943
+ if (/^(?:---|\.\.\.)(?:\s|$)/.test(text2)) {
2944
+ pushToken(tokens, start, start + 3, "keyword");
2945
+ scanYamlValue(source, start + 3, end, tokens, "#");
2946
+ continue;
2947
+ }
2948
+ let cursor = start + indent;
2949
+ const dash = /^(?:-\s+)+/.exec(text2.slice(indent));
2950
+ if (dash) cursor += dash[0].length;
2951
+ let valueStart = cursor;
2952
+ const key = yamlKey(source, cursor, end);
2953
+ if (key) {
2954
+ pushToken(tokens, cursor, key.nameEnd, "property");
2955
+ valueStart = key.colon + 1;
2956
+ }
2957
+ scanYamlValue(source, valueStart, end, tokens, "#");
2958
+ if (/(?:^|\s)[|>][+-]?\d?\s*(?:#.*)?$/.test(text2.slice(valueStart - start))) blockIndent = indent;
2959
+ }
2960
+ return tokens;
2961
+ }
2962
+ function scanIni(source, def) {
2963
+ const tokens = [], comments = (def.line ?? []).join("");
2964
+ for (const { start, end } of lineRanges(source)) {
2965
+ const text2 = source.slice(start, end), indent = /^\s*/.exec(text2)[0].length, first = text2[indent];
2966
+ if (first === void 0) continue;
2967
+ if (comments.includes(first)) {
2968
+ pushToken(tokens, start + indent, end, "comment");
2969
+ continue;
2970
+ }
2971
+ if (first === "[") {
2972
+ const close = text2.indexOf("]", indent);
2973
+ const stop = close < 0 ? end : start + close + 1;
2974
+ pushToken(tokens, start + indent, stop, "type");
2975
+ scanYamlValue(source, stop, end, tokens, comments);
2976
+ continue;
2977
+ }
2978
+ const key = /^("[^"\n]*"|'[^'\n]*'|[^\s=:#;"']+(?:\s+[^\s=:#;"']+)*)\s*[=:]/.exec(text2.slice(indent));
2979
+ let valueStart = start + indent;
2980
+ if (key) {
2981
+ pushToken(tokens, start + indent, start + indent + key[1].length, "property");
2982
+ valueStart = start + indent + key[0].length;
2983
+ }
2984
+ scanYamlValue(source, valueStart, end, tokens, comments);
2985
+ }
2986
+ return tokens;
2987
+ }
2988
+ function scanMarkup(source) {
2989
+ const tokens = [];
2990
+ let index = 0;
2991
+ while (index < source.length) {
2992
+ const open = source.indexOf("<", index);
2993
+ if (open < 0) break;
2994
+ if (source.startsWith("<!--", open)) {
2995
+ const close = source.indexOf("-->", open + 4);
2996
+ const end = close < 0 ? source.length : close + 3;
2997
+ pushToken(tokens, open, end, "comment");
2998
+ index = end;
2999
+ continue;
3000
+ }
3001
+ if (source.startsWith("<![CDATA[", open)) {
3002
+ const close = source.indexOf("]]>", open);
3003
+ const end = close < 0 ? source.length : close + 3;
3004
+ pushToken(tokens, open, end, "string");
3005
+ index = end;
3006
+ continue;
3007
+ }
3008
+ const name = /<([/?!]?)([A-Za-z][\w:.-]*|DOCTYPE)?/y;
3009
+ name.lastIndex = open;
3010
+ const found = name.exec(source);
3011
+ if (!found || !found[2]) {
3012
+ index = open + 1;
3013
+ continue;
3014
+ }
3015
+ pushToken(tokens, open + 1, open + found[0].length, "keyword");
3016
+ index = open + found[0].length;
3017
+ while (index < source.length && source[index] !== ">") {
3018
+ const character = source[index];
3019
+ if (character === '"' || character === "'") {
3020
+ const close = source.indexOf(character, index + 1);
3021
+ const end = close < 0 ? source.length : close + 1;
3022
+ pushToken(tokens, index, end, "string");
3023
+ index = end;
3024
+ continue;
3025
+ }
3026
+ const attribute = /[A-Za-z_:@#][\w:.@#-]*/y;
3027
+ attribute.lastIndex = index;
3028
+ const matched = attribute.exec(source);
3029
+ if (matched) {
3030
+ pushToken(tokens, index, index + matched[0].length, "property");
3031
+ index += matched[0].length;
3032
+ continue;
3033
+ }
3034
+ index++;
3035
+ }
3036
+ if (source[index] === ">") index++;
3037
+ }
3038
+ return tokens;
3039
+ }
3040
+ function scanCss(source) {
3041
+ const tokens = [];
3042
+ let index = 0, depth = 0;
3043
+ while (index < source.length) {
3044
+ const character = source[index];
3045
+ if (/\s/.test(character)) {
3046
+ index++;
3047
+ continue;
3048
+ }
3049
+ if (source.startsWith("/*", index)) {
3050
+ const close = source.indexOf("*/", index + 2);
3051
+ const end = close < 0 ? source.length : close + 2;
3052
+ pushToken(tokens, index, end, "comment");
3053
+ index = end;
3054
+ continue;
3055
+ }
3056
+ if (character === '"' || character === "'") {
3057
+ const end = scanQuoted(source, index, character, true, false);
3058
+ pushToken(tokens, index, end, "string");
3059
+ index = end;
3060
+ continue;
3061
+ }
3062
+ if (character === "{") {
3063
+ depth++;
3064
+ index++;
3065
+ continue;
3066
+ }
3067
+ if (character === "}") {
3068
+ depth = Math.max(0, depth - 1);
3069
+ index++;
3070
+ continue;
3071
+ }
3072
+ if (character === "@") {
3073
+ const match = /@[\w-]+/y;
3074
+ match.lastIndex = index;
3075
+ const found2 = match.exec(source);
3076
+ if (found2) {
3077
+ pushToken(tokens, index, index + found2[0].length, "keyword");
3078
+ index += found2[0].length;
3079
+ continue;
3080
+ }
3081
+ }
3082
+ if (character === "!") {
3083
+ const match = /!\s*important/y;
3084
+ match.lastIndex = index;
3085
+ const found2 = match.exec(source);
3086
+ if (found2) {
3087
+ pushToken(tokens, index, index + found2[0].length, "keyword");
3088
+ index += found2[0].length;
3089
+ continue;
3090
+ }
3091
+ }
3092
+ if (character === "#" && depth > 0) {
3093
+ const match = /#[\da-fA-F]{3,8}\b/y;
3094
+ match.lastIndex = index;
3095
+ const found2 = match.exec(source);
3096
+ if (found2) {
3097
+ pushToken(tokens, index, index + found2[0].length, "number");
3098
+ index += found2[0].length;
3099
+ continue;
3100
+ }
3101
+ }
3102
+ if (depth > 0 && (/\d/.test(character) || (character === "-" || character === "." || character === "+") && /\d/.test(source[index + 1] ?? ""))) {
3103
+ const match = /[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?(?:%|[a-zA-Z]+)?/y;
3104
+ match.lastIndex = index;
3105
+ const found2 = match.exec(source);
3106
+ if (found2 && !isIdentChar(source[index - 1])) {
3107
+ pushToken(tokens, index, index + found2[0].length, "number");
3108
+ index += found2[0].length;
3109
+ continue;
3110
+ }
3111
+ }
3112
+ const word = /-?[\p{L}_][\p{L}\p{N}_-]*/uy;
3113
+ word.lastIndex = index;
3114
+ const found = word.exec(source);
3115
+ if (found) {
3116
+ const end = index + found[0].length;
3117
+ let back = index - 1;
3118
+ while (back >= 0 && /\s/.test(source[back])) back--;
3119
+ const before = back >= 0 ? source[back] : "";
3120
+ if (depth > 0 && /^\s*:(?!:)/.test(source.slice(end, end + 8)) && (before === "{" || before === ";" || before === "")) pushToken(tokens, index, end, "property");
3121
+ else if (source[end] === "(") pushToken(tokens, index, end, "function");
3122
+ index = end;
3123
+ continue;
3124
+ }
3125
+ if (depth === 0 && (character === "." || character === "#")) {
3126
+ const match = /[.#][\p{L}_-][\p{L}\p{N}_-]*/uy;
3127
+ match.lastIndex = index;
3128
+ const matched = match.exec(source);
3129
+ if (matched) {
3130
+ pushToken(tokens, index, index + matched[0].length, "type");
3131
+ index += matched[0].length;
3132
+ continue;
3133
+ }
3134
+ }
3135
+ index++;
3136
+ }
3137
+ return tokens;
3138
+ }
3139
+ function tokenizeCode(source, language) {
3140
+ const id = resolveCodeLanguage(language);
3141
+ if (id === void 0 || typeof source !== "string" || source.length === 0 || source.length > CODE_HIGHLIGHT_MAX_LENGTH) return [];
3142
+ const def = LANGUAGES[id];
3143
+ let tokens;
3144
+ switch (def.kind) {
3145
+ case "yaml":
3146
+ tokens = scanYaml(source);
3147
+ break;
3148
+ case "ini":
3149
+ tokens = scanIni(source, def);
3150
+ break;
3151
+ case "markup":
3152
+ tokens = scanMarkup(source);
3153
+ break;
3154
+ case "css":
3155
+ tokens = scanCss(source);
3156
+ break;
3157
+ default:
3158
+ tokens = scanGeneric(source, def);
3159
+ }
3160
+ return tokens.filter((token) => token.end > token.start).sort((a, b) => a.start - b.start);
3161
+ }
3162
+ function codeLineRuns(tokens, start, end, source) {
3163
+ const runs = [];
3164
+ const push = (from, to, kind2) => {
3165
+ if (kind2 === void 0 || source === void 0 || !source.slice(from, to).includes(" ")) {
3166
+ runs.push(kind2 === void 0 ? { start: from, end: to } : { start: from, end: to, kind: kind2 });
3167
+ return;
3168
+ }
3169
+ let at3 = from;
3170
+ for (let index = from; index < to; index++) {
3171
+ if (source[index] !== " ") continue;
3172
+ if (index > at3) runs.push({ start: at3, end: index, kind: kind2 });
3173
+ runs.push({ start: index, end: index + 1 });
3174
+ at3 = index + 1;
3175
+ }
3176
+ if (at3 < to) runs.push({ start: at3, end: to, kind: kind2 });
3177
+ };
3178
+ let cursor = start;
3179
+ for (const token of tokens) {
3180
+ if (token.end <= start) continue;
3181
+ if (token.start >= end) break;
3182
+ const from = Math.max(token.start, start), to = Math.min(token.end, end);
3183
+ if (from > cursor) push(cursor, from);
3184
+ push(from, to, token.kind);
3185
+ cursor = to;
3186
+ }
3187
+ if (cursor < end) push(cursor, end);
3188
+ return runs;
3189
+ }
3190
+ var distance = (a, b) => Math.hypot(...channels(a).map((value, index) => value - channels(b)[index]));
3191
+ var FALLBACK = { keyword: "#C4B5FD", string: "#86EFAC", number: "#FCD34D", function: "#93C5FD", type: "#67E8F9", property: "#F9A8D4", comment: "#94A3B8" };
3192
+ function codeSyntaxPalette(theme = {}, options = {}) {
3193
+ const background = normalize(options.background) ?? CODE_PANEL_BACKGROUND, plain = normalize(options.foreground) ?? CODE_PANEL_FOREGROUND;
3194
+ const minimum = options.minimumContrast ?? CODE_SYNTAX_MIN_CONTRAST;
3195
+ const palette = { plain: legible(plain, background, minimum) };
3196
+ const taken = [palette.plain];
3197
+ const slots = [["keyword", theme.primary], ["string", theme.accent], ["number", theme.secondary], ["comment", theme.mutedText], ["function", void 0], ["type", void 0], ["property", void 0]];
3198
+ for (const [kind2, themed] of slots) {
3199
+ const candidates = [normalize(themed), FALLBACK[kind2]].filter((value) => value !== void 0).map((value) => legible(value, background, minimum));
3200
+ let [h, s, l] = toHsl(FALLBACK[kind2]);
3201
+ let pick = candidates.find((candidate) => taken.every((other) => distance(candidate, other) >= 48));
3202
+ for (let turn = 0; pick === void 0 && turn < 9; turn++) {
3203
+ h += 40;
3204
+ const candidate = legible(fromHsl(h, s, l), background, minimum);
3205
+ if (taken.every((other) => distance(candidate, other) >= 48)) pick = candidate;
3206
+ }
3207
+ palette[kind2] = pick ?? candidates[candidates.length - 1];
3208
+ taken.push(palette[kind2]);
3209
+ }
3210
+ return palette;
3211
+ }
3212
+ function codeSyntaxPaletteForScheme(scheme, options = {}) {
3213
+ const record6 = scheme && typeof scheme === "object" ? scheme : {};
3214
+ const pick = (role, slot, fallback) => normalize(record6[role]) ?? normalize(record6[slot]) ?? fallback;
3215
+ return codeSyntaxPalette({ primary: pick("primary", "accent1", "#2563EB"), secondary: pick("secondary", "accent2", "#0F766E"), accent: pick("accent", "accent3", "#F59E0B") }, options);
3216
+ }
3217
+
3218
+ // src/metric-trend.ts
3219
+ var METRIC_DEFAULT_SENTIMENT = Object.freeze({ up: "positive", down: "negative", flat: "neutral" });
3220
+ function metricEffectiveSentiment(trend, sentiment) {
3221
+ return sentiment ?? METRIC_DEFAULT_SENTIMENT[trend];
3222
+ }
3223
+ var METRIC_TREND_SHAPES = Object.freeze({ up: "upArrow", down: "downArrow", flat: "rightArrow" });
3224
+ var METRIC_TREND_MIN_CONTRAST = 4.5;
3225
+ var SEMANTIC = {
3226
+ positive: { light: "#15803D", dark: "#4ADE80" },
3227
+ negative: { light: "#B91C1C", dark: "#F87171" }
3228
+ };
3229
+ function metricTrendColor(trend, options) {
3230
+ const background = normalize(options.background) ?? "#FFFFFF";
3231
+ const sentiment = metricEffectiveSentiment(trend, options.sentiment);
3232
+ if (sentiment === "neutral") return legible(normalize(options.neutral) ?? (luminance2(background) < 0.5 ? "#CBD5E1" : "#475569"), background, METRIC_TREND_MIN_CONTRAST);
3233
+ const pair = SEMANTIC[sentiment];
3234
+ return legible(luminance2(background) < 0.5 ? pair.dark : pair.light, background, METRIC_TREND_MIN_CONTRAST);
3235
+ }
3236
+ function metricTrendPoints(shape, box) {
3237
+ const { x: l, y: t, width: w, height: h } = box, r = l + w, b = t + h, hc = l + w / 2, vc = t + h / 2, ss = Math.min(w, h);
3238
+ if (shape === "rightArrow") {
3239
+ const x12 = r - ss * 0.5, y1 = vc - h * 0.25, y22 = vc + h * 0.25;
3240
+ return [[l, y1], [x12, y1], [x12, t], [r, vc], [x12, b], [x12, y22], [l, y22]];
3241
+ }
3242
+ const dy = ss * 0.5, x1 = hc - w * 0.25, x2 = hc + w * 0.25;
3243
+ if (shape === "upArrow") {
3244
+ const y22 = t + dy;
3245
+ return [[l, y22], [hc, t], [r, y22], [x2, y22], [x2, b], [x1, b], [x1, y22]];
3246
+ }
3247
+ const y2 = b - dy;
3248
+ return [[l, y2], [x1, y2], [x1, t], [x2, t], [x2, y2], [r, y2], [hc, b]];
3249
+ }
3250
+ function metricTrendMark(layout, options) {
3251
+ const part = layout.parts.find((candidate) => candidate.role === "trend");
3252
+ if (!part || !part.visible || !part.fit || part.fit.sourceLines.length === 0) return void 0;
3253
+ const trend = part.text.trim();
3254
+ if (!Object.hasOwn(METRIC_TREND_SHAPES, trend)) return void 0;
3255
+ const line = part.fit.sourceLines[0], origin = part.linePositions[0];
3256
+ if (!origin || line.width <= 0) return void 0;
3257
+ const size = part.fit.fontSize * 0.72, gap = part.fit.fontSize * 0.3, left = part.box.x, right = part.box.x + part.box.width;
3258
+ const after = origin.x + line.width + gap, before = origin.x - gap - size;
3259
+ const fitsAfter = after + size <= right + 0.01, fitsBefore = before >= left - 0.01;
3260
+ const x = layout.alignment === "left" ? fitsAfter ? after : fitsBefore ? before : void 0 : fitsBefore ? before : fitsAfter ? after : void 0;
3261
+ if (x === void 0) return void 0;
3262
+ const shape = METRIC_TREND_SHAPES[trend], box = { x, y: origin.baseline - size, width: size, height: size };
3263
+ const sentiment = metricEffectiveSentiment(trend, options.sentiment ?? layout.sentiment);
3264
+ return { trend, sentiment, shape, box, points: metricTrendPoints(shape, box), color: metricTrendColor(trend, { ...options, sentiment }), ariaLabel: `Trend: ${trend}`, path: part.path };
3265
+ }
3266
+
3267
+ // src/timeline-status.ts
3268
+ var TIMELINE_STATUSES = Object.freeze(["done", "current", "planned"]);
3269
+ var TIMELINE_TEXT_MIN_CONTRAST = 4.5;
3270
+ var TIMELINE_OUTLINE_MIN_CONTRAST = 3;
3271
+ function timelineMarkerShapes(marker, colors) {
3272
+ const background = normalize(colors.background) ?? "#FFFFFF";
3273
+ const primary = normalize(colors.primary), outline = primary ? legible(primary, background, TIMELINE_OUTLINE_MIN_CONTRAST) : colors.primary;
3274
+ const shapes = [];
3275
+ const width = marker.strokeWidth ?? 0;
3276
+ if (marker.status === "current" && marker.ring) {
3277
+ shapes.push({ role: "ring", shape: "ellipse", cx: marker.x, cy: marker.y, radius: marker.ring.radius, fill: colors.background, stroke: { color: outline, width } });
3278
+ }
3279
+ if (marker.status === "planned") {
3280
+ shapes.push({ role: "marker", shape: "ellipse", cx: marker.x, cy: marker.y, radius: marker.radius, fill: colors.background, stroke: { color: outline, width } });
3281
+ } else {
3282
+ shapes.push({ role: "marker", shape: "ellipse", cx: marker.x, cy: marker.y, radius: marker.radius, fill: colors.primary });
3283
+ }
3284
+ return shapes;
3285
+ }
3286
+ function timelineTextColor(part, colors) {
3287
+ if (part.status !== "planned") return colors.text;
3288
+ const background = normalize(colors.background) ?? "#FFFFFF", muted = normalize(colors.mutedText);
3289
+ return muted ? legible(muted, background, TIMELINE_TEXT_MIN_CONTRAST) : colors.mutedText;
3290
+ }
3291
+
3292
+ // src/code-highlight.ts
3293
+ function codeLineCount(source) {
3294
+ let count = 1;
3295
+ for (let index = 0; index < source.length; index++) {
3296
+ const char = source[index];
3297
+ if (char === "\r" && source[index + 1] === "\n") index++;
3298
+ if (char === "\r" || char === "\n") count++;
3299
+ }
3300
+ return count > 1 && /(?:\r\n|\r|\n)$/.test(source) ? count - 1 : count;
3301
+ }
3302
+ var isLine = (value) => typeof value === "number" && Number.isInteger(value) && value >= 1;
3303
+ function codeHighlightLines(highlight, source) {
3304
+ const lineCount = codeLineCount(source), marked = /* @__PURE__ */ new Set(), issues = [];
3305
+ if (!Array.isArray(highlight)) return { lineCount, lines: [], issues };
3306
+ highlight.forEach((entry, index) => {
3307
+ const range = Array.isArray(entry) ? entry : [entry, entry];
3308
+ if (range.length !== 2 || !isLine(range[0]) || !isLine(range[1])) {
3309
+ issues.push({ code: "code-highlight-invalid", index, message: "A code highlight entry is a line number or a [start, end] pair of line numbers from 1." });
3310
+ return;
3311
+ }
3312
+ const [start, end] = range;
3313
+ if (start > end) {
3314
+ issues.push({ code: "code-highlight-range-reversed", index, message: `The highlight range [${start}, ${end}] ends before it starts, so it marks no line; write [${end}, ${start}].` });
3315
+ return;
3316
+ }
3317
+ if (end > lineCount) issues.push({ code: "code-highlight-out-of-range", index, message: `The highlight ${start === end ? `line ${start}` : `range [${start}, ${end}]`} is past the last line (the code has ${lineCount} ${lineCount === 1 ? "line" : "lines"}); lines beyond it are ignored.` });
3318
+ for (let line = start; line <= Math.min(end, lineCount); line++) marked.add(line);
3319
+ });
3320
+ return { lineCount, lines: [...marked].sort((a, b) => a - b), issues };
3321
+ }
3322
+ function codeHighlightList(lines) {
3323
+ const sorted = [...new Set(lines)].sort((a, b) => a - b), out = [];
3324
+ for (let index = 0; index < sorted.length; ) {
3325
+ let end = index;
3326
+ while (sorted[end + 1] === sorted[end] + 1) end++;
3327
+ out.push(end === index ? sorted[index] : [sorted[index], sorted[end]]);
3328
+ index = end + 1;
3329
+ }
3330
+ return out;
3331
+ }
3332
+ function codeLineNumbers(sourceLines) {
3333
+ let line = 1;
3334
+ return sourceLines.map((entry) => {
3335
+ const number = line;
3336
+ if (entry.boundary === "hard") line++;
3337
+ return number;
3338
+ });
3339
+ }
3340
+ function codeHighlightBands(sourceLines, lines) {
3341
+ if (!lines.length) return [];
3342
+ const marked = new Set(lines), numbers = codeLineNumbers(sourceLines), bands = [];
3343
+ numbers.forEach((number, index) => {
3344
+ if (!marked.has(number)) return;
3345
+ const last = bands.at(-1);
3346
+ if (last && last.last === index - 1) last.last = index;
3347
+ else bands.push({ first: index, last: index });
3348
+ });
3349
+ return bands;
3350
+ }
3351
+ function codeHighlightSlice(highlight, source, start, end) {
3352
+ const { lines } = codeHighlightLines(highlight, source);
3353
+ if (!lines.length) return void 0;
3354
+ const breaks = (text2) => (text2.match(/\r\n|\r|\n/g) ?? []).length;
3355
+ const before = breaks(source.slice(0, start)), count = codeLineCount(source.slice(start, end));
3356
+ const kept = lines.filter((line) => line > before && line <= before + count).map((line) => line - before);
3357
+ return kept.length ? codeHighlightList(kept) : void 0;
3358
+ }
3359
+ var CODE_HIGHLIGHT_DIM = 0.35;
3360
+ var CODE_HIGHLIGHT_BAND_TINT = 0.3;
3361
+ var blend = (from, to, amount) => {
3362
+ const a = channels(from), b = channels(to);
3363
+ return toHex(a.map((value, index) => value + (b[index] - value) * amount));
3364
+ };
3365
+ function codeHighlightColors(scheme, palette = codeSyntaxPaletteForScheme(scheme)) {
3366
+ const record6 = scheme && typeof scheme === "object" ? scheme : {};
3367
+ const primary = normalize(record6.primary) ?? normalize(record6.accent1) ?? "#2563EB";
3368
+ const [hue, saturation] = toHsl(primary);
3369
+ const tint = fromHsl(hue, Math.min(saturation, 0.7), 0.45);
3370
+ const band = blend(CODE_PANEL_BACKGROUND, tint, CODE_HIGHLIGHT_BAND_TINT);
3371
+ const lit = {}, dim = {};
3372
+ for (const key of Object.keys(palette)) {
3373
+ lit[key] = legible(palette[key], band, CODE_SYNTAX_MIN_CONTRAST);
3374
+ dim[key] = legible(blend(palette[key], CODE_PANEL_BACKGROUND, CODE_HIGHLIGHT_DIM), CODE_PANEL_BACKGROUND, CODE_SYNTAX_MIN_CONTRAST);
3375
+ }
3376
+ return { band, lit, dim };
3377
+ }
3378
+
3379
+ // src/watermark.ts
3380
+ var WATERMARK_TEXT_ROTATION = -30;
3381
+ var WATERMARK_TEXT_MAX_WIDTH = 0.7;
3382
+ var WATERMARK_TEXT_MAX_HEIGHT = 0.3;
3383
+ function layoutWatermark(text2, size, options = {}) {
3384
+ const value = typeof text2 === "string" ? text2.replace(/\s*[\r\n]+\s*/g, " ").trim() : "";
3385
+ if (!value) return void 0;
3386
+ const { width, height } = size;
3387
+ if (![width, height].every((n) => Number.isFinite(n) && n > 0)) throw new RangeError("Watermark slide size must be finite and positive.");
3388
+ const fontFamily = options.fontFamily ?? "sans-serif", fontWeight = options.fontWeight ?? 700;
3389
+ const style = resolveTextStyle({ fontFamily, fontWeight, italic: false, path: "design.watermark" }, options.textMeasurement);
3390
+ const measure = textWidthMeasurer(style, options.textMeasurement);
3391
+ const reference = 100, unit = measure(value, reference);
3392
+ const wanted = unit > 0 ? WATERMARK_TEXT_MAX_WIDTH * width * reference / unit : WATERMARK_TEXT_MAX_HEIGHT * Math.min(width, height);
3393
+ const fontSize = Math.max(1, Math.min(wanted, WATERMARK_TEXT_MAX_HEIGHT * Math.min(width, height)));
3394
+ const textWidth = measure(value, fontSize);
3395
+ const boxWidth = textWidth + fontSize * 0.5, boxHeight = fontSize * 1.4;
3396
+ return {
3397
+ text: value,
3398
+ fontFamily: style.fontFamily,
3399
+ fontWeight,
3400
+ style,
3401
+ fontSize,
3402
+ textWidth,
3403
+ box: { x: (width - boxWidth) / 2, y: (height - boxHeight) / 2, width: boxWidth, height: boxHeight },
3404
+ rotation: WATERMARK_TEXT_ROTATION
3405
+ };
3406
+ }
3407
+
3408
+ // src/pattern-fills.ts
3409
+ var PATTERN_PRESETS = Object.freeze([
3410
+ "pct5",
3411
+ "pct10",
3412
+ "pct20",
3413
+ "pct25",
3414
+ "pct30",
3415
+ "pct40",
3416
+ "pct50",
3417
+ "pct60",
3418
+ "pct70",
3419
+ "pct75",
3420
+ "pct80",
3421
+ "pct90",
3422
+ "horz",
3423
+ "vert",
3424
+ "ltHorz",
3425
+ "ltVert",
3426
+ "dkHorz",
3427
+ "dkVert",
3428
+ "narHorz",
3429
+ "narVert",
3430
+ "dashHorz",
3431
+ "dashVert",
3432
+ "cross",
3433
+ "dnDiag",
3434
+ "upDiag",
3435
+ "ltDnDiag",
3436
+ "ltUpDiag",
3437
+ "dkDnDiag",
3438
+ "dkUpDiag",
3439
+ "wdDnDiag",
3440
+ "wdUpDiag",
3441
+ "dashDnDiag",
3442
+ "dashUpDiag",
3443
+ "diagCross",
3444
+ "smCheck",
3445
+ "lgCheck",
3446
+ "smGrid",
3447
+ "lgGrid",
3448
+ "dotGrid",
3449
+ "smConfetti",
3450
+ "lgConfetti",
3451
+ "horzBrick",
3452
+ "diagBrick",
3453
+ "solidDmnd",
3454
+ "openDmnd",
3455
+ "dotDmnd",
3456
+ "plaid",
3457
+ "sphere",
3458
+ "weave",
3459
+ "divot",
3460
+ "shingle",
3461
+ "wave",
3462
+ "trellis",
3463
+ "zigZag"
3464
+ ]);
3465
+ var PATTERN_PRESET_ALIASES = Object.freeze({ diagStripe: "wdUpDiag" });
3466
+ var PATTERN_TILE_SIZE = 8;
3467
+ var MEASURED = {
3468
+ pct5: "#......./......../......../......../....#.../......../......../........",
3469
+ pct10: "#......./......../....#.../......../#......./......../....#.../........",
3470
+ pct20: "#...#.../......../..#...#./......../#...#.../......../..#...#./........",
3471
+ pct25: "#...#.../..#...#./#...#.../..#...#./#...#.../..#...#./#...#.../..#...#.",
3472
+ pct30: "#.#.#.#./.#...#../#.#.#.#./...#...#/#.#.#.#./.#...#../#.#.#.#./...#...#",
3473
+ pct40: "#.#.#.#./.#.#.#.#/#.#.#.#./.#.#...#/#.#.#.#./.#.#.#.#/#.#.#.#./...#.#.#",
3474
+ pct50: "#.#.#.#./.#.#.#.#/#.#.#.#./.#.#.#.#/#.#.#.#./.#.#.#.#/#.#.#.#./.#.#.#.#",
3475
+ pct60: "###.###./.#.#.#.#/#.###.##/.#.#.#.#/###.###./.#.#.#.#/#.###.##/.#.#.#.#",
3476
+ pct70: ".###.###/##.###.#/.###.###/##.###.#/.###.###/##.###.#/.###.###/##.###.#",
3477
+ pct75: ".###.###/########/##.###.#/########/.###.###/########/##.###.#/########",
3478
+ pct80: "###.####/########/#######./########/###.####/########/#######./########",
3479
+ pct90: "########/########/########/####.###/########/########/########/.#######",
3480
+ horz: "########/......../......../......../......../......../......../........",
3481
+ vert: "#......./#......./#......./#......./#......./#......./#......./#.......",
3482
+ ltHorz: "########/......../......../......../########/......../......../........",
3483
+ ltVert: "#...#.../#...#.../#...#.../#...#.../#...#.../#...#.../#...#.../#...#...",
3484
+ dkHorz: "########/########/......../......../########/########/......../........",
3485
+ dkVert: "##..##../##..##../##..##../##..##../##..##../##..##../##..##../##..##..",
3486
+ narHorz: "########/......../########/......../########/......../########/........",
3487
+ narVert: ".#.#.#.#/.#.#.#.#/.#.#.#.#/.#.#.#.#/.#.#.#.#/.#.#.#.#/.#.#.#.#/.#.#.#.#",
3488
+ dashHorz: "####..../......../......../......../....####/......../......../........",
3489
+ dashVert: "#......./#......./#......./#......./....#.../....#.../....#.../....#...",
3490
+ cross: "########/#......./#......./#......./#......./#......./#......./#.......",
3491
+ dnDiag: "#......./.#....../..#...../...#..../....#.../.....#../......#./.......#",
3492
+ upDiag: ".......#/......#./.....#../....#.../...#..../..#...../.#....../#.......",
3493
+ ltDnDiag: "#...#.../.#...#../..#...#./...#...#/#...#.../.#...#../..#...#./...#...#",
3494
+ ltUpDiag: "...#...#/..#...#./.#...#../#...#.../...#...#/..#...#./.#...#../#...#...",
3495
+ dkDnDiag: "##..##../.##..##./..##..##/#..##..#/##..##../.##..##./..##..##/#..##..#",
3496
+ dkUpDiag: "..##..##/.##..##./##..##../#..##..#/..##..##/.##..##./##..##../#..##..#",
3497
+ wdDnDiag: "##.....#/###...../.###..../..###.../...###../....###./.....###/#.....##",
3498
+ wdUpDiag: "#.....##/.....###/....###./...###../..###.../.###..../###...../##.....#",
3499
+ dashDnDiag: "......../......../#...#.../.#...#../..#...#./...#...#/......../........",
3500
+ dashUpDiag: "......../......../...#...#/..#...#./.#...#../#...#.../......../........",
3501
+ diagCross: "#......#/.#....#./..#..#../...##.../...##.../..#..#../.#....#./#......#",
3502
+ smCheck: "#..##..#/.##..##./.##..##./#..##..#/#..##..#/.##..##./.##..##./#..##..#",
3503
+ lgCheck: "####..../####..../####..../####..../....####/....####/....####/....####",
3504
+ smGrid: "########/#...#.../#...#.../#...#.../########/#...#.../#...#.../#...#...",
3505
+ lgGrid: "########/#......./#......./#......./#......./#......./#......./#.......",
3506
+ dotGrid: "#.#.#.#./......../#......./......../#......./......../#......./........",
3507
+ smConfetti: "#......./....#.../.#....../......#./...#..../.......#/..#...../.....#..",
3508
+ lgConfetti: "#.##...#/..##..../......##/...##.##/##.##.../##....../....##../#...##.#",
3509
+ horzBrick: "########/#......./#......./#......./########/....#.../....#.../....#...",
3510
+ diagBrick: ".......#/......#./.....#../....#.../...##.../..#..#../.#....#./#......#",
3511
+ solidDmnd: "...#..../..###.../.#####../#######./.#####../..###.../...#..../........",
3512
+ openDmnd: "#.....#./.#...#../..#.#.../...#..../..#.#.../.#...#../#.....#./.......#",
3513
+ dotDmnd: "#......./......../..#...#./......../....#.../......../..#...#./........",
3514
+ plaid: "#.#.#.#./.#.#.#.#/#.#.#.#./.#.#.#.#/####..../####..../####..../####....",
3515
+ sphere: ".###.###/#...#..#/#...####/#...####/.###.###/#..##.../#####.../#####...",
3516
+ weave: "#...#.../.#.#.#../..#...#./.#...#.#/#...#.../...#.#../..#...#./.#.#...#",
3517
+ divot: "......../...#..../....#.../...#..../......../#......./.......#/#.......",
3518
+ shingle: "......##/#....#../.#..#.../..##..../....##../......#./.......#/.......#",
3519
+ wave: "......../...##.../..#..#.#/##....../......../...##.../..#..#.#/##......",
3520
+ trellis: "########/.##..##./########/#..##..#/########/.##..##./########/#..##..#",
3521
+ zigZag: "#......#/.#....#./..#..#../...##.../#......#/.#....#./..#..#../...##..."
3522
+ };
3523
+ function rows(preset) {
3524
+ const art = MEASURED[preset];
3525
+ if (!art) return void 0;
3526
+ return art.split("/").map((row) => [...row].reduce((bits, cell, index) => cell === "#" ? bits | 128 >> index : bits, 0));
3527
+ }
3528
+ var BITMAPS = /* @__PURE__ */ new Map();
3529
+ for (const preset of PATTERN_PRESETS) {
3530
+ const bitmap = rows(preset);
3531
+ if (bitmap) BITMAPS.set(preset, Object.freeze(bitmap));
3532
+ }
3533
+ function resolvePatternPreset(preset) {
3534
+ if (typeof preset !== "string") return void 0;
3535
+ if (BITMAPS.has(preset)) return preset;
3536
+ return Object.hasOwn(PATTERN_PRESET_ALIASES, preset) ? PATTERN_PRESET_ALIASES[preset] : void 0;
3537
+ }
3538
+ function patternBitmap(preset) {
3539
+ const resolved = resolvePatternPreset(preset);
3540
+ return resolved === void 0 ? void 0 : BITMAPS.get(resolved);
3541
+ }
3542
+ function patternRuns(preset) {
3543
+ const bitmap = patternBitmap(preset);
3544
+ if (!bitmap) return void 0;
3545
+ const runs = [];
3546
+ bitmap.forEach((row, y) => {
3547
+ for (let x = 0; x < 8; x++) {
3548
+ if (!(row & 128 >> x)) continue;
3549
+ const start = x;
3550
+ while (x + 1 < 8 && row & 128 >> x + 1) x++;
3551
+ runs.push({ x: start, y, width: x - start + 1 });
3552
+ }
3553
+ });
3554
+ return runs;
3555
+ }
2666
3556
 
2667
3557
  // src/annotations.ts
2668
3558
  var CITATION_MARKER_SCALE = 2 / 3;
@@ -2676,6 +3566,7 @@ var isRecord3 = (value) => !!value && typeof value === "object" && !Array.isArra
2676
3566
  var round = (value) => Math.round(value * 1e6) / 1e6 || value;
2677
3567
  var regionKey = /^(top|middle|bottom|left|center|right)([+:]|$)/;
2678
3568
  var TEXT_FIELDS = ["text", "items", "bullets"];
3569
+ var HEADING_FIELDS = ["tag", "title", "subtitle"];
2679
3570
  function annotationText(value) {
2680
3571
  if (typeof value === "string") return value;
2681
3572
  if (Array.isArray(value)) return value.map((run) => typeof run === "string" ? run : record4(run).text ?? "").join("");
@@ -2723,8 +3614,10 @@ function walkCitationRuns(slide, basePath, visit) {
2723
3614
  if (field === "text") runs(payload.text, `${path}.text`);
2724
3615
  else list(payload[field], `${path}.${field}`);
2725
3616
  }
3617
+ if (isRecord3(payload.quote)) runs(payload.quote.text, `${path}.quote.text`);
2726
3618
  };
2727
3619
  const value = record4(slide);
3620
+ for (const field of HEADING_FIELDS) runs(value[field], `${basePath}.${field}`);
2728
3621
  const regions = Object.keys(value).filter((key) => regionKey.test(key)).sort();
2729
3622
  if (regions.length) {
2730
3623
  for (const key of regions) host(value[key], `${basePath}.${key}`, 0);
@@ -2846,6 +3739,29 @@ function referencesSlide(presentation, options = {}) {
2846
3739
  return { title, items };
2847
3740
  }
2848
3741
 
3742
+ // src/layout-content.ts
3743
+ var LAYOUT_BODY_KINDS = ["text", "list", "image", "video", "chart", "table", "code", "metric", "quote", "timeline"];
3744
+ var bodyKinds = new Set(LAYOUT_BODY_KINDS);
3745
+ function layoutContent(record6) {
3746
+ const heading = { title: false, subtitle: false, tag: false };
3747
+ const counts = /* @__PURE__ */ new Map();
3748
+ let count = 0;
3749
+ for (const placeholder of Array.isArray(record6?.placeholders) ? record6.placeholders : []) {
3750
+ const type = placeholder?.type;
3751
+ if (type === "title" || type === "subtitle" || type === "tag") heading[type] = true;
3752
+ else if (typeof type === "string" && bodyKinds.has(type)) {
3753
+ counts.set(type, (counts.get(type) ?? 0) + 1);
3754
+ count += 1;
3755
+ }
3756
+ }
3757
+ let kind2 = "title", best = 0;
3758
+ for (const [candidate, total] of counts) if (total > best) {
3759
+ kind2 = candidate;
3760
+ best = total;
3761
+ }
3762
+ return { kind: kind2, count, heading };
3763
+ }
3764
+
2849
3765
  // src/composition.ts
2850
3766
  var MAX_COMPOSITION_DEPTH = 32;
2851
3767
  var FALLBACK_CODE_FAMILY = "Roboto Mono";
@@ -2862,7 +3778,7 @@ function resolveFontSchemeReference(reference, lookup, path = "design.fontScheme
2862
3778
  }
2863
3779
  function resolveFontFamilies(input) {
2864
3780
  const scheme = record5(input);
2865
- const family = (value) => typeof value === "string" ? value : record5(value).family;
3781
+ const family = (value) => typeof value === "string" && value ? value : void 0;
2866
3782
  const accent = family(scheme.accent);
2867
3783
  return {
2868
3784
  heading: family(scheme.heading) ?? scheme.major ?? scheme.minor ?? DEFAULT_FONT_FAMILIES.heading,
@@ -2946,7 +3862,7 @@ var OPFCompositionError = class extends Error {
2946
3862
  var fields = ["text", "items", "bullets", "image", "video", "chart", "table", "code", "metric", "quote", "timeline"];
2947
3863
  var headings = /* @__PURE__ */ new Set(["title", "subtitle", "tag"]);
2948
3864
  var COVER_LAYOUT_IDS = /* @__PURE__ */ new Set(["title", "title-subtitle"]);
2949
- var rows = ["top", "middle", "bottom"];
3865
+ var rows2 = ["top", "middle", "bottom"];
2950
3866
  var columns = ["left", "center", "right"];
2951
3867
  var record5 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
2952
3868
  var kind = (field) => field === "items" ? "list" : field === "bullets" ? "text" : field;
@@ -2982,14 +3898,14 @@ function resolveSlideImage(slide, layout, presentation, width, height, path, pad
2982
3898
  const configured = local ? own2.slideImage : deck.slideImage;
2983
3899
  if (!configured || typeof configured !== "object" && typeof configured !== "string") return void 0;
2984
3900
  const treatment = typeof configured === "object" && !Array.isArray(configured) && "position" in configured ? record5(configured) : void 0;
2985
- const alignment = typeof layout.slideImageAlignment === "string" ? layout.slideImageAlignment.toLowerCase() : void 0;
2986
- const authoredPosition = treatment ? treatment.position : SLIDE_IMAGE_POSITIONS.find((value2) => value2 === alignment) ?? "background";
3901
+ const layoutImage = record5(record5(layout.design).slideImage), layoutPosition = layoutImage.position;
3902
+ const authoredPosition = treatment ? treatment.position : SLIDE_IMAGE_POSITIONS.find((value2) => value2 === layoutPosition) ?? "background";
2987
3903
  if (!SLIDE_IMAGE_POSITIONS.includes(authoredPosition)) return void 0;
2988
3904
  const mirrorSide = (side) => !rtl ? side : side === "left" ? "right" : side === "right" ? "left" : side;
2989
3905
  const position = mirrorSide(authoredPosition);
2990
3906
  const designSource = treatment ? treatment.src : configured;
2991
3907
  const root = slide.image, sameSource = root !== void 0 && designSource !== void 0 && assetSource(root) === assetSource(designSource);
2992
- if (!local && layout.slideImage !== true && !sameSource) return void 0;
3908
+ if (!local && record5(layout.design).slideImage === void 0 && !sameSource) return void 0;
2993
3909
  const replacesContent = root !== void 0 && (designSource === void 0 || sameSource);
2994
3910
  const value = replacesContent ? root : designSource;
2995
3911
  const source = assetSource(value);
@@ -3058,10 +3974,10 @@ function resolveLogo(presentation, slide, options = {}) {
3058
3974
  if (typeof value === "string" || typeof value === "object" && !Array.isArray(value) && "src" in record5(value)) {
3059
3975
  return usable(value) ? { source: value, path, variant: "default", slot } : null;
3060
3976
  }
3061
- const set = record5(value);
3062
- if (!Object.keys(set).some((key) => LOGO_SET_KEYS.has(key))) return null;
3977
+ const set2 = record5(value);
3978
+ if (!Object.keys(set2).some((key) => LOGO_SET_KEYS.has(key))) return null;
3063
3979
  for (const key of chain) {
3064
- const variant = set[key];
3980
+ const variant = set2[key];
3065
3981
  if (variant !== void 0 && usable(variant)) return { source: variant, path: `${path}.${key}`, variant: key, slot };
3066
3982
  }
3067
3983
  return null;
@@ -3108,8 +4024,9 @@ function layoutFurniture(input, options = {}) {
3108
4024
  const sourceRoot = `slides.${options.slideIndex ?? 0}`, organizations = Array.isArray(options.presentation?.organization) ? options.presentation.organization : [options.presentation?.organization];
3109
4025
  const primaryIndex = organizations.findIndex((item) => record5(item).role === "primary"), organizationIndex = primaryIndex >= 0 ? primaryIndex : organizations.findIndex(Boolean);
3110
4026
  const organization = record5(organizations[organizationIndex]), organizationRoot = Array.isArray(options.presentation?.organization) ? `organization.${organizationIndex}` : "organization", organizationPath = `${organizationRoot}.name`;
4027
+ const speakers = Array.isArray(options.presentation?.speaker) ? options.presentation.speaker : [options.presentation?.speaker], speaker = record5(speakers[0]), speakerRoot = Array.isArray(options.presentation?.speaker) ? "speaker.0" : "speaker";
3111
4028
  const inlinePlatforms = record5(record5(options.presentation?.catalogs).socialPlatforms).records, platformRecords = [...Array.isArray(inlinePlatforms) ? inlinePlatforms : [], ...options.socialPlatforms ?? []];
3112
- const fontFamily = options.fonts?.body ?? "sans-serif";
4029
+ const fontFamily = options.fontFamilies?.body ?? "sans-serif";
3113
4030
  let headerBottom = 0, footerTop = height, configured = false;
3114
4031
  const error = (path, message, code = "text-overflow") => diagnostics.push({ code, path, message });
3115
4032
  for (const kind2 of ["header", "footer"]) {
@@ -3179,6 +4096,10 @@ function layoutFurniture(input, options = {}) {
3179
4096
  if (typeof organization.name === "string") add("organization", organization.name, true, organizationPath);
3180
4097
  else error(`${path}.organization`, "Generated organization name needs a named organization in the presentation.", "unresolved-content");
3181
4098
  }
4099
+ if (content.speaker === true) {
4100
+ if (typeof speaker.name === "string" && speaker.name.trim()) add("speaker", typeof speaker.title === "string" && speaker.title.trim() ? `${speaker.name}, ${speaker.title}` : speaker.name, true, `${speakerRoot}.name`);
4101
+ else error(`${path}.speaker`, "Generated speaker needs a named speaker in the presentation.", "unresolved-content");
4102
+ }
3182
4103
  if (content.socials === true) {
3183
4104
  const links = Object.entries(record5(organization.socials)).filter(([, value2]) => typeof value2 === "string" && value2.trim()).map(([platform, value2]) => ({ platform, sourcePath: `${organizationRoot}.socials.${platform}`, ...resolveSocialProfile(platform, value2, platformRecords, "organization") }));
3184
4105
  if (links.length) add("socials", links.map((link) => link.text).join("\n"), true, `${organizationRoot}.socials`, { links });
@@ -3272,12 +4193,25 @@ function fitAtSizes(layout, requested, minimum, step = 1, snap = true) {
3272
4193
  }
3273
4194
  throw new Error("Text fitting did not evaluate its bounded floor trial.");
3274
4195
  }
4196
+ var PHOTO_RATIO = 3;
4197
+ var PHOTO_GAP = 0.75;
4198
+ function quoteBodyRuns(runs) {
4199
+ if (!runs.length) return ['""'];
4200
+ const last = runs.length - 1;
4201
+ return runs.map((run, index) => {
4202
+ const before = index === 0 ? '"' : "", after = index === last ? '"' : "";
4203
+ return typeof run === "string" ? before + run + after : { ...run, text: before + run.text + after };
4204
+ });
4205
+ }
3275
4206
  function layoutQuote(value, box, options = {}) {
3276
4207
  const shorthand = typeof value === "string";
3277
4208
  const quote = shorthand ? { text: value } : value;
3278
- if (!quote || Array.isArray(quote) || typeof quote.text !== "string" || [quote.attribution, quote.source].some((field) => field !== void 0 && typeof field !== "string")) {
3279
- throw new TypeError("Quote content must be a string or a text object with optional string attribution/source.");
4209
+ const photoValue = quote?.photo;
4210
+ if (!quote || Array.isArray(quote) || typeof quote.text !== "string" && !Array.isArray(quote.text) || [quote.attribution, quote.role, quote.source].some((field) => field !== void 0 && typeof field !== "string") || photoValue !== void 0 && typeof photoValue !== "string" && !(typeof photoValue === "object" && photoValue !== null && typeof photoValue.src === "string")) {
4211
+ throw new TypeError("Quote content must be a string or a text object (text a string or TextRun[]) with optional string attribution/role/source and an asset photo.");
3280
4212
  }
4213
+ const richBody = Array.isArray(quote.text) ? quote.text : void 0;
4214
+ const quoteText = richBody ? annotationText(richBody) : quote.text;
3281
4215
  const scale = options.scale ?? 1, minimum = snapFontSizeUp((options.minFontSize ?? 16) * scale);
3282
4216
  if (![box.x, box.y, box.width, box.height, scale, minimum].every(Number.isFinite) || box.width <= 0 || box.height <= 0 || scale <= 0 || minimum <= 0) {
3283
4217
  throw new RangeError("Quote dimensions, scale and minimum font size must be finite and positive.");
@@ -3287,78 +4221,96 @@ function layoutQuote(value, box, options = {}) {
3287
4221
  const diagnostics = [], parts = [];
3288
4222
  const report = (reason, diagnosticPath, roles, message) => diagnostics.push({ code: "text-overflow", reason, path: diagnosticPath, parts: roles, message });
3289
4223
  const source = (sourcePath, text2, outputStart) => ({ path: sourcePath, start: 0, end: text2.length, outputStart, outputEnd: outputStart + text2.length });
3290
- const add = (role, text2, sources, area, fontSize, fontFamily, fontWeight, partPath) => {
4224
+ const add = (role, text2, sources, area, fontSize, fontFamily, fontWeight, partPath, runs) => {
3291
4225
  const requestedStyle = { fontFamily, fontWeight, italic: false, path: partPath };
3292
4226
  const style = resolveTextStyle({ ...requestedStyle }, options.textMeasurement);
3293
4227
  const requestedFontSize = gridFontSize(fontSize * scale, minimum);
3294
- const part = { role, path: partPath, text: text2, sources, box: area, requestedFontSize, minFontSize: minimum, requestedStyle, style };
4228
+ const part = { role, path: partPath, text: text2, sources, box: area, requestedFontSize, minFontSize: minimum, requestedStyle, style, ...runs ? { runs } : {} };
3295
4229
  parts.push(part);
3296
4230
  return part;
3297
4231
  };
3298
4232
  let footer = "";
3299
4233
  const footerSources = [];
3300
- for (const field of ["attribution", "source"]) {
4234
+ for (const field of ["attribution", "role", "source"]) {
3301
4235
  const text2 = quote[field];
3302
4236
  if (!text2) continue;
3303
- if (footer) footer += " - ";
4237
+ if (footer) footer += field === "role" ? "\n" : " - ";
3304
4238
  footerSources.push(source(`${path}.${field}`, text2, footer.length));
3305
4239
  footer += text2;
3306
4240
  }
4241
+ const hasPhoto = photoValue !== void 0, hasFooter = footer !== "", hasBlock = hasPhoto || hasFooter;
4242
+ const photoPath = `${path}.photo`, rtl = options.direction === "rtl";
3307
4243
  const bodyPath = shorthand ? path : `${path}.text`;
3308
4244
  const body = add(
3309
4245
  "body",
3310
- `"${quote.text}"`,
3311
- [source(bodyPath, quote.text, 1)],
3312
- { x: box.x + 18, y: box.y + 18, width: box.width - 36, height: box.height - (footer ? 94 : 36) },
4246
+ `"${quoteText}"`,
4247
+ [source(bodyPath, quoteText, 1)],
4248
+ { x: box.x + 18, y: box.y + 18, width: box.width - 36, height: box.height - (hasBlock ? 94 : 36) },
3313
4249
  28,
3314
- options.fonts?.accent ?? options.fonts?.heading ?? "sans-serif",
4250
+ options.fontFamilies?.accent ?? options.fontFamilies?.heading ?? "sans-serif",
3315
4251
  600,
3316
- bodyPath
4252
+ bodyPath,
4253
+ richBody ? quoteBodyRuns(richBody) : void 0
3317
4254
  );
3318
- const attribution = footer ? add(
4255
+ const attribution = hasFooter ? add(
3319
4256
  "footer",
3320
4257
  footer,
3321
4258
  footerSources,
3322
4259
  { x: box.x + 18, y: box.y + box.height - 58, width: box.width - 36, height: 40 },
3323
4260
  17,
3324
- options.fonts?.body ?? "sans-serif",
4261
+ options.fontFamilies?.body ?? "sans-serif",
3325
4262
  500,
3326
4263
  path
3327
4264
  ) : void 0;
4265
+ const footerRequested = attribution?.requestedFontSize ?? gridFontSize(17 * scale, minimum);
3328
4266
  const usable = (area) => [area.x, area.y, area.width, area.height].every(Number.isFinite) && area.width > 0 && area.height > 0;
3329
- const fit = (part, area, size = part.requestedFontSize, floor = minimum) => usable(area) ? fitText(part.text, area, size, floor, textWidthMeasurer(part.style, options.textMeasurement), options.direction) : void 0;
4267
+ const fit = (part, area, size = part.requestedFontSize, floor = minimum) => !usable(area) ? void 0 : part.runs ? fitRichText(part.runs, area, size, floor, { style: part.style, textMeasurement: options.textMeasurement, ...options.citationMarker ? { citationMarker: options.citationMarker } : {}, ...options.direction ? { direction: options.direction } : {} }) : fitText(part.text, area, size, floor, textWidthMeasurer(part.style, options.textMeasurement), options.direction);
4268
+ const heightOf = (fit2) => "richLines" in fit2 ? fit2.height : fit2.lines.length * fit2.lineHeight;
3330
4269
  const inner = { x: box.x + 18, y: box.y + 18, width: box.width - 36, height: box.height - 36 };
3331
- if (!attribution) body.fit = fit(body, body.box);
4270
+ let photo, photoFits = true;
4271
+ if (!hasBlock) body.fit = fit(body, body.box);
3332
4272
  else if (usable(inner) && inner.height > 18) {
3333
4273
  const available = inner.height - 18;
3334
4274
  const preferredBody = fit(body, inner, body.requestedFontSize, body.requestedFontSize);
3335
4275
  const minimumBody = body.requestedFontSize === minimum ? preferredBody : fit(body, inner, minimum, minimum);
3336
- const preferredBodyHeight = preferredBody.lines.length * preferredBody.lineHeight;
3337
- const minimumBodyHeight = minimumBody.lines.length * minimumBody.lineHeight;
4276
+ const preferredBodyHeight = heightOf(preferredBody);
4277
+ const minimumBodyHeight = heightOf(minimumBody);
3338
4278
  let selected;
3339
- for (const size of /* @__PURE__ */ new Set([attribution.requestedFontSize, minimum])) {
3340
- const natural = fit(attribution, inner, size, size);
3341
- const naturalHeight = natural.lines.length * natural.lineHeight;
3342
- const preferredHeight = Math.max(40, naturalHeight);
3343
- const bodyReservation = Math.min(minimumBodyHeight, Math.max(minimumBody.lineHeight, available - natural.lineHeight));
3344
- const footerHeight = preferredBodyHeight + preferredHeight <= available + 0.01 ? preferredHeight : Math.min(naturalHeight, Math.max(0, available - bodyReservation));
4279
+ for (const size of /* @__PURE__ */ new Set([footerRequested, minimum])) {
4280
+ const diameter = hasPhoto ? PHOTO_RATIO * size : 0, gap = hasPhoto ? PHOTO_GAP * size : 0;
4281
+ const textArea = { ...inner, width: inner.width - diameter - gap, x: rtl ? inner.x : inner.x + diameter + gap };
4282
+ const natural = attribution ? fit(attribution, textArea, size, size) : void 0;
4283
+ const naturalHeight = natural ? natural.lines.length * natural.lineHeight : 0;
4284
+ const blockHeight = Math.max(naturalHeight, diameter);
4285
+ const lineHeight = natural?.lineHeight ?? size * 1.22;
4286
+ const preferredHeight = Math.max(40, blockHeight);
4287
+ const bodyReservation = Math.min(minimumBodyHeight, Math.max(minimumBody.lineHeight, available - lineHeight));
4288
+ const footerHeight = preferredBodyHeight + preferredHeight <= available + 0.01 ? preferredHeight : Math.min(blockHeight, Math.max(0, available - bodyReservation));
3345
4289
  const bodyBox = { ...inner, height: available - footerHeight };
3346
4290
  const footerBox = { ...inner, y: inner.y + inner.height - footerHeight, height: footerHeight };
3347
4291
  const bodyFit = fit(body, bodyBox);
3348
- const footerFit = usable(footerBox) ? { ...natural, overflow: natural.overflow || naturalHeight > footerHeight + 0.01 } : void 0;
3349
- const overflow = !bodyFit || !footerFit || bodyFit.overflow || footerFit.overflow;
3350
- const score = (body.requestedFontSize - (bodyFit?.fontSize ?? minimum) + attribution.requestedFontSize - size) / scale;
4292
+ const photoBox = hasPhoto ? { x: rtl ? inner.x + inner.width - diameter : inner.x, y: footerBox.y + (footerHeight - diameter) / 2, width: diameter, height: diameter } : void 0;
4293
+ const textBox = attribution ? hasPhoto ? { ...textArea, y: footerBox.y + Math.max(0, footerHeight - naturalHeight) / 2, height: Math.min(naturalHeight, footerHeight) } : footerBox : void 0;
4294
+ const footerFit = attribution && natural && usable(footerBox) ? { ...natural, overflow: natural.overflow || naturalHeight > footerHeight + 0.01 } : void 0;
4295
+ const fitsPhoto = !hasPhoto || diameter <= footerHeight + 0.01 && (!attribution || usable(textArea));
4296
+ const overflow = !bodyFit || bodyFit.overflow || (attribution ? !footerFit || footerFit.overflow : false) || !fitsPhoto;
4297
+ const score = (body.requestedFontSize - (bodyFit?.fontSize ?? minimum) + footerRequested - size) / scale;
3351
4298
  if (!selected || !overflow && (selected.overflow || score < selected.score) || overflow && selected.overflow) {
3352
- selected = { bodyBox, footerBox, bodyFit, footerFit, score, overflow };
4299
+ selected = { bodyBox, footerBox, textBox, photoBox, bodyFit, footerFit, score, overflow, photoFits: fitsPhoto };
3353
4300
  }
3354
4301
  }
3355
4302
  if (selected) {
3356
4303
  body.box = selected.bodyBox;
3357
4304
  body.fit = selected.bodyFit;
3358
- attribution.box = selected.footerBox;
3359
- attribution.fit = selected.footerFit;
4305
+ if (attribution) {
4306
+ attribution.box = selected.textBox ?? selected.footerBox;
4307
+ attribution.fit = selected.footerFit;
4308
+ }
4309
+ if (selected.photoBox) photo = { path: photoPath, value: photoValue, box: selected.photoBox, shape: slideImageShape("circle", selected.photoBox) };
4310
+ photoFits = selected.photoFits;
3360
4311
  }
3361
4312
  }
4313
+ if (hasPhoto && !photo) photoFits = false;
3362
4314
  for (const part of parts) {
3363
4315
  const area = part.box;
3364
4316
  if (!part.fit) {
@@ -3370,17 +4322,20 @@ function layoutQuote(value, box, options = {}) {
3370
4322
  report("part-outside-cell", part.path, [part.role], `Quote ${part.role} extends outside its cell; increase the cell size or change the arrangement.`);
3371
4323
  }
3372
4324
  }
3373
- if (body?.fit && attribution?.fit && body.box.y + body.fit.lines.length * body.fit.lineHeight > attribution.box.y + 0.01 && attribution.box.y + attribution.fit.lines.length * attribution.fit.lineHeight > body.box.y + 0.01) {
4325
+ if (hasPhoto && !photoFits) report("photo-fit", photoPath, ["footer"], "Quote photo does not fit beside the attribution at the readability floor; increase the cell size, shorten the text or remove the photo.");
4326
+ if (body?.fit && attribution?.fit && body.box.y + heightOf(body.fit) > attribution.box.y + 0.01 && attribution.box.y + attribution.fit.lines.length * attribution.fit.lineHeight > body.box.y + 0.01) {
3374
4327
  report("part-overlap", path, ["body", "footer"], "Quote body and footer line boxes overlap; do not accept this layout without more space.");
4328
+ } else if (body?.fit && photo && body.box.y + heightOf(body.fit) > photo.box.y + 0.01) {
4329
+ report("part-overlap", path, ["body", "footer"], "Quote body and photo overlap; do not accept this layout without more space.");
3375
4330
  }
3376
4331
  if (diagnostics.length && options.overflow === "error") throw new OPFCompositionError(diagnostics);
3377
- return { algorithm: "quote-flow-v1", textMeasurement: options.textMeasurement ? "provided" : "estimated", parts, diagnostics, overflow: diagnostics.length > 0 };
4332
+ return { algorithm: "quote-flow-v1", textMeasurement: options.textMeasurement ? "provided" : "estimated", parts, ...photo ? { photo } : {}, diagnostics, overflow: diagnostics.length > 0 };
3378
4333
  }
3379
4334
  function layoutMetric(value, box, options = {}) {
3380
4335
  const scalar = typeof value === "string" || typeof value === "number";
3381
4336
  const metric = scalar ? { value } : value;
3382
4337
  const isValue = (input) => typeof input === "string" || typeof input === "number" && Number.isFinite(input);
3383
- if (!metric || Array.isArray(metric) || !isValue(metric.value) || [metric.label, metric.description, metric.unit].some((field) => field !== void 0 && typeof field !== "string") || metric.delta !== void 0 && !isValue(metric.delta) || metric.trend !== void 0 && !["up", "down", "flat"].includes(metric.trend)) {
4338
+ if (!metric || Array.isArray(metric) || !isValue(metric.value) || [metric.label, metric.description, metric.unit].some((field) => field !== void 0 && typeof field !== "string") || metric.delta !== void 0 && !isValue(metric.delta) || metric.trend !== void 0 && !["up", "down", "flat"].includes(metric.trend) || metric.sentiment !== void 0 && !["positive", "negative", "neutral"].includes(metric.sentiment)) {
3384
4339
  throw new TypeError("Metric content requires a finite numeric or string value and schema-valid display metadata.");
3385
4340
  }
3386
4341
  const scale = options.scale ?? 1, minimum = snapFontSizeUp((options.minFontSize ?? 16) * scale);
@@ -3398,7 +4353,7 @@ function layoutMetric(value, box, options = {}) {
3398
4353
  if (sourceValue === void 0) continue;
3399
4354
  const text2 = String(sourceValue), path = scalar ? sourcePath : `${sourcePath}.${role}`;
3400
4355
  const nominal = role === "value" ? Math.min(76 * scale, box.height * 0.28) : (role === "description" ? 20 : role === "trend" ? 18 : 23) * scale;
3401
- const requestedStyle = { fontFamily: (role === "value" ? options.fonts?.heading : options.fonts?.body) ?? "sans-serif", fontWeight: role === "value" ? 800 : role === "description" ? 400 : 500, italic: false, path };
4356
+ const requestedStyle = { fontFamily: (role === "value" ? options.fontFamilies?.heading : options.fontFamilies?.body) ?? "sans-serif", fontWeight: role === "value" ? 800 : role === "description" ? 400 : 500, italic: false, path };
3402
4357
  const part = {
3403
4358
  role,
3404
4359
  path,
@@ -3544,24 +4499,28 @@ function layoutMetric(value, box, options = {}) {
3544
4499
  }
3545
4500
  }
3546
4501
  if (diagnostics.length && options.overflow === "error") throw new OPFCompositionError(diagnostics);
3547
- return { algorithm: "metric-flow-v1", alignment, textMeasurement: options.textMeasurement ? "provided" : "estimated", arrangement: selected.arrangement, attempts, parts, diagnostics, overflow: diagnostics.length > 0 };
4502
+ return { algorithm: "metric-flow-v1", alignment, textMeasurement: options.textMeasurement ? "provided" : "estimated", arrangement: selected.arrangement, ...metric.sentiment === void 0 ? {} : { sentiment: metric.sentiment }, attempts, parts, diagnostics, overflow: diagnostics.length > 0 };
3548
4503
  }
4504
+ var TIMELINE_STATUS_VALUES = ["done", "current", "planned"];
4505
+ var TIMELINE_RING_RATIO = 1.6;
3549
4506
  function layoutTimeline(value, box, options = {}) {
3550
4507
  const shorthand = Array.isArray(value), timeline = shorthand ? { events: value } : value;
3551
4508
  if (!timeline || !Array.isArray(timeline.events) || !timeline.events.length || [timeline.name, timeline.description].some((field) => field !== void 0 && typeof field !== "string") || timeline.events.some((event) => !event || typeof event.what !== "string" || [event.when, event.description].some((field) => field !== void 0 && typeof field !== "string"))) {
3552
4509
  throw new TypeError("Timeline content requires ordered events with string labels and optional string metadata.");
3553
4510
  }
4511
+ if (timeline.events.some((event) => event.status !== void 0 && !TIMELINE_STATUS_VALUES.includes(event.status))) throw new TypeError("Timeline event status must be 'done', 'current' or 'planned'.");
3554
4512
  const scale = options.scale ?? 1, minimum = snapFontSizeUp((options.minFontSize ?? 16) * scale), padding = (options.textRasterPadding ?? 1) * scale;
3555
4513
  if (![box.x, box.y, box.width, box.height, scale, minimum, padding].every(Number.isFinite) || box.width <= 0 || box.height <= 0 || scale <= 0 || minimum <= 0 || padding < 0) throw new RangeError("Timeline dimensions, scale and minimum must be positive, with finite nonnegative raster padding.");
3556
4514
  if (options.overflow !== void 0 && !["warn", "error"].includes(options.overflow)) throw new RangeError("Invalid timeline overflow policy.");
3557
4515
  const outlines = options.textMeasurement?.outlineBounds !== void 0, rtl = options.direction === "rtl";
3558
4516
  if (outlines && typeof options.textMeasurement?.outlineBounds !== "function") throw new TypeError("Text outline provider must be a function.");
3559
4517
  const path = options.path ?? "timeline", eventPath = (index) => shorthand ? `${path}.${index}` : `${path}.events.${index}`;
3560
- const fonts = resolveFontFamilies(options.fonts), source = [];
4518
+ const fonts = resolveFontFamilies(options.fontFamilies), source = [];
3561
4519
  const add = (role, text2, partPath, size, weight, eventIndex) => {
3562
4520
  if (text2 === void 0) return;
3563
- const requestedStyle = { fontFamily: fonts.body, fontWeight: weight, italic: false, path: partPath };
3564
- source.push({ role, eventIndex, path: partPath, text: text2, sources: [{ path: partPath, start: 0, end: text2.length }], box: { ...box }, alignment: "center", requestedFontSize: gridFontSize(size * scale, minimum), minFontSize: minimum, requestedStyle, style: resolveTextStyle({ ...requestedStyle }, options.textMeasurement) });
4521
+ const status = eventIndex === void 0 ? void 0 : timeline.events[eventIndex].status;
4522
+ const requestedStyle = { fontFamily: fonts.body, fontWeight: status === "current" && role === "what" ? 700 : weight, italic: false, path: partPath };
4523
+ source.push({ role, eventIndex, ...status ? { status } : {}, path: partPath, text: text2, sources: [{ path: partPath, start: 0, end: text2.length }], box: { ...box }, alignment: "center", requestedFontSize: gridFontSize(size * scale, minimum), minFontSize: minimum, requestedStyle, style: resolveTextStyle({ ...requestedStyle }, options.textMeasurement) });
3565
4524
  };
3566
4525
  add("name", timeline.name, `${path}.name`, 24, 700);
3567
4526
  add("description", timeline.description, `${path}.description`, 18, 400);
@@ -3631,12 +4590,18 @@ function layoutTimeline(value, box, options = {}) {
3631
4590
  y += placed.box.height + 8 * scale;
3632
4591
  }
3633
4592
  const available = box.y + box.height - y, count = events.length, radius = Math.min(9 * scale, box.width / Math.max(2, count) / 5, Math.max(scale, available) * 0.04);
4593
+ const statusOf = (index) => timeline.events[index].status, ringRadius = radius * TIMELINE_RING_RATIO, strokeWidth = Math.min(2 * scale, radius / 2);
4594
+ const hasRing = timeline.events.some((event) => event.status === "current");
4595
+ const marker = (index, x, y2) => {
4596
+ const status = statusOf(index);
4597
+ return { path: eventPath(index), eventIndex: index, x, y: y2, radius, ...status ? { status } : {}, ...status === "current" ? { ring: { radius: ringRadius } } : {}, ...status === "current" || status === "planned" ? { strokeWidth } : {} };
4598
+ };
3634
4599
  if (arrangement === "alternating") {
3635
4600
  const width = box.width / Math.max(2, count), step = (box.width - width) / Math.max(1, count - 1), start = count === 1 ? box.x + box.width / 2 : box.x + width / 2;
3636
4601
  const lineY = y + Math.max(scale, available) * 0.46;
3637
4602
  events.forEach((fields2, index) => {
3638
4603
  const x = start + (rtl ? count - 1 - index : index) * step, top = index % 2 === 0 ? y : lineY + 24 * scale, bottom = index % 2 === 0 ? lineY - 24 * scale : box.y + box.height;
3639
- markers.push({ path: eventPath(index), eventIndex: index, x, y: lineY, radius });
4604
+ markers.push(marker(index, x, lineY));
3640
4605
  let cursor = top;
3641
4606
  for (const part of fields2) {
3642
4607
  const placed = place(part, x - width / 2, cursor, width, "center");
@@ -3645,7 +4610,8 @@ function layoutTimeline(value, box, options = {}) {
3645
4610
  }
3646
4611
  });
3647
4612
  } else {
3648
- const x = rtl ? box.x + box.width - radius : box.x + radius, textX = rtl ? box.x : box.x + 24 * scale, width = box.width - 24 * scale;
4613
+ const lead = hasRing ? ringRadius + strokeWidth / 2 : radius, gap = 24 * scale + (lead - radius);
4614
+ const x = rtl ? box.x + box.width - lead : box.x + lead, textX = rtl ? box.x : box.x + gap, width = box.width - gap;
3649
4615
  events.forEach((fields2, index) => {
3650
4616
  const top = y;
3651
4617
  let first2;
@@ -3654,13 +4620,16 @@ function layoutTimeline(value, box, options = {}) {
3654
4620
  first2 ??= placed;
3655
4621
  y += placed.box.height;
3656
4622
  }
3657
- markers.push({ path: eventPath(index), eventIndex: index, x, y: top + Math.min(first2?.box.height ?? 2 * radius, 2 * radius) / 2, radius });
4623
+ markers.push(marker(index, x, top + Math.min(first2?.box.height ?? 2 * radius, 2 * radius) / 2));
3658
4624
  y += 16 * scale;
3659
4625
  });
3660
4626
  }
3661
- for (const marker of markers) if (marker.x - marker.radius < box.x - 0.01 || marker.y - marker.radius < box.y - 0.01 || marker.x + marker.radius > box.x + box.width + 0.01 || marker.y + marker.radius > box.y + box.height + 0.01) {
3662
- diagnostics.push({ code: "text-overflow", reason: "event-space", path: marker.path, message: "Timeline marker has no usable space; increase the cell or paginate events." });
3663
- score2 += 1;
4627
+ for (const marker2 of markers) {
4628
+ const extent = (marker2.ring?.radius ?? marker2.radius) + (marker2.strokeWidth ?? 0) / 2;
4629
+ if (marker2.x - extent < box.x - 0.01 || marker2.y - extent < box.y - 0.01 || marker2.x + extent > box.x + box.width + 0.01 || marker2.y + extent > box.y + box.height + 0.01) {
4630
+ diagnostics.push({ code: "text-overflow", reason: "event-space", path: marker2.path, message: "Timeline marker has no usable space; increase the cell or paginate events." });
4631
+ score2 += 1;
4632
+ }
3664
4633
  }
3665
4634
  const first = markers[0], last = markers.at(-1), connector = rtl ? { x1: Math.min(first.x, last.x), y1: first.y, x2: Math.max(first.x, last.x), y2: last.y } : { x1: first.x, y1: first.y, x2: last.x, y2: last.y };
3666
4635
  const candidate = { arrangement, parts, markers, connector, diagnostics, score: score2 };
@@ -3771,7 +4740,7 @@ function layoutCode(value, box, options = {}) {
3771
4740
  const path = options.path ?? "code", inner = { x: box.x + 18, y: box.y + 18, width: box.width - 36, height: box.height - 36 };
3772
4741
  const parts = [], diagnostics = [];
3773
4742
  const add = (role, text2, partPath, generated = false) => {
3774
- const requestedStyle = { fontFamily: options.fonts?.code ?? "monospace", fontWeight: role === "body" ? 400 : 700, italic: false, path: partPath };
4743
+ const requestedStyle = { fontFamily: options.fontFamilies?.code ?? "monospace", fontWeight: role === "body" ? 400 : 700, italic: false, path: partPath };
3775
4744
  const part = {
3776
4745
  role,
3777
4746
  path: partPath,
@@ -3857,7 +4826,8 @@ function richTextLayouter(input, box, requestedSize, options, minimum = 0) {
3857
4826
  if (typeof run?.text !== "string" || run.fontSize !== void 0 && (!Number.isFinite(run.fontSize) || run.fontSize <= 0)) throw new RangeError("Rich text runs need text and a positive finite font size.");
3858
4827
  const start = offset;
3859
4828
  offset += run.text.length;
3860
- const style = resolveTextStyle({ ...options.style, fontFamily: run.fontFamily ?? options.style.fontFamily, fontWeight: run.bold === void 0 ? options.style.fontWeight : run.bold ? 700 : 400, italic: run.italic ?? options.style.italic, path: options.style.path ? `${options.style.path}.${runIndex}` : void 0 }, options.textMeasurement);
4829
+ const resolvedStyle = resolveTextStyle({ ...options.style, fontFamily: run.fontFamily ?? (run.code === true ? options.codeFontFamily ?? "monospace" : options.style.fontFamily), fontWeight: run.bold === void 0 ? options.style.fontWeight : run.bold ? 700 : 400, italic: run.italic ?? options.style.italic, path: options.style.path ? `${options.style.path}.${runIndex}` : void 0 }, options.textMeasurement);
4830
+ const style = typeof run.lang === "string" && run.lang ? { ...resolvedStyle, lang: run.lang } : resolvedStyle;
3861
4831
  const marker = options.citationMarker && options.style.path && run.text ? options.citationMarker(`${options.style.path}.${runIndex}`) : void 0;
3862
4832
  return { run, runIndex, start, end: offset, style, ...marker ? { marker } : {} };
3863
4833
  });
@@ -3974,15 +4944,15 @@ var PICTURE_BULLET_SCALE = 0.65;
3974
4944
  function fitList(input, box, requestedSize = 25, minFontSize = 16, options = { style: { fontFamily: "sans-serif", fontWeight: 400 } }) {
3975
4945
  if (!Array.isArray(input) || ![box.width, box.height, requestedSize, minFontSize].every((value) => Number.isFinite(value) && value > 0)) throw new RangeError("List content, dimensions and font sizes must be valid.");
3976
4946
  const source = input.map((value, index) => {
3977
- const object = typeof value === "object" && !Array.isArray(value) ? value : void 0;
3978
- const text2 = object ? object.text : value, description = object?.description, level = object?.level ?? 0;
4947
+ const object2 = typeof value === "object" && !Array.isArray(value) ? value : void 0;
4948
+ const text2 = object2 ? object2.text : value, description = object2?.description, level = object2?.level ?? 0;
3979
4949
  if (!Number.isInteger(level) || level < 0) throw new RangeError("List levels must be nonnegative integers.");
3980
4950
  const runs = (value2) => typeof value2 === "string" ? [value2] : value2;
3981
4951
  if (!Array.isArray(runs(text2)) || description !== void 0 && !Array.isArray(runs(description))) throw new TypeError("List text and descriptions must be strings or text runs.");
3982
4952
  const base = options.style.path ? `${options.style.path}.${index}` : void 0;
3983
4953
  const plain = (value2) => typeof value2 === "string" ? value2 : value2.map((run) => typeof run === "string" ? run : run.text).join("");
3984
4954
  const direction = options.direction === "rtl" ? paragraphDirection(plain(text2), "rtl") : void 0;
3985
- return { index, level, direction, value: text2, descriptionValue: description, textPath: base ? base + (object ? ".text" : "") : void 0, descriptionPath: base ? base + ".description" : void 0, runs: runs(text2), descriptionRuns: description === void 0 ? void 0 : runs(description) };
4955
+ return { index, level, direction, value: text2, descriptionValue: description, textPath: base ? base + (object2 ? ".text" : "") : void 0, descriptionPath: base ? base + ".description" : void 0, runs: runs(text2), descriptionRuns: description === void 0 ? void 0 : runs(description) };
3986
4956
  });
3987
4957
  const numbers = options.numbering === void 0 ? void 0 : listNumbers(input, options.numbering);
3988
4958
  const markerStyleFor = (item) => {
@@ -4079,13 +5049,13 @@ function layoutTable(value, box, options = {}) {
4079
5049
  const cellMinimum = (cell) => Array.isArray(cell.value) ? richMinimum(cell.value, requested, minimum) : minimum;
4080
5050
  const fitCell = (cell, height, min) => {
4081
5051
  const textBox = { width: Math.max(scale, cell.width), height: Math.max(scale, height) };
4082
- return Array.isArray(cell.value) ? fitRichText(cell.value, textBox, requested, min, { style: cell.textStyle, textMeasurement: options.textMeasurement, uniformLineHeight: true, direction: options.direction }) : fitText(flatten(cell.value), textBox, requested, min, textWidthMeasurer(resolveTextStyle(cell.textStyle, options.textMeasurement), options.textMeasurement), options.direction);
5052
+ return Array.isArray(cell.value) ? fitRichText(cell.value, textBox, requested, min, { style: cell.textStyle, ...options.codeFontFamily ? { codeFontFamily: options.codeFontFamily } : {}, textMeasurement: options.textMeasurement, uniformLineHeight: true, direction: options.direction }) : fitText(flatten(cell.value), textBox, requested, min, textWidthMeasurer(resolveTextStyle(cell.textStyle, options.textMeasurement), options.textMeasurement), options.direction);
4083
5053
  };
4084
5054
  const textHeight = (fit) => "height" in fit ? fit.height : fit.lines.length * fit.lineHeight;
4085
5055
  const required = (cell, natural2) => {
4086
5056
  const floor = cellMinimum(cell), size = gridFontSize(natural2 ? Math.max(requested, floor) : floor, floor);
4087
5057
  const textBox = { width: Math.max(scale, cell.width), height: scale };
4088
- const fit = Array.isArray(cell.value) ? richTextLayouter(cell.value, textBox, requested, { style: cell.textStyle, textMeasurement: options.textMeasurement, uniformLineHeight: true }, minimum)(size) : fitText(flatten(cell.value), textBox, size, size, textWidthMeasurer(resolveTextStyle(cell.textStyle, options.textMeasurement), options.textMeasurement));
5058
+ const fit = Array.isArray(cell.value) ? richTextLayouter(cell.value, textBox, requested, { style: cell.textStyle, ...options.codeFontFamily ? { codeFontFamily: options.codeFontFamily } : {}, textMeasurement: options.textMeasurement, uniformLineHeight: true }, minimum)(size) : fitText(flatten(cell.value), textBox, size, size, textWidthMeasurer(resolveTextStyle(cell.textStyle, options.textMeasurement), options.textMeasurement));
4089
5059
  return textHeight(fit) + (cell.padding.top + cell.padding.bottom) * scale;
4090
5060
  };
4091
5061
  const natural = Array(grid.rowCount).fill(0), needed = Array(grid.rowCount).fill(0);
@@ -4106,7 +5076,7 @@ function layoutTable(value, box, options = {}) {
4106
5076
  const ys = [box.y];
4107
5077
  for (const height of heights) ys.push(ys.at(-1) + height);
4108
5078
  let overflow = false;
4109
- const rows2 = heights.map((height, r) => ({ box: { x: box.x, y: ys[r], width: box.width, height }, cells: [] }));
5079
+ const rows3 = heights.map((height, r) => ({ box: { x: box.x, y: ys[r], width: box.width, height }, cells: [] }));
4110
5080
  for (const cell of cells) {
4111
5081
  const cellBox = { x: box.x + (options.direction === "rtl" ? columnCount - cell.column - cell.colSpan : cell.column) * cellWidth, y: ys[cell.row], width: cell.colSpan * cellWidth, height: ys[cell.row + cell.rowSpan] - ys[cell.row] };
4112
5082
  const available = cellBox.height - (cell.padding.top + cell.padding.bottom) * scale;
@@ -4114,12 +5084,12 @@ function layoutTable(value, box, options = {}) {
4114
5084
  const offset = cell.style.verticalAlign === "bottom" ? Math.max(0, available - height) : cell.style.verticalAlign === "middle" ? Math.max(0, (available - height) / 2) : 0;
4115
5085
  const textBox = { x: cellBox.x + cell.padding.left * scale, y: cellBox.y + cell.padding.top * scale + offset, width: Math.max(scale, cell.width), height: Math.max(scale, available - offset) };
4116
5086
  overflow ||= cell.width <= 0 || available <= 0 || fit.overflow;
4117
- rows2[cell.row].cells.push({ value: cell.value, input: cell.input, path: cell.valuePath, sourcePath: cell.path, style: cell.style, row: cell.row, column: cell.column, rowSpan: cell.rowSpan, colSpan: cell.colSpan, header: cell.header, rich: Array.isArray(cell.value), box: cellBox, textBox, textStyle: resolveTextStyle(cell.textStyle, options.textMeasurement), fit, ...fit.directions ? { direction: fit.directions[0] } : {} });
5087
+ rows3[cell.row].cells.push({ value: cell.value, input: cell.input, path: cell.valuePath, sourcePath: cell.path, style: cell.style, row: cell.row, column: cell.column, rowSpan: cell.rowSpan, colSpan: cell.colSpan, header: cell.header, rich: Array.isArray(cell.value), box: cellBox, textBox, textStyle: resolveTextStyle(cell.textStyle, options.textMeasurement), fit, ...fit.directions ? { direction: fit.directions[0] } : {} });
4118
5088
  }
4119
- return { rows: rows2, columnCount, height: sum(heights), overflow };
5089
+ return { rows: rows3, columnCount, height: sum(heights), overflow };
4120
5090
  }
4121
5091
  function tableOverflows(value, box, scale, settings, options, path) {
4122
- return box.width <= 0 || box.height <= 0 || layoutTable(value, box, { scale, minFontSize: settings.minFontSize, fontFamily: options.fonts?.body, textMeasurement: options.textMeasurement, path, presentation: options.presentation }).overflow;
5092
+ return box.width <= 0 || box.height <= 0 || layoutTable(value, box, { scale, minFontSize: settings.minFontSize, fontFamily: options.fontFamilies?.body, ...options.fontFamilies?.code ? { codeFontFamily: options.fontFamilies.code } : {}, textMeasurement: options.textMeasurement, path, presentation: options.presentation }).overflow;
4123
5093
  }
4124
5094
  function flatten(value) {
4125
5095
  if (value == null) return "";
@@ -4135,10 +5105,10 @@ function regionParts(key) {
4135
5105
  };
4136
5106
  const parts = key.split(":");
4137
5107
  if (parts.length === 2) {
4138
- const r = span(parts[0], rows), c = span(parts[1], columns);
5108
+ const r = span(parts[0], rows2), c = span(parts[1], columns);
4139
5109
  if (r && c) return [r, c];
4140
5110
  } else if (parts.length === 1) {
4141
- const r = span(key, rows), c = span(key, columns);
5111
+ const r = span(key, rows2), c = span(key, columns);
4142
5112
  if (r) return [r, [0, 1, 2]];
4143
5113
  if (c) return [[0, 1, 2], c];
4144
5114
  }
@@ -4187,7 +5157,8 @@ function composeSlide(input, options = {}) {
4187
5157
  const scale = Math.min(width, height) / 720;
4188
5158
  const deckDirection = options.direction ?? resolveSlideDirection(options.presentation, options.slideIndex);
4189
5159
  const rtl = deckDirection === "rtl", textDirection = rtl ? "rtl" : void 0;
4190
- const hasCards = record5(slide.design).contentBox ?? options.contentBox ?? false;
5160
+ const hints = resolveDesignHints({ slide, layout, presentation: options.presentation, slideIndex: options.slideIndex, deck: { titleAlignment: options.titleAlignment, contentAlignment: options.contentAlignment, contentBox: options.contentBox } });
5161
+ const hasCards = hints.contentBox ?? false;
4191
5162
  const composition = { ...record5(layout.composition), ...record5(slide.composition) };
4192
5163
  assertComposition(composition);
4193
5164
  const padding = (composition.padding ?? 0.08) * Math.min(width, height);
@@ -4196,15 +5167,13 @@ function composeSlide(input, options = {}) {
4196
5167
  const rasterPadding = (options.textRasterPadding ?? 1) * scale;
4197
5168
  if (!Number.isFinite(rasterPadding) || rasterPadding < 0) throw new RangeError("Text raster padding must be finite and nonnegative.");
4198
5169
  let coverGroup = false;
4199
- const alignmentFor = (field) => (field === "title" || coverGroup && (field === "tag" || field === "subtitle") && record5(slide.design).contentAlignment === void 0 ? record5(slide.design).titleAlignment ?? options.titleAlignment : record5(slide.design).contentAlignment ?? options.contentAlignment) ?? "left";
5170
+ const alignmentFor = (field) => (field === "title" || coverGroup && (field === "tag" || field === "subtitle") && hints.sources.contentAlignment !== "slide" ? hints.titleAlignment : hints.contentAlignment) ?? "left";
4200
5171
  const styleFor = (field, path2) => resolveTextStyle({
4201
- fontFamily: (field === "title" ? options.fonts?.heading : field === "code" ? options.fonts?.code : field === "tag" ? options.fonts?.accent ?? options.fonts?.body : options.fonts?.body) ?? (field === "code" ? "monospace" : "sans-serif"),
5172
+ fontFamily: (field === "title" ? options.fontFamilies?.heading : field === "code" ? options.fontFamilies?.code : field === "tag" ? options.fontFamilies?.accent ?? options.fontFamilies?.body : options.fontFamilies?.body) ?? (field === "code" ? "monospace" : "sans-serif"),
4202
5173
  fontWeight: field === "title" ? 700 : 400,
4203
5174
  path: path2
4204
5175
  }, options.textMeasurement);
4205
- const slideDesign = record5(slide.design), deckDesign = record5(record5(options.presentation).design);
4206
- const designHint = (field) => slideDesign[field] !== void 0 ? { value: slideDesign[field], path: `slides.${options.slideIndex ?? 0}.design.${field}` } : deckDesign[field] !== void 0 ? { value: deckDesign[field], path: `design.${field}` } : void 0;
4207
- const listBullet = designHint("listBullet");
5176
+ const listBullet = hints.listBullet !== void 0 ? { value: hints.listBullet, path: hints.paths.listBullet } : void 0;
4208
5177
  const bulletImage = listBullet?.value === "image" ? (() => {
4209
5178
  const resolved = resolveLogo(options.presentation, slide, { slot: "icon", onDark: options.darkBackground, slideIndex: options.slideIndex });
4210
5179
  return resolved ? { source: resolved.source, path: resolved.path } : void 0;
@@ -4212,9 +5181,9 @@ function composeSlide(input, options = {}) {
4212
5181
  const widthFor = (field, path2) => textWidthMeasurer(styleFor(field, path2), options.textMeasurement);
4213
5182
  const citations = slideCitations(slide, options.slideIndex ?? 0, options.presentation);
4214
5183
  const citationMarker = citations ? (runPath) => citations.markers.get(runPath) : void 0;
4215
- const richOptions = (style) => ({ style, textMeasurement: options.textMeasurement, ...citationMarker ? { citationMarker } : {}, ...rtl ? { direction: "rtl" } : {} });
5184
+ const richOptions = (style) => ({ style, textMeasurement: options.textMeasurement, ...options.fontFamilies?.code ? { codeFontFamily: options.fontFamilies.code } : {}, ...citationMarker ? { citationMarker } : {}, ...rtl ? { direction: "rtl" } : {} });
4216
5185
  const fitPlacedText = (field, value, text2, box, size, minimum, path2, explicitAlignment) => {
4217
- const style = styleFor(field, path2), rich = field === "text" && Array.isArray(value);
5186
+ const style = styleFor(field, path2), rich = (field === "text" || headings.has(field)) && Array.isArray(value);
4218
5187
  if (!options.textMeasurement?.outlineBounds) return rich ? fitRichText(value, box, size, minimum, richOptions(style)) : fitText(text2, box, size, minimum, textWidthMeasurer(style, options.textMeasurement), textDirection);
4219
5188
  const alignment = explicitAlignment ?? alignmentFor(field);
4220
5189
  const richLayout = rich ? richTextLayouter(value, box, size, richOptions(style), minimum) : void 0;
@@ -4307,12 +5276,12 @@ function composeSlide(input, options = {}) {
4307
5276
  let y = logo ? logo.box.y + logo.box.height + gap : headingTop;
4308
5277
  const headingItems = [];
4309
5278
  for (const field of ["tag", "title", "subtitle"]) {
4310
- if (!slide[field]) continue;
5279
+ if (!slide[field] || Array.isArray(slide[field]) && !annotationText(slide[field])) continue;
4311
5280
  const requested = (field === "title" ? 54 : field === "tag" ? 16 : 25) * scale;
4312
5281
  const maxHeight = Math.max(height * (field === "title" ? 0.26 : field === "subtitle" ? 0.12 : 0.045), minSize * 1.22 + 2 * rasterPadding);
4313
5282
  const box = { x: area.left + padding, y, width: area.right - area.left - padding * 2, height: maxHeight };
4314
- const text2 = fitPlacedText(field, slide[field], String(slide[field]), box, requested, minSize, `${path}.${field}`);
4315
- box.height = Math.min(maxHeight, Math.max(text2.lines.length * text2.lineHeight, text2.placement?.height ?? 0));
5283
+ const text2 = fitPlacedText(field, slide[field], annotationText(slide[field]), box, requested, minSize, `${path}.${field}`);
5284
+ box.height = Math.min(maxHeight, Math.max("richLines" in text2 ? text2.height : text2.lines.length * text2.lineHeight, text2.placement?.height ?? 0));
4316
5285
  if (furniture && box.y + box.height > bodyBottom + 0.01) diagnostics.push({ code: "text-overflow", path: `${path}.${field}`, message: "Repeated furniture leaves too little room for this heading. Change the header/footer or slide design." });
4317
5286
  const item = { path: `${path}.${field}`, field, type: "text", value: slide[field], payload: { text: slide[field] }, box, text: text2, textStyle: styleFor(field, `${path}.${field}`), composition, alignment: alignmentFor(field) };
4318
5287
  headingItems.push(item);
@@ -4377,22 +5346,23 @@ function composeSlide(input, options = {}) {
4377
5346
  return acceptedBox({ x: frame.x + padding2, y: frame.y + padding2, width: frame.width - 2 * padding2, height: frame.height - 2 * padding2 });
4378
5347
  };
4379
5348
  const measureQuote = (node, box, settings) => layoutQuote(node.value, acceptedBox(box), {
4380
- fonts: options.fonts,
5349
+ fontFamilies: options.fontFamilies,
4381
5350
  textMeasurement: options.textMeasurement,
4382
5351
  scale,
4383
5352
  minFontSize: settings.minFontSize,
4384
5353
  path: node.path,
4385
- direction: textDirection
5354
+ direction: textDirection,
5355
+ ...citationMarker ? { citationMarker } : {}
4386
5356
  });
4387
5357
  const measureCode = (node, box, settings) => layoutCode(node.value, acceptedBox(box), {
4388
- fonts: options.fonts,
5358
+ fontFamilies: options.fontFamilies,
4389
5359
  textMeasurement: options.textMeasurement,
4390
5360
  scale,
4391
5361
  minFontSize: settings.minFontSize,
4392
5362
  path: node.path
4393
5363
  });
4394
5364
  const measureMetric = (node, box, settings) => layoutMetric(node.value, acceptedBox(box), {
4395
- fonts: options.fonts,
5365
+ fontFamilies: options.fontFamilies,
4396
5366
  textMeasurement: options.textMeasurement,
4397
5367
  scale,
4398
5368
  minFontSize: settings.minFontSize,
@@ -4402,7 +5372,7 @@ function composeSlide(input, options = {}) {
4402
5372
  direction: textDirection
4403
5373
  });
4404
5374
  const measureTimeline = (node, box, settings) => layoutTimeline(node.value, acceptedBox(box), {
4405
- fonts: options.fonts,
5375
+ fontFamilies: options.fontFamilies,
4406
5376
  textMeasurement: options.textMeasurement,
4407
5377
  scale,
4408
5378
  minFontSize: settings.minFontSize,
@@ -4539,18 +5509,17 @@ function composeSlide(input, options = {}) {
4539
5509
  };
4540
5510
  const placeholders = Array.isArray(layout.placeholders) ? layout.placeholders.filter((p) => !headings.has(p.type)) : [];
4541
5511
  if (slideImage?.replacesContent) {
4542
- const picture = placeholders.findIndex((p) => p.type === "picture");
5512
+ const picture = placeholders.findIndex((p) => p.type === "image");
4543
5513
  if (picture >= 0) placeholders.splice(picture, 1);
4544
5514
  }
4545
5515
  const ownMode = record5(slide.composition).mode;
4546
- const direction = designHint("contentDirection")?.value;
4547
- const directionMode = direction === "vertical" ? "column" : direction === "horizontal" ? "row" : void 0;
4548
- const layoutDirectionMode = layout.slideLayoutDirection === "Vertical" ? "column" : layout.slideLayoutDirection === "Horizontal" ? "row" : "auto";
4549
- const chartHint = designHint("chartPrimary")?.value ?? (typeof layout.contentTypeChartPrimary === "string" ? layout.contentTypeChartPrimary.toLowerCase() : void 0);
5516
+ const direction = hints.contentDirection;
5517
+ const directionMode = direction === "vertical" ? "column" : direction === "horizontal" ? "row" : "auto";
5518
+ const chartHint = hints.chartPrimary;
4550
5519
  const chartSide = chartHint === "left" || chartHint === "right" || chartHint === "top" || chartHint === "bottom" ? chartHint : void 0;
4551
5520
  const chartIndex = pending.findIndex((node) => !node.children && node.field === "chart");
4552
5521
  const chartPrimary = chartSide !== void 0 && !ownMode && !regions.length && chartIndex >= 0 && pending.some((node) => node.children || node.field !== "chart") ? chartSide : void 0;
4553
- const rootSettings = chartPrimary ? { ...composition, mode: chartPrimary === "left" || chartPrimary === "right" ? "row" : "column", columns: void 0, weights: chartPrimary === "left" || chartPrimary === "top" ? [3, 2] : [2, 3] } : { ...composition, mode: composition.mode ?? directionMode ?? layoutDirectionMode };
5522
+ const rootSettings = chartPrimary ? { ...composition, mode: chartPrimary === "left" || chartPrimary === "right" ? "row" : "column", columns: void 0, weights: chartPrimary === "left" || chartPrimary === "top" ? [3, 2] : [2, 3] } : { ...composition, mode: composition.mode ?? directionMode };
4554
5523
  if (chartPrimary) {
4555
5524
  const primary = pending[chartIndex], rest = pending.filter((_, index) => index !== chartIndex);
4556
5525
  const container = { field: "blocks", type: "group", value: rest.map((node) => node.payload), path, payload: {}, children: rest, composition: {}, synthetic: true };
@@ -4595,7 +5564,7 @@ function composeSlide(input, options = {}) {
4595
5564
  } : void 0;
4596
5565
  if (failures.length) throw new OPFCompositionError(failures, explanation);
4597
5566
  diagnostics.push(...slideImageDiagnostics, ...numberingDiagnostics);
4598
- return { width, height, contentBox, items, groups, flows, diagnostics, composition, ...furniture ? { furniture } : {}, ...slideImage ? { slideImage } : {}, ...logo ? { logo } : {}, ...rtl ? { direction: "rtl" } : {}, ...footnotes ? { footnotes } : {}, ...explanation ? { explanation } : {} };
5567
+ return { width, height, contentBox, items, groups, flows, diagnostics, composition, design: hints, ...furniture ? { furniture } : {}, ...slideImage ? { slideImage } : {}, ...logo ? { logo } : {}, ...rtl ? { direction: "rtl" } : {}, ...footnotes ? { footnotes } : {}, ...explanation ? { explanation } : {} };
4599
5568
  }
4600
5569
  function resolveCanvasDimensions(input) {
4601
5570
  const presets = {
@@ -4604,6 +5573,9 @@ function resolveCanvasDimensions(input) {
4604
5573
  standard: [10, 7.5],
4605
5574
  "4:3": [10, 7.5],
4606
5575
  "16:10": [10, 6.25],
5576
+ "1:1": [7.5, 7.5],
5577
+ "4:5": [7.5, 9.375],
5578
+ "9:16": [7.5, 40 / 3],
4607
5579
  letter: [11, 8.5],
4608
5580
  a4: [11.69, 8.27]
4609
5581
  };
@@ -4615,4 +5587,4 @@ function resolveCanvasDimensions(input) {
4615
5587
  return { width, height };
4616
5588
  }
4617
5589
 
4618
- export { CAPTIONABLE_FIELDS, CAPTION_FONT_RATIO, CAPTION_MAX_RATIO, CHART_SERIES_MIN_DIFFERENCE, CHART_SERIES_MIN_LIGHTNESS_STEP, CITATION_MARKER_RAISE, CITATION_MARKER_SCALE, DEFAULT_CHART_LABEL_SEPARATOR, DEFAULT_FONT_SCHEME, DEFAULT_FURNITURE_DATE_FORMAT, DEFAULT_SLIDE_NUMBER_FORMAT, DEFAULT_VARIABLE_DATE_FORMAT, FONT_SIZE_GRID_PER_PX, FOOTNOTE_MAX_RATIO, MAX_COMPOSITION_DEPTH, MAX_NUMBERING_LEVELS, MAX_NUMBERING_VALUE, MAX_ROMAN_VALUE, NUMBERING_STYLES, NUMBERING_SUFFIXES, OPFCompositionError, OPFVariableError, PICTURE_BULLET_SCALE, VARIABLE_KINDS, annotationText, bareIdPattern, captionSettings, catalogIds, chartColorForFill, chartLabelText, chartNumber, chartNumberFixesByCell, chartOptionSupport, chartOptionTarget, chartPaletteForFill, citationMarkerText, coerceVariableValue, collectCitations, colorContrast, composeSlide, datasetDiagnostics, deprecatedCatalogIds, excelNumberFormat, fitList, fitRichText, fitText, formatChartLabelNumber, formatChartLabelPercent, formatDataNumber, formatFurnitureDate, formatListNumber, formatSlideNumber, formatVariableNumber, hasContentVariables, inlineChartData, inlineDatasets, inlineTableData, instantiateForValidation, intrinsicImageSize, isDatasetRef, isRecord, isTemplate, isXYChartType, layoutCaption, layoutCode, layoutFootnotes, layoutFurniture, layoutMetric, layoutQuote, layoutTable, layoutTimeline, listNumbers, listVariables, measureText, measureTextOutline, normalizeHexColor, numberFormatError, numberFormatFromExcel, numberingAtLevel, numberingFindings, numberingStyleDraws, paragraphDirection, paragraphDirectionAt, pathFor, physicalAlignment, placeTextLines, promotedRegionKeys, readingRows, referencesSlide, resolveCanvasDimensions, resolveChartData, resolveChartOptions, resolveColorRef, resolveFontFamilies, resolveFontSchemeReference, resolveLogo, resolveNumbering, resolveScriptFonts, resolveSlideDirection, resolveSocialProfile, resolveTableData, resolveTextStyle, resolveVariables, scriptFontRole, sliceNumberedItems, slideCitations, slideImageShape, snapFontSizeDown, snapFontSizeUp, suggestChartNumberFix, tableCellDisplayValue, tableGrid, tableRowBoundaries, textColorForFill, textWidthMeasurer, unusedDatasets, variableDeclarations, visitContentPayloads, visualReadingOrder, walkCitationRuns, wrapText };
5590
+ export { CAPTIONABLE_FIELDS, CAPTION_FONT_RATIO, CAPTION_MAX_RATIO, CHART_HIGHLIGHT_MUTED_MIN_CONTRAST, CHART_HIGHLIGHT_MUTED_MIX, CHART_SERIES_MIN_DIFFERENCE, CHART_SERIES_MIN_LIGHTNESS_STEP, CITATION_MARKER_RAISE, CITATION_MARKER_SCALE, CODE_HIGHLIGHT_LANGUAGES, CODE_HIGHLIGHT_MAX_LENGTH, CODE_PANEL_BACKGROUND, CODE_PANEL_FOREGROUND, CODE_SYNTAX_MIN_CONTRAST, DARK_BACKGROUND_LUMINANCE, DEFAULT_CHART_LABEL_SEPARATOR, DEFAULT_FONT_SCHEME, DEFAULT_FURNITURE_DATE_FORMAT, DEFAULT_SLIDE_NUMBER_FORMAT, DEFAULT_VARIABLE_DATE_FORMAT, DESIGN_HINT_KEYS, FONT_SIZE_GRID_PER_PX, FOOTNOTE_MAX_RATIO, LAYOUT_BODY_KINDS, MAX_COMPOSITION_DEPTH, MAX_NUMBERING_LEVELS, MAX_NUMBERING_VALUE, MAX_ROMAN_VALUE, METRIC_TREND_MIN_CONTRAST, METRIC_TREND_SHAPES, NUMBERING_STYLES, NUMBERING_SUFFIXES, OPFCompositionError, OPFVariableError, PATTERN_PRESETS, PATTERN_PRESET_ALIASES, PATTERN_TILE_SIZE, PICTURE_BULLET_SCALE, SURFACE_ALT_MIN_CONTRAST, SURFACE_ALT_MIX, TIMELINE_OUTLINE_MIN_CONTRAST, TIMELINE_STATUSES, TIMELINE_TEXT_MIN_CONTRAST, VARIABLE_KINDS, annotationText, bareIdPattern, captionSettings, chartColorForFill, chartHighlightColors, chartHighlightMarks, chartLabelText, chartNumber, chartNumberFixesByCell, chartOptionSupport, chartOptionTarget, chartPaletteForFill, citationMarkerText, codeHighlightBands, codeHighlightColors, codeHighlightLines, codeHighlightSlice, codeLineNumbers, codeLineRuns, codeSyntaxPalette, codeSyntaxPaletteForScheme, coerceVariableValue, collectCitations, colorContrast, composeSlide, datasetDiagnostics, defaultSlideBackground, fitList, fitRichText, fitText, formatChartLabelNumber, formatChartLabelPercent, formatDataNumber, formatFurnitureDate, formatListNumber, formatSlideNumber, formatVariableNumber, fromExcelNumberFormat, hasContentVariables, inlineChartData, inlineDatasets, inlineTableData, instantiateForValidation, intrinsicImageSize, isDarkColor, isDatasetRef, isRecord, isTemplate, isXYChartType, layoutCaption, layoutCode, layoutContent, layoutFootnotes, layoutFurniture, layoutMetric, layoutQuote, layoutTable, layoutTimeline, layoutWatermark, listBuiltinVariables, listNumbers, listVariables, measureText, measureTextOutline, metricTrendColor, metricTrendMark, metricTrendPoints, normalizeHexColor, normalizeLanguageFamily, numberFormatError, numberingAtLevel, numberingFindings, numberingStyleDraws, paragraphDirection, paragraphDirectionAt, pathFor, patternBitmap, patternRuns, physicalAlignment, placeTextLines, promotedRegionKeys, readingRows, referencesSlide, resolveCanvasDimensions, resolveChartData, resolveChartOptions, resolveCodeLanguage, resolveColorRef, resolveColorRoles, resolveDesignHints, resolveFontFamilies, resolveFontSchemeReference, resolveLogo, resolveNumbering, resolvePatternPreset, resolveScriptFonts, resolveSlideDirection, resolveSocialProfile, resolveTableData, resolveTextStyle, resolveVariables, scriptFontRole, sliceNumberedItems, slideCitations, slideImageShape, snapFontSizeDown, snapFontSizeUp, suggestChartNumberFix, surfaceAltColor, tableCellDisplayValue, tableGrid, tableRowBoundaries, textColorForFill, textWidthMeasurer, timelineMarkerShapes, timelineTextColor, toExcelNumberFormat, tokenizeCode, unusedDatasets, variableDeclarations, visitContentPayloads, visualReadingOrder, walkCitationRuns, wrapText };