prographs 0.12.0 → 0.13.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 (269) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/README.md +6 -4
  3. package/dist/AutoGraph-PDPEAIXL.cjs +145 -0
  4. package/dist/GraphType.js +19 -0
  5. package/dist/autograph/chartIndex.js +521 -0
  6. package/dist/autograph/chartModules.js +2 -1
  7. package/dist/autograph/index.cjs +98 -93
  8. package/dist/catalog-DI4XZ46L.cjs +142 -0
  9. package/dist/catalog.js +2 -1
  10. package/dist/charts/biologycharts/BiologySamples.js +59 -0
  11. package/dist/charts/biologycharts/PunnettSquare.js +342 -0
  12. package/dist/charts/biologycharts/biologyEnums.js +22 -1
  13. package/dist/charts/biologycharts/index.js +5 -3
  14. package/dist/charts/doecharts/DoeSamples.js +78 -0
  15. package/dist/charts/doecharts/SipocDiagram.js +453 -0
  16. package/dist/charts/doecharts/index.js +4 -2
  17. package/dist/charts/fieldcharts/SpeciesAccumulationCurve.js +350 -0
  18. package/dist/charts/fieldcharts/fieldEnums.js +8 -1
  19. package/dist/charts/fieldcharts/index.js +5 -3
  20. package/dist/charts/signals/AntennaPatternChart.js +492 -0
  21. package/dist/charts/signals/SignalSamples.js +17 -0
  22. package/dist/charts/signals/index.js +5 -3
  23. package/dist/charts/softwarediagrams/ComponentDiagram.js +504 -0
  24. package/dist/charts/softwarediagrams/DeploymentDiagram.js +419 -0
  25. package/dist/charts/softwarediagrams/SoftwareSamples.js +283 -1
  26. package/dist/charts/softwarediagrams/index.js +7 -3
  27. package/dist/charts/softwarediagrams/softwareEnums.js +45 -1
  28. package/dist/charts/sportscharts/PowerDurationCurve.js +301 -0
  29. package/dist/charts/sportscharts/SportsSamples.js +102 -0
  30. package/dist/charts/sportscharts/TrainingLoadChart.js +325 -0
  31. package/dist/charts/sportscharts/index.js +6 -2
  32. package/dist/charts/strategycharts/BassDiffusionChart.js +362 -0
  33. package/dist/charts/strategycharts/BassModel.js +96 -0
  34. package/dist/charts/strategycharts/BurnRunwayChart.js +284 -0
  35. package/dist/charts/strategycharts/CapTableChart.js +366 -0
  36. package/dist/charts/strategycharts/KanbanBoard.js +324 -0
  37. package/dist/charts/strategycharts/OkrTree.js +339 -0
  38. package/dist/charts/strategycharts/StrategyPane.js +27 -0
  39. package/dist/charts/strategycharts/StrategySamples.js +251 -0
  40. package/dist/charts/strategycharts/index.js +15 -3
  41. package/dist/charts/threefields/BsfcMap3DChart.js +231 -0
  42. package/dist/charts/threefields/CompressorMap3DChart.js +217 -0
  43. package/dist/charts/threefields/FieldGrid.js +50 -0
  44. package/dist/charts/threefields/LossLandscape3DChart.js +201 -0
  45. package/dist/charts/threefields/MapSheet.js +77 -0
  46. package/dist/charts/threefields/TerrainRoute3DChart.js +201 -0
  47. package/dist/charts/threefields/TerrainRouteMath.js +40 -0
  48. package/dist/charts/threefields/ThreeFieldBase.js +117 -0
  49. package/dist/charts/threefields/ThreeFieldsSamples.js +80 -0
  50. package/dist/charts/threefields/WaferMap3DChart.js +218 -0
  51. package/dist/charts/threefields/index.js +19 -0
  52. package/dist/charts/threesurfaces/index.js +2 -2
  53. package/dist/charts/tradingcharts/KeltnerChannelChart.js +171 -0
  54. package/dist/charts/tradingcharts/TradingMath.js +20 -0
  55. package/dist/charts/tradingcharts/index.js +4 -2
  56. package/dist/{chunk-ZL6XDXMK.cjs → chunk-26PSLEP4.cjs} +8 -8
  57. package/dist/{chunk-W3US6EFP.cjs → chunk-2BO5DZUP.cjs} +12 -12
  58. package/dist/{chunk-5DP7OUSE.cjs → chunk-2GG5YYSC.cjs} +6 -6
  59. package/dist/{chunk-7FG4JSVO.cjs → chunk-2GL2VNJU.cjs} +253 -33
  60. package/dist/{chunk-LCWMRCLF.cjs → chunk-2PYOI7OY.cjs} +21 -21
  61. package/dist/{chunk-JFWJAEBD.cjs → chunk-3U4MCSKI.cjs} +4 -4
  62. package/dist/{chunk-CUPLHZRR.cjs → chunk-3ZMM3FSK.cjs} +4 -4
  63. package/dist/{chunk-L2AV62DP.cjs → chunk-4767WQJ7.cjs} +6 -6
  64. package/dist/{chunk-DA2EYIIP.cjs → chunk-4E7FSSBF.cjs} +1210 -168
  65. package/dist/{chunk-VS5LQEZB.cjs → chunk-526STI2S.cjs} +5 -5
  66. package/dist/{chunk-RXIMEK6C.cjs → chunk-55767YPI.cjs} +20 -20
  67. package/dist/{chunk-JXLSKIUV.cjs → chunk-5FBQOMMT.cjs} +26 -26
  68. package/dist/{chunk-27PZV5BR.cjs → chunk-5N4Z7MTS.cjs} +4 -4
  69. package/dist/{chunk-KEWCUIQA.cjs → chunk-5WEV6YWA.cjs} +22 -22
  70. package/dist/chunk-5XOVVC5X.cjs +3281 -0
  71. package/dist/{chunk-HK5J7Q2W.cjs → chunk-6HLXVWXU.cjs} +9 -9
  72. package/dist/{chunk-7JG47RW4.cjs → chunk-6LQT4WJ5.cjs} +25 -25
  73. package/dist/{chunk-OCVTI6X4.cjs → chunk-6YTWOUFD.cjs} +329 -36
  74. package/dist/{chunk-W7IQCAVN.cjs → chunk-7F6W6HKL.cjs} +11 -11
  75. package/dist/{chunk-F2DCJXDM.cjs → chunk-7L6KYU5A.cjs} +21 -21
  76. package/dist/{chunk-GTGR6LPR.cjs → chunk-A4GIN4FE.cjs} +17 -17
  77. package/dist/{chunk-B2CETSR6.cjs → chunk-A4US7SA7.cjs} +5 -5
  78. package/dist/{chunk-3DIF2YYW.cjs → chunk-AOXPBLPW.cjs} +10 -10
  79. package/dist/{chunk-7TTR4UF5.cjs → chunk-ATI45Z4M.cjs} +2 -2
  80. package/dist/{chunk-5BFCIX2V.cjs → chunk-CPPMO4IQ.cjs} +434 -148
  81. package/dist/{chunk-AYZZQ6AC.cjs → chunk-CZ5KGF6Q.cjs} +9 -9
  82. package/dist/{chunk-7THJ3ZBK.cjs → chunk-D4I35MCE.cjs} +2 -2
  83. package/dist/{chunk-MCPPFRLN.cjs → chunk-DCGAAN3Z.cjs} +2 -2
  84. package/dist/{chunk-VABL6CVX.cjs → chunk-DEY36N37.cjs} +21 -21
  85. package/dist/{chunk-RNCKGJCC.cjs → chunk-DXHXD3DK.cjs} +3 -3
  86. package/dist/{chunk-A56ZGMVZ.cjs → chunk-E7B45DBZ.cjs} +11 -11
  87. package/dist/{chunk-DOR6L4MT.cjs → chunk-EJC6EAC5.cjs} +18 -18
  88. package/dist/{chunk-UPGNM7MA.cjs → chunk-EULJOOMA.cjs} +11 -11
  89. package/dist/{chunk-G4AZL4GO.cjs → chunk-EYM6LEIF.cjs} +474 -70
  90. package/dist/{chunk-NJ4X6XGV.cjs → chunk-EZTYX2GH.cjs} +5 -5
  91. package/dist/chunk-FDD4UP73.cjs +521 -0
  92. package/dist/{chunk-WJ3VH2Q4.cjs → chunk-GEAIGM3J.cjs} +110 -615
  93. package/dist/{chunk-P3SBHF43.cjs → chunk-GRUYVXTS.cjs} +2 -2
  94. package/dist/{chunk-NX4Z5LMS.cjs → chunk-H3SZXND5.cjs} +5 -5
  95. package/dist/{chunk-EE4S4TOE.cjs → chunk-HS45TOFJ.cjs} +21 -21
  96. package/dist/chunk-INGOG6OV.cjs +899 -0
  97. package/dist/{chunk-UDKA6DGT.cjs → chunk-J3CDXZHF.cjs} +4 -4
  98. package/dist/{chunk-YO6G7TKI.cjs → chunk-JAU5ADEU.cjs} +11 -11
  99. package/dist/{chunk-22LBK4GA.cjs → chunk-JQEBSHX3.cjs} +4 -4
  100. package/dist/{chunk-RXX3U7VQ.cjs → chunk-KLXGLMFU.cjs} +10 -10
  101. package/dist/chunk-KVOX36J3.cjs +327 -0
  102. package/dist/chunk-L6BGNHFL.cjs +139 -0
  103. package/dist/{chunk-GMER35L3.cjs → chunk-L7TB7PU5.cjs} +20 -20
  104. package/dist/{chunk-AFXYNBL2.cjs → chunk-LBTRYEM2.cjs} +4 -4
  105. package/dist/{chunk-WYYCKIOD.cjs → chunk-LLULNJSP.cjs} +11 -11
  106. package/dist/{chunk-J27XOSLP.cjs → chunk-LSO46AFV.cjs} +8 -8
  107. package/dist/{chunk-5XJO45ES.cjs → chunk-LZ2KJ7ZX.cjs} +11 -11
  108. package/dist/chunk-M4IQ5LIZ.cjs +422 -0
  109. package/dist/{chunk-Y2KIUKJF.cjs → chunk-MPDHDKYZ.cjs} +11 -11
  110. package/dist/{chunk-4EMPKRZU.cjs → chunk-MRQ42ZJE.cjs} +3 -3
  111. package/dist/{chunk-EU5D2MF4.cjs → chunk-MYV4KZWP.cjs} +9 -9
  112. package/dist/{chunk-XD7KN4UN.cjs → chunk-MZXVLC24.cjs} +6 -6
  113. package/dist/{chunk-PPSONARU.cjs → chunk-NLBVDFIR.cjs} +41 -2
  114. package/dist/{chunk-L3PEGMGM.cjs → chunk-NY3TBZY4.cjs} +33 -33
  115. package/dist/{chunk-6YNYXXB6.cjs → chunk-OGVVSFAR.cjs} +3 -3
  116. package/dist/{chunk-MLV7QLB6.cjs → chunk-OMTQIQMN.cjs} +6 -6
  117. package/dist/{chunk-BEEOSNK7.cjs → chunk-PEJJ6TXJ.cjs} +15 -144
  118. package/dist/{chunk-SOKOWUF5.cjs → chunk-PPGWHIU7.cjs} +2 -2
  119. package/dist/{chunk-IELWOM2J.cjs → chunk-PPO6SDAN.cjs} +6 -6
  120. package/dist/{chunk-6JTZZCSL.cjs → chunk-PUMKX5F2.cjs} +3 -3
  121. package/dist/{chunk-RFOXFY2U.cjs → chunk-PXBYWCNB.cjs} +190 -799
  122. package/dist/{chunk-3BYXOISI.cjs → chunk-Q3HB3IX6.cjs} +4 -4
  123. package/dist/{chunk-RXCOVONX.cjs → chunk-RBMUOIXE.cjs} +289 -34
  124. package/dist/{chunk-MSBNHCSE.cjs → chunk-RJHGCUUD.cjs} +6 -6
  125. package/dist/{chunk-I6VG7F6Z.cjs → chunk-RSONDMYW.cjs} +708 -141
  126. package/dist/{chunk-GZDNPHMT.cjs → chunk-SHMPFCUE.cjs} +19 -19
  127. package/dist/{chunk-ZIBVCOW6.cjs → chunk-SN4FCXFC.cjs} +19 -19
  128. package/dist/{chunk-7KM52NMN.cjs → chunk-SN5T7WYO.cjs} +2 -2
  129. package/dist/{chunk-7MSZR65Z.cjs → chunk-SQJZGVDR.cjs} +7 -7
  130. package/dist/chunk-SYABFMD7.cjs +633 -0
  131. package/dist/{chunk-2RRFEYFH.cjs → chunk-TICB3MAC.cjs} +16 -16
  132. package/dist/{chunk-AOOKHUV5.cjs → chunk-U7Z7XYR2.cjs} +5 -5
  133. package/dist/{chunk-JEWQAXVG.cjs → chunk-UA2THQFV.cjs} +6 -6
  134. package/dist/{chunk-LHZPAHU3.cjs → chunk-VIK4L2YF.cjs} +112 -521
  135. package/dist/{chunk-4YWMAQ4J.cjs → chunk-VM2Y6BDY.cjs} +4 -4
  136. package/dist/{chunk-IRRKE2ZE.cjs → chunk-VMS3KWYI.cjs} +21 -21
  137. package/dist/{chunk-4SLARW6F.cjs → chunk-VU5NUD46.cjs} +17 -17
  138. package/dist/{chunk-XHY6TVYG.cjs → chunk-VV5CVOF7.cjs} +13 -13
  139. package/dist/{chunk-CCIBPGPZ.cjs → chunk-VYSAWPSS.cjs} +57 -57
  140. package/dist/{chunk-TTNEMQ2A.cjs → chunk-W7YRWEWQ.cjs} +22 -22
  141. package/dist/{chunk-C7MUOGEW.cjs → chunk-X7R5SY62.cjs} +6 -6
  142. package/dist/{chunk-ILR5KBMB.cjs → chunk-XOK3KTSS.cjs} +6 -6
  143. package/dist/{chunk-2CZM2I3T.cjs → chunk-XUIX45VU.cjs} +19 -19
  144. package/dist/{chunk-TGRMPS3A.cjs → chunk-XWH46PVJ.cjs} +165 -43
  145. package/dist/{chunk-WQYXXECR.cjs → chunk-Y5XVMK3K.cjs} +6 -6
  146. package/dist/{chunk-AK4TX2WG.cjs → chunk-YCNKEDTG.cjs} +13 -13
  147. package/dist/{chunk-PJJB24DU.cjs → chunk-YEF7SE3X.cjs} +20 -20
  148. package/dist/{chunk-RVLV4XW6.cjs → chunk-YMTVPMU3.cjs} +22 -22
  149. package/dist/data/index.cjs +2 -2
  150. package/dist/entries/autograph-lazy.cjs +2 -2
  151. package/dist/entries/charts/acoustictransport.cjs +3 -3
  152. package/dist/entries/charts/analysischarts.cjs +3 -3
  153. package/dist/entries/charts/astrocharts.cjs +3 -3
  154. package/dist/entries/charts/bars.cjs +3 -3
  155. package/dist/entries/charts/bayesiancharts.cjs +3 -3
  156. package/dist/entries/charts/biocharts.cjs +3 -3
  157. package/dist/entries/charts/biologycharts.cjs +11 -3
  158. package/dist/entries/charts/biologycharts.d.ts +1 -1
  159. package/dist/entries/charts/biologycharts.js +3 -2
  160. package/dist/entries/charts/business.cjs +3 -3
  161. package/dist/entries/charts/carecharts.cjs +3 -3
  162. package/dist/entries/charts/chemistrycharts.cjs +3 -3
  163. package/dist/entries/charts/civicscharts.cjs +3 -3
  164. package/dist/entries/charts/clinicalcharts.cjs +3 -3
  165. package/dist/entries/charts/comparison.cjs +3 -3
  166. package/dist/entries/charts/demography.cjs +3 -3
  167. package/dist/entries/charts/density.cjs +3 -3
  168. package/dist/entries/charts/diagrams.cjs +3 -3
  169. package/dist/entries/charts/distribution.cjs +3 -3
  170. package/dist/entries/charts/doecharts.cjs +13 -3
  171. package/dist/entries/charts/doecharts.d.ts +1 -1
  172. package/dist/entries/charts/doecharts.js +2 -1
  173. package/dist/entries/charts/earthscience.cjs +3 -3
  174. package/dist/entries/charts/economicscharts.cjs +3 -3
  175. package/dist/entries/charts/energycharts.cjs +3 -3
  176. package/dist/entries/charts/engineering.cjs +3 -3
  177. package/dist/entries/charts/fieldcharts.cjs +7 -3
  178. package/dist/entries/charts/fieldcharts.d.ts +1 -1
  179. package/dist/entries/charts/fieldcharts.js +3 -2
  180. package/dist/entries/charts/financial.cjs +3 -3
  181. package/dist/entries/charts/flow.cjs +3 -3
  182. package/dist/entries/charts/frameworks.cjs +3 -3
  183. package/dist/entries/charts/genomics.cjs +3 -3
  184. package/dist/entries/charts/geoflows.cjs +3 -3
  185. package/dist/entries/charts/geomaps.cjs +3 -3
  186. package/dist/entries/charts/geosciencecharts.cjs +3 -3
  187. package/dist/entries/charts/hierarchy.cjs +3 -3
  188. package/dist/entries/charts/indicators.cjs +3 -3
  189. package/dist/entries/charts/inferencecharts.cjs +3 -3
  190. package/dist/entries/charts/layoutcharts.cjs +3 -3
  191. package/dist/entries/charts/lifescience.cjs +4 -4
  192. package/dist/entries/charts/linesareas.cjs +3 -3
  193. package/dist/entries/charts/logisticscharts.cjs +3 -3
  194. package/dist/entries/charts/machinecharts.cjs +7 -3
  195. package/dist/entries/charts/machinecharts.d.ts +1 -1
  196. package/dist/entries/charts/machinecharts.js +2 -1
  197. package/dist/entries/charts/massive.cjs +3 -3
  198. package/dist/entries/charts/mathematical.cjs +3 -3
  199. package/dist/entries/charts/matrix.cjs +3 -3
  200. package/dist/entries/charts/medicalcharts.cjs +4 -4
  201. package/dist/entries/charts/mlcharts.cjs +4 -4
  202. package/dist/entries/charts/modelcharts.cjs +6 -5
  203. package/dist/entries/charts/multivariate.cjs +3 -3
  204. package/dist/entries/charts/musiccharts.cjs +3 -3
  205. package/dist/entries/charts/network.cjs +3 -3
  206. package/dist/entries/charts/physicscharts.cjs +3 -3
  207. package/dist/entries/charts/pictorial.cjs +4 -4
  208. package/dist/entries/charts/portfoliocharts.cjs +3 -3
  209. package/dist/entries/charts/productcharts.cjs +3 -3
  210. package/dist/entries/charts/proportion.cjs +3 -3
  211. package/dist/entries/charts/qualitycharts.cjs +3 -3
  212. package/dist/entries/charts/radial.cjs +3 -3
  213. package/dist/entries/charts/reliabilitycharts.cjs +5 -3
  214. package/dist/entries/charts/scatter.cjs +3 -3
  215. package/dist/entries/charts/scientific.cjs +3 -3
  216. package/dist/entries/charts/seriescharts.cjs +3 -3
  217. package/dist/entries/charts/signals.cjs +7 -3
  218. package/dist/entries/charts/signals.d.ts +1 -1
  219. package/dist/entries/charts/signals.js +2 -1
  220. package/dist/entries/charts/softwarediagrams.cjs +21 -3
  221. package/dist/entries/charts/softwarediagrams.d.ts +1 -1
  222. package/dist/entries/charts/softwarediagrams.js +4 -2
  223. package/dist/entries/charts/sportscharts.cjs +13 -3
  224. package/dist/entries/charts/sportscharts.d.ts +1 -1
  225. package/dist/entries/charts/sportscharts.js +3 -1
  226. package/dist/entries/charts/statistics.cjs +6 -6
  227. package/dist/entries/charts/strategycharts.cjs +30 -3
  228. package/dist/entries/charts/strategycharts.d.ts +1 -1
  229. package/dist/entries/charts/strategycharts.js +6 -1
  230. package/dist/entries/charts/structure.cjs +3 -3
  231. package/dist/entries/charts/surveycharts.cjs +3 -3
  232. package/dist/entries/charts/systemscharts.cjs +3 -3
  233. package/dist/entries/charts/textcharts.cjs +5 -5
  234. package/dist/entries/charts/thematicmaps.cjs +4 -4
  235. package/dist/entries/charts/threebars.cjs +3 -3
  236. package/dist/entries/charts/threefields.cjs +53 -0
  237. package/dist/entries/charts/threefields.d.ts +1 -0
  238. package/dist/entries/charts/threefields.js +6 -0
  239. package/dist/entries/charts/threeglobe.cjs +3 -3
  240. package/dist/entries/charts/threenetwork.cjs +3 -3
  241. package/dist/entries/charts/threestrata.cjs +3 -3
  242. package/dist/entries/charts/threesurfaces.cjs +7 -3
  243. package/dist/entries/charts/threesurfaces.d.ts +1 -1
  244. package/dist/entries/charts/threesurfaces.js +2 -1
  245. package/dist/entries/charts/threevolume.cjs +4 -4
  246. package/dist/entries/charts/timeline.cjs +3 -3
  247. package/dist/entries/charts/tracecharts.cjs +3 -3
  248. package/dist/entries/charts/trackscharts.cjs +3 -3
  249. package/dist/entries/charts/tradingcharts.cjs +6 -4
  250. package/dist/entries/charts/tradingcharts.d.ts +1 -1
  251. package/dist/entries/charts/tradingcharts.js +2 -1
  252. package/dist/entries/three.cjs +60 -20
  253. package/dist/entries/three.d.ts +1 -1
  254. package/dist/entries/three.js +7 -1
  255. package/dist/index.cjs +258 -97
  256. package/dist/index.d.cts +1953 -10
  257. package/dist/index.d.ts +1953 -10
  258. package/dist/index.js +26 -5
  259. package/dist/page/index.cjs +2 -2
  260. package/dist/react/components.js +58 -1
  261. package/dist/react/index.cjs +135 -92
  262. package/dist/react/index.d.ts +1 -1
  263. package/dist/react/index.js +2 -2
  264. package/package.json +1 -1
  265. package/dist/AutoGraph-XLBJQDRB.cjs +0 -140
  266. package/dist/catalog-O7XGDD2H.cjs +0 -137
  267. package/dist/chunk-77K2HTRC.cjs +0 -3220
  268. package/dist/chunk-XEK47TVD.cjs +0 -323
  269. /package/dist/{chunk-UMEKIIHJ.cjs → chunk-LNWTC72Y.cjs} +0 -0
@@ -1,8 +1,11 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7; var _class8; var _class9; var _class10; var _class11;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7; var _class8; var _class9; var _class10; var _class11; var _class12; var _class13; var _class14; var _class15; var _class16;
2
2
 
3
3
  var _chunkQ5A2TY2Acjs = require('./chunk-Q5A2TY2A.cjs');
4
4
 
5
5
 
6
+ var _chunkNEXADWQScjs = require('./chunk-NEXADWQS.cjs');
7
+
8
+
6
9
  var _chunkXX2YTCORcjs = require('./chunk-XX2YTCOR.cjs');
7
10
 
8
11
 
@@ -12,7 +15,7 @@ var _chunkEEF5WRRZcjs = require('./chunk-EEF5WRRZ.cjs');
12
15
  var _chunkPY4R3IFFcjs = require('./chunk-PY4R3IFF.cjs');
13
16
 
14
17
 
15
- var _chunkUMEKIIHJcjs = require('./chunk-UMEKIIHJ.cjs');
18
+ var _chunkLNWTC72Ycjs = require('./chunk-LNWTC72Y.cjs');
16
19
 
17
20
  // src/charts/strategycharts/KanoCurve.ts
18
21
  var KanoCategory = /* @__PURE__ */ ((KanoCategory2) => {
@@ -56,69 +59,87 @@ var KanoCurve = class {
56
59
  }
57
60
  };
58
61
 
59
- // src/charts/strategycharts/StrategyNotes.ts
60
- var SIZES = [11, 10, 9];
61
- var DOT = 3;
62
- var INDENT = 10;
63
- var CARD_PAD = 4;
64
- var TIP_WIDTH = 320;
65
- var StrategyNotes = class _StrategyNotes {
66
- static plan(boxes, style) {
67
- let blocks = [];
68
- for (const size of SIZES) {
69
- const filled = boxes.map((box) => _StrategyNotes.#fill(box, size, style));
70
- blocks = filled.flatMap((fill) => fill.blocks);
71
- if (filled.every((fill) => fill.whole)) break;
72
- }
73
- return blocks;
74
- }
75
- static #fill(box, size, style) {
76
- const { notes } = box, lead = Math.round(size * 1.25), pad = style === "card" ? CARD_PAD : 0, gap = style === "bullet" ? 2 : 3;
77
- const indent = style === "bullet" ? INDENT : pad, width = box.width - indent - pad;
78
- if (width < size * 2 || box.height < lead) return { blocks: [], whole: !notes.length };
79
- const wrapped = notes.map((note) => _chunkQ5A2TY2Acjs.FrameworkText.wrap(note.text, width, size));
80
- const tall = (lines) => lines.length * lead + pad;
81
- const cost = (count) => wrapped.slice(0, count).reduce((sum, lines) => sum + tall(lines) + gap, 0);
82
- let shown = notes.length;
83
- if (cost(shown) - gap > box.height) {
84
- shown--;
85
- while (shown > 0 && cost(shown) + lead > box.height) shown--;
62
+ // src/charts/strategycharts/BassDiffusionChart.ts
63
+ var _d3 = require('d3');
64
+
65
+ // src/charts/strategycharts/BassModel.ts
66
+ var LEAST = 3;
67
+ var FLAT = 1e-6;
68
+ var positive = (value) => Number.isFinite(value) && value > 0;
69
+ var BassModel = class _BassModel {
70
+ /** Periods 1 to `count` of the model. */
71
+ static run({ p, q, m }, count2) {
72
+ const periods = [];
73
+ let adopted = 0;
74
+ for (let t = 1; t <= count2; t++) {
75
+ const left = Math.max(0, m - adopted), innovators = Math.min(left, p * left), imitators = Math.min(left - innovators, m > 0 ? q * (adopted / m) * left : 0);
76
+ adopted += innovators + imitators;
77
+ periods.push({ t, innovators, imitators, adopters: innovators + imitators, cumulative: adopted });
86
78
  }
87
- let cut = false;
88
- if (shown === 0 && notes.length) {
89
- const rows = Math.floor((box.height - pad - (notes.length > 1 ? lead + gap : 0)) / lead);
90
- if (rows >= 1) {
91
- cut = wrapped[0].length > rows;
92
- wrapped[0] = _chunkQ5A2TY2Acjs.FrameworkText.clamp(wrapped[0], rows, width, size);
93
- shown = 1;
79
+ return periods;
80
+ }
81
+ /**
82
+ * Bass's own estimate: least squares of each period's adopters on the total adopted before it and that total squared,
83
+ * solved for p, q and m. Null with fewer than three periods, or when the fit is not a diffusion: no positive
84
+ * coefficients, or a market smaller than what has already adopted.
85
+ */
86
+ static fit(adopters) {
87
+ if (adopters.length < LEAST) return null;
88
+ const total = adopters.reduce((sum5, value) => sum5 + value, 0);
89
+ if (!positive(total)) return null;
90
+ let before = 0;
91
+ const rows = adopters.map((value) => {
92
+ const x = before / total;
93
+ before += value;
94
+ return [1, x, x * x, value];
95
+ });
96
+ const normal = [0, 1, 2].map((i) => [...[0, 1, 2].map((j) => rows.reduce((sum5, row) => sum5 + row[i] * row[j], 0)), rows.reduce((sum5, row) => sum5 + row[i] * row[3], 0)]);
97
+ const solved = _BassModel.#solve(normal);
98
+ if (!solved) return null;
99
+ const a = solved[0], b = solved[1] / total, c = solved[2] / (total * total), root = b * b - 4 * a * c;
100
+ if (!(solved[2] < -FLAT * Math.abs(a)) || !(a > 0) || root < 0) return null;
101
+ const m = (-b - Math.sqrt(root)) / (2 * c), p = a / m, q = -c * m;
102
+ return positive(m) && positive(p) && positive(q) && p < 1 && m >= total ? { p, q, m } : null;
103
+ }
104
+ /** Gaussian elimination with partial pivoting on an augmented matrix. Null when the rows are not independent. */
105
+ static #solve(matrix) {
106
+ const size = matrix.length;
107
+ for (let column = 0; column < size; column++) {
108
+ let pivot = column;
109
+ for (let row = column + 1; row < size; row++) if (Math.abs(matrix[row][column]) > Math.abs(matrix[pivot][column])) pivot = row;
110
+ if (Math.abs(matrix[pivot][column]) < 1e-12) return null;
111
+ [matrix[column], matrix[pivot]] = [matrix[pivot], matrix[column]];
112
+ for (let row = 0; row < size; row++) {
113
+ if (row === column) continue;
114
+ const factor = matrix[row][column] / matrix[column][column];
115
+ for (let k = column; k <= size; k++) matrix[row][k] -= factor * matrix[column][k];
94
116
  }
95
117
  }
96
- let top = box.y;
97
- const place = (note, hidden2, lines, key) => {
98
- const height = note ? tall(lines) : lead, inset = note ? pad / 2 : 0;
99
- const block = { key, box, note, hidden: hidden2, lines, x: box.x + (note ? indent : 0), y: top + inset + size - 1, lead, left: box.x, top, width: box.width, height, size };
100
- top += height + gap;
101
- return block;
102
- };
103
- const blocks = notes.slice(0, shown).map((note, i) => place(note, [], wrapped[i], `${box.key}:${i}`));
104
- const hidden = notes.slice(shown);
105
- if (hidden.length && top + lead <= box.y + box.height + 0.5) blocks.push(place(null, hidden, [`+${hidden.length} more`], `${box.key}:more`));
106
- return { blocks, whole: !hidden.length && !cut };
118
+ return matrix.map((row, i) => row[size] / row[i]);
107
119
  }
108
- static draw(ctx, name, blocks, style) {
109
- const items = ctx.marks(name, "g", blocks, (block) => block.key), tint = (block) => _nullishCoalesce(_optionalChain([block, 'access', _5 => _5.note, 'optionalAccess', _6 => _6.color]), () => ( block.box.color));
110
- ctx.hover(items, (block) => {
111
- if (block.note) return _chunkQ5A2TY2Acjs.FrameworkText.tip(block.note.text, _nullishCoalesce(block.note.rows, () => ( [])), tint(block));
112
- return { title: `${block.hidden.length} more`, color: block.box.color, rows: block.hidden.flatMap((note) => _chunkQ5A2TY2Acjs.FrameworkText.wrap(note.text, TIP_WIDTH, 12).map((line6) => [line6, ""])) };
113
- });
114
- const carded = (block) => style === "card" && !!block.note;
115
- const backs = items.selectAll(":scope > rect").data((block) => [block]).join("rect").attr("rx", 3).attr("fill", (block) => carded(block) ? tint(block) : "transparent").attr("fill-opacity", (block) => carded(block) ? 0.22 : null);
116
- ctx.set(backs, { x: (block) => block.left, y: (block) => block.top, width: (block) => block.width, height: (block) => block.height });
117
- const dots = items.selectAll("circle").data((block) => style === "bullet" && block.note ? [block] : []).join("circle").attr("r", DOT).attr("fill", tint).attr("stroke", ctx.theme.surface).attr("stroke-width", 2);
118
- ctx.set(dots, { cx: (block) => block.left + DOT + 1, cy: (block) => block.top + block.lead / 2 });
119
- const body = ctx.text(items.selectAll("text").data((block) => [block]).join("text"), 11, "ink").attr("font-size", (block) => block.size).attr("fill", (block) => block.note ? ctx.theme.ink : ctx.theme.inkSecondary).attr("pointer-events", "none");
120
- _chunkQ5A2TY2Acjs.FrameworkText.write(ctx, body);
121
- return items;
120
+ /** The market that makes the model with `p` and `q` reach `total` adopters by the end of period `count`. */
121
+ static market(p, q, total, count2) {
122
+ const share = _nullishCoalesce(_optionalChain([_BassModel, 'access', _5 => _5.run, 'call', _6 => _6({ p, q, m: 1 }, count2), 'access', _7 => _7.at, 'call', _8 => _8(-1), 'optionalAccess', _9 => _9.cumulative]), () => ( 0));
123
+ return share > 0 ? total / share : total;
124
+ }
125
+ /** The period in which the model's new adopters peak, or null when it has no periods. */
126
+ static peak(periods) {
127
+ return periods.reduce((best, period) => best && best.adopters >= period.adopters ? best : period, null);
128
+ }
129
+ };
130
+
131
+ // src/charts/strategycharts/StrategyPane.ts
132
+ var StrategyPane = class {
133
+ static axis(ctx, name, scale, count2, format) {
134
+ const ticks = scale.ticks(count2);
135
+ const grid = ctx.marks(`axis-${name}-grid`, "line", ticks, (tick) => tick).attr("stroke", (tick) => tick === 0 ? ctx.theme.axis : ctx.theme.grid).attr("stroke-width", 1);
136
+ ctx.set(grid, { x1: 0, x2: ctx.plot.width, y1: (tick) => scale(tick), y2: (tick) => scale(tick) });
137
+ const labels = ctx.text(ctx.marks(`axis-${name}-ticks`, "text", ticks, (tick) => tick)).attr("dy", "0.32em").attr("text-anchor", "end").text(format);
138
+ ctx.set(labels, { x: -3, y: (tick) => scale(tick) });
139
+ }
140
+ /** Short figures for pane ticks and notes: 261K, 2.1M. */
141
+ static compact(value) {
142
+ return Intl.NumberFormat("en", { notation: "compact", maximumFractionDigits: 1 }).format(value);
122
143
  }
123
144
  };
124
145
 
@@ -262,20 +283,51 @@ var METHODS = [
262
283
  ];
263
284
  var PEOPLE = ["Mira V.", "Tobias R.", "Ines H.", "Kofi A.", "Lena B.", "Arun S.", "Yuki M.", "Dara Q.", "Paulo R.", "Greta O.", "Sami N.", "Noor F.", "Elan W.", "Cora L."];
264
285
  var TEAMS = ["Sales", "Product", "Operations"];
286
+ var ROUNDS = [
287
+ ["Founding", []],
288
+ ["Seed", [["Angel investors", 0.05], ["Halden Seed Fund", 0.14]]],
289
+ ["Series A", [["Northquill Ventures", 0.2], ["Halden Seed Fund", 0.03], ["Employee pool", 0.06]]],
290
+ ["Series B", [["Pellmoor Capital", 0.15], ["Northquill Ventures", 0.03], ["Employee pool", 0.03]]]
291
+ ];
292
+ var STAGES = [["Backlog", null], ["Ready", 4], ["In progress", 3], ["Review", 2], ["Done", null]];
293
+ var CARDS = [
294
+ ["Gift card balance", 0, "Checkout", "Feature"],
295
+ ["Search by ingredient", 0, "Search", "Feature"],
296
+ ["Archive old orders", 0, "Platform", "Chore"],
297
+ ["Split shipments", 0, "Checkout", "Feature"],
298
+ ["Retry failed payments", 1, "Checkout", "Bug"],
299
+ ["Typo-tolerant search", 1, "Search", "Feature"],
300
+ ["Rotate signing keys", 1, "Platform", "Chore"],
301
+ ["Saved carts sync", 2, "Checkout", "Feature"],
302
+ ["Slow results on mobile", 2, "Search", "Bug"],
303
+ ["Move queues to new cluster", 2, "Platform", "Chore"],
304
+ ["Address lookup", 2, "Checkout", "Feature"],
305
+ ["Tax rounding error", 3, "Checkout", "Bug"],
306
+ ["Filter by dietary need", 3, "Search", "Feature"],
307
+ ["One-page checkout", 4, "Checkout", "Feature"],
308
+ ["Synonym dictionary", 4, "Search", "Feature"],
309
+ ["Upgrade database", 4, "Platform", "Chore"],
310
+ ["Empty results page", 4, "Search", "Bug"]
311
+ ];
312
+ var OBJECTIVES = [
313
+ ["Make setup quick for new teams", [["Median setup time under 10 minutes", 72, 0.8], ["Activation rate from 41% to 55%", 48, 0.6], ["Halve setup support tickets", 85, 0.9]]],
314
+ ["Earn the trust of larger customers", [["Pass the security audit", 90, 0.9], ["Uptime of 99.95% for the quarter", 64, 0.7], ["Sign 6 customers over 500 seats", 33, 0.3], ["Launch single sign-on", 55, 0.5]]],
315
+ ["Grow revenue from existing accounts", [["Net revenue retention of 112%", 40, 0.5], ["Launch usage-based pricing", 20, 0.3], ["Expansion pipeline of 1.8M", 68, 0.7]]]
316
+ ];
265
317
  var StrategySamples = class {
266
318
  /** `{ technology, position, years }`: place on the cycle from 0 to 100, and years to the plateau or the word Obsolete. */
267
319
  static hypeCycle(seed = 1) {
268
- const { u } = _chunkUMEKIIHJcjs.SampleData.rng(seed);
320
+ const { u } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
269
321
  return TECHNOLOGIES.map(([technology, position, years]) => ({ technology, position: round(clamp(position + (u() - 0.5) * 6, 1, 99)), years }));
270
322
  }
271
323
  /** `{ technology, adoption }`: share of the market that has adopted each product, in percent. */
272
324
  static adoption(seed = 1) {
273
- const { u } = _chunkUMEKIIHJcjs.SampleData.rng(seed);
325
+ const { u } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
274
326
  return PRODUCTS.map(([technology, adoption]) => ({ technology, adoption: round(clamp(adoption + (u() - 0.5) * 6, 1, 99)) }));
275
327
  }
276
328
  /** `{ feature, category, implementation, satisfaction }` for an invented notes app: implementation 0 to 100, satisfaction -100 to 100. */
277
329
  static kano(seed = 1) {
278
- const { n } = _chunkUMEKIIHJcjs.SampleData.rng(seed);
330
+ const { n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
279
331
  return FEATURES.map(([feature, category, level]) => {
280
332
  const implementation = clamp(Math.round(level + n() * 4), 0, 100);
281
333
  return { feature, category, implementation, satisfaction: clamp(Math.round(KanoCurve.satisfaction(category, implementation / 100) * 100 + n() * 7), -100, 100) };
@@ -283,7 +335,7 @@ var StrategySamples = class {
283
335
  }
284
336
  /** An invented tea shop's value chain: nodes `{ id, visibility, evolution, evolveTo }` on 0 to 1, links from each component to what it needs. */
285
337
  static wardley(seed = 1) {
286
- const { u } = _chunkUMEKIIHJcjs.SampleData.rng(seed);
338
+ const { u } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
287
339
  const nodes = COMPONENTS.map(([id, visibility, evolution, evolveTo]) => {
288
340
  const shift = (u() - 0.5) * 0.05;
289
341
  return { id, visibility, evolution: round(clamp(evolution + shift, 0.02, 0.98), 3), evolveTo: evolveTo === void 0 ? null : round(clamp(evolveTo + shift, 0.02, 0.98), 3) };
@@ -292,12 +344,12 @@ var StrategySamples = class {
292
344
  }
293
345
  /** `{ factor, offering, score }`: how much each invented hotel offering gives on each competing factor, 0 to 10. */
294
346
  static strategyCanvas(seed = 1) {
295
- const { u } = _chunkUMEKIIHJcjs.SampleData.rng(seed);
347
+ const { u } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
296
348
  return OFFERINGS.flatMap(([offering, scores]) => FACTORS.map((factor, i) => ({ factor, offering, score: round(clamp(scores[i] + (u() - 0.5) * 1.2, 0, 10)) })));
297
349
  }
298
350
  /** `{ force, driver, strength }` for an invented grocery delivery firm: each driver's strength from 1 to 5. */
299
351
  static fiveForces(seed = 1) {
300
- const { u } = _chunkUMEKIIHJcjs.SampleData.rng(seed);
352
+ const { u } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
301
353
  return FORCES.flatMap(([force, drivers]) => drivers.map(([driver, strength]) => ({ force, driver, strength: clamp(strength + Math.round((u() - 0.5) * 1.6), 1, 5) })));
302
354
  }
303
355
  /** `{ block, note }` for an invented bike-share scheme, covering the blocks of the business model canvas and of the lean canvas. */
@@ -306,7 +358,7 @@ var StrategySamples = class {
306
358
  }
307
359
  /** `{ stage, lane, note, emotion }` for an invented mattress brand: emotion runs from -2 to 2 and repeats on each row of a stage. */
308
360
  static journey(seed = 1) {
309
- const { u } = _chunkUMEKIIHJcjs.SampleData.rng(seed);
361
+ const { u } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
310
362
  return JOURNEY.flatMap(([stage, mood, actions, touchpoints, pains]) => {
311
363
  const emotion = clamp(Math.round((mood + (u() - 0.5)) * 2) / 2, -2, 2);
312
364
  const lane = (name, notes) => notes.map((note) => ({ stage, lane: name, note, emotion }));
@@ -319,15 +371,57 @@ var StrategySamples = class {
319
371
  }
320
372
  /** `{ method, basis, low, high, current }`: an invented share's value range by method, with today's price on every row. */
321
373
  static footballField(seed = 1) {
322
- const { u, n } = _chunkUMEKIIHJcjs.SampleData.rng(seed);
374
+ const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
323
375
  const level = 0.9 + u() * 0.2, current = round(42 * level + n(), 2);
324
376
  return METHODS.map(([method, basis, low, high]) => ({ method, basis, low: round(low * level + n() * 1.5, 2), high: round(high * level + n() * 1.5, 2), current }));
325
377
  }
326
378
  /** `{ name, team, performance, potential, tenure }`: invented people rated 0 to 100 on two scales, with years in role. */
327
379
  static nineBox(seed = 1) {
328
- const { u } = _chunkUMEKIIHJcjs.SampleData.rng(seed);
380
+ const { u } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
329
381
  return PEOPLE.map((name, i) => ({ name, team: TEAMS[i % TEAMS.length], performance: Math.round(8 + u() * 88), potential: Math.round(8 + u() * 88), tenure: round(0.5 + u() * 9) }));
330
382
  }
383
+ /** `{ round, holder, shares }`: the fully diluted shares each holder of an invented company has after each funding round. */
384
+ static capTable(seed = 1) {
385
+ const { u } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
386
+ const held = /* @__PURE__ */ new Map([["Founders", 8e6], ["Employee pool", 1e6]]);
387
+ return ROUNDS.flatMap(([round2, buyers]) => {
388
+ const stakes = buyers.map(([holder, stake]) => [holder, stake * (0.85 + u() * 0.3)]);
389
+ const before = [...held.values()].reduce((sum5, shares) => sum5 + shares, 0), sold = stakes.reduce((sum5, [, stake]) => sum5 + stake, 0);
390
+ for (const [holder, stake] of stakes) held.set(holder, (_nullishCoalesce(held.get(holder), () => ( 0))) + Math.round(before * stake / (1 - sold) / 1e3) * 1e3);
391
+ return [...held].map(([holder, shares]) => ({ round: round2, holder, shares }));
392
+ });
393
+ }
394
+ /** `{ month, balance, burn }`: an invented company's month-end cash and net burn over a year, with one month of net inflow. */
395
+ static burn(seed = 1) {
396
+ const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
397
+ let balance = Math.round(4600 + u() * 600) * 1e3;
398
+ return Array.from({ length: 12 }, (_, i) => {
399
+ const burn = i === 4 ? -Math.round(40 + u() * 60) * 1e3 : Math.round(175 + 11 * i + n() * 22) * 1e3;
400
+ balance -= burn;
401
+ return { month: `${i < 2 ? 2025 : 2026}-${String((i + 10) % 12 + 1).padStart(2, "0")}`, balance, burn };
402
+ });
403
+ }
404
+ /** `{ task, stage, lane, kind, owner, limit }`: an invented shop team's board, each card carrying its stage's work-in-progress limit. A few cards move on a stage by seed. */
405
+ static kanban(seed = 1) {
406
+ const { u } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
407
+ return CARDS.map(([task, stage, lane, kind], i) => ({ task, at: Math.min(STAGES.length - 1, stage + (u() < 0.2 ? 1 : 0)), lane, kind, owner: PEOPLE[i % PEOPLE.length] })).sort((a, b) => a.at - b.at).map(({ at, ...card }) => ({ ...card, stage: STAGES[at][0], limit: STAGES[at][1] }));
408
+ }
409
+ /** `{ objective, keyResult, progress, confidence }` for an invented software firm's quarter: progress 0 to 100, confidence 0 to 1. */
410
+ static okr(seed = 1) {
411
+ const { u } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
412
+ return OBJECTIVES.flatMap(([objective, results]) => results.map(([keyResult, progress, confidence]) => ({
413
+ objective,
414
+ keyResult,
415
+ progress: clamp(Math.round(progress + (u() - 0.5) * 16), 0, 100),
416
+ confidence: round(clamp(confidence + (u() - 0.5) * 0.2, 0, 1))
417
+ })));
418
+ }
419
+ /** `{ period, adopters }`: households taking up an invented product in each of its first eight years, drawn from a Bass curve with noise. */
420
+ static bass(seed = 1) {
421
+ const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
422
+ const model = BassModel.run({ p: 0.02 + u() * 0.012, q: 0.38 + u() * 0.1, m: Math.round(110 + u() * 40) * 1e3 }, 8);
423
+ return model.map((period) => ({ period: 2018 + period.t, adopters: Math.max(0, Math.round(period.adopters * (1 + n() * 0.035))) }));
424
+ }
331
425
  };
332
426
 
333
427
  // src/charts/strategycharts/StrategyWords.ts
@@ -341,6 +435,427 @@ var StrategyWords = class {
341
435
  }
342
436
  };
343
437
 
438
+ // src/charts/strategycharts/BassDiffusionChart.ts
439
+ var BassDiffusionView = /* @__PURE__ */ ((BassDiffusionView2) => {
440
+ BassDiffusionView2["Both"] = "both";
441
+ BassDiffusionView2["Adopters"] = "adopters";
442
+ BassDiffusionView2["Cumulative"] = "cumulative";
443
+ return BassDiffusionView2;
444
+ })(BassDiffusionView || {});
445
+ var OBSERVED = "Observed";
446
+ var MODEL = "Bass model";
447
+ var SOURCES = ["Innovators", "Imitators"];
448
+ var TITLES = { ["adopters" /* Adopters */]: "New adopters per period", ["cumulative" /* Cumulative */]: "Cumulative adopters" };
449
+ var LIMIT = 60;
450
+ var NEARLY = 0.985;
451
+ var PANE_GAP = 20;
452
+ var SIZE = 10.5;
453
+ var figure = (value) => value.toLocaleString("en", { maximumFractionDigits: Math.abs(value) < 100 ? 1 : 0 });
454
+ var BassDiffusionChart = (_class = class extends _chunkXX2YTCORcjs.CartesianChart {
455
+ static __initStatic() {this.meta = {
456
+ id: "bass-diffusion",
457
+ name: "Bass diffusion curve",
458
+ family: "trend" /* Trend */,
459
+ dimension: 2 /* Two */,
460
+ shape: "table" /* Table */,
461
+ description: "Fits the Bass model to observed adoptions and draws new adopters per period and the cumulative S-curve, dashed where they run past the data.",
462
+ tags: ["diffusion of innovations", "adoption", "s-curve", "forecast", "innovation", "imitation", "marketing"],
463
+ sample: (seed) => StrategySamples.bass(seed),
464
+ variants: {
465
+ view: ["both" /* Both */, "adopters" /* Adopters */, "cumulative" /* Cumulative */],
466
+ split: [false, true],
467
+ peak: [false, true]
468
+ }
469
+ }}
470
+ #x = null;
471
+ #ticks = 6;
472
+ defaults() {
473
+ return { period: "period", adopters: "adopters", view: "both" /* Both */, split: false, peak: false };
474
+ }
475
+ yTicks() {
476
+ return _nullishCoalesce(this.options.yTicks, () => ( this.#ticks));
477
+ }
478
+ /** The panes have a scale each, so with both drawn only the periods can zoom. */
479
+ zoomAxes() {
480
+ return this.options.view === "both" /* Both */ ? "x" /* X */ : "xy" /* XY */;
481
+ }
482
+ #rows() {
483
+ const { period, adopters } = this.options;
484
+ return StrategyRows.of(this.options.data).flatMap((row) => {
485
+ const seen = StrategyRows.number(row[adopters]);
486
+ return seen === null ? [] : [{ period: row[period], adopters: Math.max(0, seen) }];
487
+ });
488
+ }
489
+ /** The coefficients in use, and the model run from the first period until nearly the whole market has adopted. */
490
+ get model() {
491
+ const { innovation, imitation, market } = this.options, observed = this.#rows().map((row) => row.adopters);
492
+ const given = (value, most = Infinity) => value !== void 0 && Number.isFinite(value) && value > 0 && value <= most ? value : void 0;
493
+ const fit = BassModel.fit(observed), total = _d3.sum.call(void 0, observed);
494
+ const p = _nullishCoalesce(_nullishCoalesce(given(innovation, 1), () => ( _optionalChain([fit, 'optionalAccess', _10 => _10.p]))), () => ( 0.03)), q = _nullishCoalesce(_nullishCoalesce(given(imitation), () => ( _optionalChain([fit, 'optionalAccess', _11 => _11.q]))), () => ( 0.38));
495
+ const m = _nullishCoalesce(_nullishCoalesce(given(market), () => ( _optionalChain([fit, 'optionalAccess', _12 => _12.m]))), () => ( (total > 0 ? BassModel.market(p, q, total, observed.length) : 100)));
496
+ const coefficients = { p, q, m }, done = BassModel.run(coefficients, LIMIT).findIndex((period) => period.cumulative >= NEARLY * m);
497
+ const count2 = Math.max(observed.length + 2, Math.min(LIMIT, Math.max(6, done < 0 ? LIMIT : done + 2)));
498
+ return { coefficients, fitted: !!fit && [innovation, imitation, market].every((value) => given(value) === void 0), observed, periods: BassModel.run(coefficients, count2) };
499
+ }
500
+ /** Names period `t`, counted from 1: the observed names, carried on where they are evenly spaced numbers and as +1, +2 where they are not. */
501
+ #namer() {
502
+ const cells = this.#rows().map((row) => row.period), numbers = cells.map((cell) => StrategyRows.number(cell)), step = cells.length > 1 ? numbers[1] - numbers[0] : 1;
503
+ if (!cells.length) return (t) => `${t}`;
504
+ if (step && numbers.every((value, i) => value !== null && Math.abs(value - (numbers[0] + i * step)) < 1e-9)) return (t) => `${+(numbers[0] + (t - 1) * step).toFixed(6)}`;
505
+ return (t) => t <= cells.length ? _chunkQ5A2TY2Acjs.FrameworkText.clean(cells[t - 1]) || `${t}` : `+${t - cells.length}`;
506
+ }
507
+ tickFormat(scale) {
508
+ if (scale !== this.#x) return super.tickFormat(scale);
509
+ const name = this.#namer(), last = this.model.periods.length;
510
+ return (value) => Number.isInteger(+value) && +value >= 1 && +value <= last ? _chunkQ5A2TY2Acjs.FrameworkText.fit(name(+value), 64, 11) : "";
511
+ }
512
+ #panes(height, { coefficients, observed, periods }) {
513
+ const { view, peak } = this.options;
514
+ const kinds = view === "both" /* Both */ ? ["adopters" /* Adopters */, "cumulative" /* Cumulative */] : [view === "cumulative" /* Cumulative */ ? "cumulative" /* Cumulative */ : "adopters" /* Adopters */];
515
+ const upper = kinds.length > 1 ? Math.round((height - PANE_GAP) * 0.54) : height;
516
+ return kinds.map((kind, i) => {
517
+ const top = i ? upper + PANE_GAP : 0, bottom = i ? height : upper, bell = kind === "adopters" /* Adopters */;
518
+ const head = bell ? peak ? 36 : 18 : i ? 18 : 32;
519
+ const high = bell ? _d3.max.call(void 0, [...periods.map((period) => period.adopters), ...observed]) : Math.max(coefficients.m, _d3.sum.call(void 0, observed));
520
+ const scale = _d3.scaleLinear.call(void 0, [0, high || 1], [bottom, Math.min(bottom - 1, top + head)]);
521
+ return { kind, first: !i, top, bottom, scale: bell ? scale.nice(4) : scale };
522
+ });
523
+ }
524
+ scales(ctx) {
525
+ const fit = this.model;
526
+ this.#x = _d3.scaleLinear.call(void 0, [0.5, fit.periods.length + 0.5], [0, ctx.plot.width]);
527
+ const [first] = this.#panes(ctx.plot.height, fit);
528
+ const [low, high] = first.scale.range();
529
+ this.#ticks = Math.max(2, Math.min(6, Math.floor((low - high) / 24)));
530
+ return { x: this.#x, y: first.scale };
531
+ }
532
+ plotMarks(ctx, { x, y }) {
533
+ const { split, peak } = this.options, { palette, theme, plot } = ctx;
534
+ const fit = this.model, { observed, periods, coefficients } = fit, name = this.#namer(), seen = observed.length;
535
+ const colors = { observed: seen ? palette.color(OBSERVED) : theme.inkMuted, model: palette.color(MODEL), sources: split ? SOURCES.map((source) => palette.color(source)) : [] };
536
+ const panes = this.#panes(plot.height, fit).map((pane) => pane.first ? { ...pane, scale: y } : pane);
537
+ const top = BassModel.peak(periods);
538
+ const columns = ctx.marks("periods", "rect", periods, (period) => period.t).attr("fill", "transparent");
539
+ ctx.set(columns, { x: (period) => x(period.t - 0.5), y: 0, width: (period) => Math.max(0, x(period.t + 0.5) - x(period.t - 0.5)), height: plot.height });
540
+ ctx.hover(columns, (period) => ({
541
+ title: name(period.t),
542
+ color: colors.model,
543
+ rows: [
544
+ ...period.t <= seen ? [[OBSERVED, figure(observed[period.t - 1])]] : [],
545
+ ["Model adopters", figure(period.adopters)],
546
+ [SOURCES[0], figure(period.innovators)],
547
+ [SOURCES[1], figure(period.imitators)],
548
+ ["Cumulative", figure(period.cumulative)],
549
+ ["Share of market", `${figure(period.cumulative / coefficients.m * 100)}%`]
550
+ ]
551
+ }));
552
+ const words = [];
553
+ let innovators = 0, counted = 0;
554
+ const running = periods.map((period) => {
555
+ innovators += period.innovators;
556
+ if (period.t <= seen) counted += observed[period.t - 1];
557
+ return { innovators, counted };
558
+ });
559
+ for (const pane of panes) {
560
+ const bell = pane.kind === "adopters" /* Adopters */;
561
+ const levels = periods.map((period, i) => bell ? { t: period.t, total: period.adopters, innovators: period.innovators, seen: period.t <= seen ? observed[i] : null } : { t: period.t, total: period.cumulative, innovators: running[i].innovators, seen: period.t <= seen ? running[i].counted : null });
562
+ if (!pane.first) StrategyPane.axis(ctx, pane.kind, pane.scale, Math.max(2, Math.min(4, Math.floor((pane.bottom - pane.top) / 28))), StrategyPane.compact);
563
+ words.push(...this.#drawPane(ctx, pane, x, levels, colors, fit, top, name));
564
+ }
565
+ words.push(...this.#heading(panes[0], fit, plot.width));
566
+ const rules = ctx.marks("peak-rule", "line", peak && top ? panes : [], (pane) => pane.kind).attr("stroke", theme.axis).attr("stroke-width", 1);
567
+ ctx.set(rules, { x1: x(_nullishCoalesce(_optionalChain([top, 'optionalAccess', _13 => _13.t]), () => ( 0))), x2: x(_nullishCoalesce(_optionalChain([top, 'optionalAccess', _14 => _14.t]), () => ( 0))), y1: (pane) => pane.scale.range()[1] - 6, y2: (pane) => pane.bottom });
568
+ StrategyWords.draw(ctx, "words", words);
569
+ }
570
+ /** The pane's title at the left and, on the first pane, the coefficients at the right where they fit beside it. */
571
+ #heading(pane, { coefficients: { p, q, m }, fitted, observed }, width) {
572
+ const figures = `p ${p.toFixed(3)}, q ${q.toFixed(3)}, m ${StrategyPane.compact(m)}`, whole = fitted ? `Fitted to ${observed.length} periods: ${figures}` : figures;
573
+ const room = width - _chunkQ5A2TY2Acjs.FrameworkText.width(TITLES[pane.kind], SIZE) - 24, text = [whole, figures].find((option) => _chunkQ5A2TY2Acjs.FrameworkText.width(option, SIZE) <= room);
574
+ return text ? [{ key: "coefficients", text, x: width - 2, y: pane.top + 7, anchor: "end", size: SIZE, halo: true }] : [];
575
+ }
576
+ #drawPane(ctx, pane, x, levels, colors, { observed, coefficients }, top, name) {
577
+ const { peak } = this.options, { theme, plot } = ctx, { kind, scale } = pane, bell = kind === "adopters" /* Adopters */;
578
+ const seen = observed.length, ahead = seen > 0 && seen < levels.length;
579
+ const spans = ahead ? [{ key: "fit", from: 1, to: seen, faded: false }, { key: "ahead", from: seen, to: levels.length, faded: true }] : [{ key: "fit", from: 1, to: levels.length, faded: false }];
580
+ const within = (span) => levels.filter((level) => level.t >= span.from && level.t <= span.to);
581
+ const curve = _chunkPY4R3IFFcjs.Scales.curve("monotone" /* Monotone */);
582
+ const market = bell ? [] : [coefficients.m];
583
+ const ceiling = ctx.marks(`axis-${kind}-market`, "line", market).attr("stroke", theme.axis).attr("stroke-dasharray", "4 3");
584
+ ctx.set(ceiling, { x1: 0, x2: plot.width, y1: (level) => scale(level), y2: (level) => scale(level) });
585
+ const layers = colors.sources.length ? spans.flatMap((span) => [0, 1].map((source) => ({ key: `${SOURCES[source]}/${span.key}`, source, faded: span.faded, levels: within(span) }))) : [];
586
+ const stack = _d3.area.call(void 0, ).x((level) => x(level.t)).curve(curve);
587
+ const fills = ctx.marks(`${kind}-sources`, "path", layers.filter((layer) => layer.levels.length > 1), (layer) => layer.key).attr("fill", (layer) => colors.sources[layer.source]).attr("fill-opacity", (layer) => layer.faded ? 0.28 : 0.72);
588
+ ctx.set(fills, { d: (layer) => _nullishCoalesce(stack.y0((level) => scale(layer.source ? level.innovators : 0)).y1((level) => scale(layer.source ? level.total : level.innovators))(layer.levels), () => ( "")) });
589
+ const whole = levels.at(-1);
590
+ ctx.hover(fills, (layer) => ({
591
+ title: SOURCES[layer.source],
592
+ color: colors.sources[layer.source],
593
+ rows: [["Span", layer.faded ? "Projected" : ahead ? "Fitted to the observed periods" : "Model"], ...whole && !bell ? [["Share of all adopters", `${figure((layer.source ? whole.total - whole.innovators : whole.innovators) / (whole.total || 1) * 100)}%`]] : []]
594
+ }));
595
+ const path = _d3.line.call(void 0, ).x((level) => x(level.t)).y((level) => scale(level.total)).curve(curve);
596
+ const drawn = ctx.marks(`${kind}-model`, "path", spans.filter((span) => !span.faded).map(within).filter((span) => span.length > 1)).attr("fill", "none").attr("stroke", colors.model).attr("stroke-width", 2).attr("stroke-linecap", "round");
597
+ ctx.set(drawn, { d: (span) => _nullishCoalesce(path(span), () => ( "")) });
598
+ ctx.drawOn(drawn);
599
+ const projected = ctx.marks(`${kind}-projection`, "path", spans.filter((span) => span.faded).map(within).filter((span) => span.length > 1)).attr("fill", "none").attr("stroke", colors.model).attr("stroke-width", 2).attr("stroke-dasharray", "6 4");
600
+ ctx.set(projected, { d: (span) => _nullishCoalesce(path(span), () => ( "")) });
601
+ const dots = ctx.marks(`${kind}-observed`, "circle", levels.filter((level) => level.seen !== null), (level) => level.t).attr("fill", colors.observed).attr("stroke", theme.surface).attr("stroke-width", 2);
602
+ ctx.set(dots, { cx: (level) => x(level.t), cy: (level) => scale(level.seen), r: 4 }, { r: 0 }, 12);
603
+ ctx.hover(dots, (level) => ({ title: name(level.t), color: colors.observed, rows: [[OBSERVED, figure(level.seen)], ["Model", figure(level.total)]] }));
604
+ const crest = peak && top ? levels.filter((level) => level.t === top.t) : [];
605
+ const turn = ctx.marks(`${kind}-peak`, "circle", crest, (level) => level.t).attr("fill", colors.model).attr("stroke", theme.surface).attr("stroke-width", 2);
606
+ ctx.set(turn, { cx: (level) => x(level.t), cy: (level) => scale(level.total), r: 5 }, { r: 0 });
607
+ ctx.hover(turn, (level) => ({ title: `Peak in ${name(level.t)}`, color: colors.model, rows: [["New adopters", figure(top.adopters)], ["Adopted by then", figure(top.cumulative)]] }));
608
+ const title = { key: `title/${kind}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(TITLES[kind], plot.width - 4, SIZE), x: 2, y: pane.top + 7, size: SIZE, weight: 600, tone: "ink", halo: true };
609
+ const words = [title];
610
+ if (!bell) {
611
+ const text = `Market potential ${StrategyPane.compact(coefficients.m)}`;
612
+ if (_chunkQ5A2TY2Acjs.FrameworkText.width(text, SIZE) + _chunkQ5A2TY2Acjs.FrameworkText.width(TITLES[kind], SIZE) + 24 <= plot.width || pane.first) words.push({ key: `market/${kind}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(text, plot.width - 4, SIZE), x: plot.width - 2, y: scale(coefficients.m) - 8, anchor: "end", size: SIZE, halo: true });
613
+ }
614
+ for (const level of crest) {
615
+ const text = `Peak ${name(level.t)}`, at = x(level.t), half = _chunkQ5A2TY2Acjs.FrameworkText.width(text, SIZE) / 2;
616
+ if (bell) words.push({ key: `peak/${kind}`, text, x: StrategyRows.clamp(at, half, Math.max(half, plot.width - half)), y: scale.range()[1] - 13, anchor: "middle", size: SIZE, weight: 600, tone: "ink", halo: true });
617
+ else if (pane.first && at + 10 + half * 2 <= plot.width) words.push({ key: `peak/${kind}`, text, x: at + 10, y: scale(level.total) + 9, size: SIZE, weight: 600, tone: "ink", halo: true });
618
+ }
619
+ return words;
620
+ }
621
+ }, _class.__initStatic(), _class);
622
+
623
+ // src/charts/strategycharts/BurnRunwayChart.ts
624
+
625
+ var BurnRunwayBalance = /* @__PURE__ */ ((BurnRunwayBalance2) => {
626
+ BurnRunwayBalance2["Area"] = "area";
627
+ BurnRunwayBalance2["Line"] = "line";
628
+ return BurnRunwayBalance2;
629
+ })(BurnRunwayBalance || {});
630
+ var BurnRunwayLayout = /* @__PURE__ */ ((BurnRunwayLayout2) => {
631
+ BurnRunwayLayout2["Panels"] = "panels";
632
+ BurnRunwayLayout2["Overlay"] = "overlay";
633
+ return BurnRunwayLayout2;
634
+ })(BurnRunwayLayout || {});
635
+ var CASH = "Cash balance";
636
+ var BURN = "Net burn";
637
+ var SHARE = 0.64;
638
+ var PANE_GAP2 = 18;
639
+ var THICK = 28;
640
+ var TICK = 42;
641
+ var MONTH = new Intl.DateTimeFormat("en", { month: "short", year: "2-digit" });
642
+ var figure2 = (value) => value.toLocaleString("en", { maximumFractionDigits: 1 });
643
+ var lasting = (value) => `${figure2(value)} ${figure2(value) === "1" ? "month" : "months"}`;
644
+ var BurnRunwayChart = (_class2 = class _BurnRunwayChart extends _chunkXX2YTCORcjs.CartesianChart {
645
+ static __initStatic2() {this.meta = {
646
+ id: "burn-runway",
647
+ name: "Burn and runway chart",
648
+ family: "financial" /* Financial */,
649
+ dimension: 2 /* Two */,
650
+ shape: "table" /* Table */,
651
+ description: "Plots month-end cash and monthly net burn, then extends the balance as a dashed line at the mean burn of the latest months to where it reaches zero.",
652
+ tags: ["cash", "burn rate", "runway", "start-up", "projection", "finance"],
653
+ sample: (seed) => StrategySamples.burn(seed),
654
+ variants: {
655
+ balanceMark: ["area" /* Area */, "line" /* Line */],
656
+ layout: ["panels" /* Panels */, "overlay" /* Overlay */],
657
+ window: [3, 6]
658
+ }
659
+ }}
660
+ /** Months until `balance` reaches zero at `rate` a month: 0 when it already has, null when the rate is not a burn. */
661
+ static runway(balance, rate) {
662
+ if (balance <= 0) return 0;
663
+ return rate !== null && rate > 0 ? balance / rate : null;
664
+ }
665
+ static #date(cell) {
666
+ if (cell instanceof Date) return Number.isNaN(+cell) ? null : cell;
667
+ const parts = /^(\d{4})-(\d{1,2})(?:-\d{1,2})?$/.exec(String(_nullishCoalesce(cell, () => ( ""))).trim());
668
+ return parts && +parts[2] >= 1 && +parts[2] <= 12 ? new Date(+parts[1], +parts[2] - 1, 1) : null;
669
+ }
670
+ /** `high` rounded up to a tick, leaving the low end of the axis where the data puts it: a month of net inflow should not open a whole step under zero. */
671
+ static #rounded(high, ticks) {
672
+ return high > 0 ? _d3.scaleLinear.call(void 0, ).domain([0, high]).nice(ticks).domain()[1] : high;
673
+ }
674
+ #every = 1;
675
+ #ticks = 6;
676
+ defaults() {
677
+ return { month: "month", balance: "balance", burn: "burn", balanceMark: "area" /* Area */, layout: "panels" /* Panels */, window: 3 };
678
+ }
679
+ yTicks() {
680
+ return _nullishCoalesce(this.options.yTicks, () => ( this.#ticks));
681
+ }
682
+ /** The pane under the balance has its own scale, so only the months can zoom. */
683
+ zoomAxes() {
684
+ return "x" /* X */;
685
+ }
686
+ /** The recorded months in order, each with its net burn where one is stated or can be worked out. */
687
+ get months() {
688
+ const { month, balance, burn } = this.options;
689
+ let before = null;
690
+ return StrategyRows.of(this.options.data).flatMap((row, i) => {
691
+ const cash = StrategyRows.number(row[balance]);
692
+ if (cash === null) return [];
693
+ const date = _BurnRunwayChart.#date(row[month]), fall = before === null ? null : before - cash;
694
+ before = cash;
695
+ return [{ label: date ? MONTH.format(date) : _chunkQ5A2TY2Acjs.FrameworkText.clean(row[month]) || `${i + 1}`, date, balance: cash, burn: _nullishCoalesce(StrategyRows.number(row[burn]), () => ( fall)) }];
696
+ });
697
+ }
698
+ get outlook() {
699
+ const recorded = this.months, last = recorded.at(-1), { window } = this.options;
700
+ const recent = recorded.slice(-(Number.isFinite(window) ? Math.max(1, Math.round(window)) : 3)).flatMap((month) => _nullishCoalesce(month.burn, () => ( []))), rate = _nullishCoalesce(_d3.mean.call(void 0, recent), () => ( null));
701
+ const runway = last ? _BurnRunwayChart.runway(last.balance, rate) : null;
702
+ const reach = runway === null || rate === null ? 0 : Math.min(runway, Math.max(6, recorded.length * 2));
703
+ const ahead = reach > 0 ? [..._d3.range.call(void 0, 0, Math.floor(reach) + 1), ...Number.isInteger(reach) ? [] : [reach]] : [];
704
+ return { rate, averaged: recent.length, months: runway, path: ahead.map((step) => ({ ahead: step, balance: step === runway ? 0 : last.balance - rate * step })) };
705
+ }
706
+ /** A label per band: the recorded months, then the months of the projection. */
707
+ #labels(recorded, { path }) {
708
+ const from = _optionalChain([recorded, 'access', _15 => _15.at, 'call', _16 => _16(-1), 'optionalAccess', _17 => _17.date]);
709
+ return [...recorded.map((month) => month.label), ..._d3.range.call(void 0, 1, Math.ceil(_nullishCoalesce(_optionalChain([path, 'access', _18 => _18.at, 'call', _19 => _19(-1), 'optionalAccess', _20 => _20.ahead]), () => ( 0))) + 1).map((step) => from ? MONTH.format(new Date(from.getFullYear(), from.getMonth() + step, 1)) : `+${step}`)];
710
+ }
711
+ tickFormat(scale) {
712
+ if (!("bandwidth" in scale)) return super.tickFormat(scale);
713
+ const labels = this.#labels(this.months, this.outlook);
714
+ return (key) => +key % this.#every ? "" : _chunkQ5A2TY2Acjs.FrameworkText.fit(_nullishCoalesce(labels[+key], () => ( "")), TICK * this.#every, 11);
715
+ }
716
+ #pane(height, recorded, rate) {
717
+ const burns = recorded.flatMap((month) => _nullishCoalesce(month.burn, () => ( []))), low = Math.min(0, _nullishCoalesce(_d3.min.call(void 0, burns), () => ( 0))), high = Math.max(0, _nullishCoalesce(_d3.max.call(void 0, burns), () => ( 0)), _nullishCoalesce(rate, () => ( 0)));
718
+ return _d3.scaleLinear.call(void 0, [low, _BurnRunwayChart.#rounded(high > low ? high : low + 1, 4)], [height, Math.round(height * SHARE) + PANE_GAP2]);
719
+ }
720
+ scales(ctx) {
721
+ const recorded = this.months, outlook = this.outlook, overlay = this.options.layout === "overlay" /* Overlay */;
722
+ const x = _d3.scaleBand.call(void 0, this.#labels(recorded, outlook).map((_, i) => `${i}`), [0, ctx.plot.width]).paddingInner(0.3).paddingOuter(0.2);
723
+ this.#every = Math.max(1, Math.ceil(TICK / Math.max(1, x.step())));
724
+ const values = [...recorded.map((month) => month.balance), ...overlay ? recorded.flatMap((month) => _nullishCoalesce(month.burn, () => ( []))) : []];
725
+ const low = Math.min(0, _nullishCoalesce(_d3.min.call(void 0, values), () => ( 0))), high = _nullishCoalesce(_d3.max.call(void 0, values), () => ( 1)), base = overlay ? ctx.plot.height : Math.round(ctx.plot.height * SHARE);
726
+ this.#ticks = Math.max(2, Math.min(6, Math.floor(base / 24)));
727
+ return { x, y: _d3.scaleLinear.call(void 0, [low, _BurnRunwayChart.#rounded(high > low ? high : low + 1, this.#ticks)], [base, 0]) };
728
+ }
729
+ plotMarks(ctx, { x, y }) {
730
+ const { balanceMark, layout } = this.options, { palette, theme, plot } = ctx;
731
+ const recorded = this.months, outlook = this.outlook, { rate, path } = outlook, labels = this.#labels(recorded, outlook);
732
+ const cash = palette.color(CASH), spend = palette.color(BURN), latest = recorded.length - 1;
733
+ const pane = layout === "overlay" /* Overlay */ ? y : this.#pane(plot.height, recorded, rate);
734
+ const centre = (index) => (_nullishCoalesce(x(`${Math.floor(index)}`), () => ( 0))) + x.bandwidth() / 2 + (index - Math.floor(index)) * x.step();
735
+ const told = (month) => ({ title: month.label, rows: [[CASH, StrategyPane.compact(month.balance)], ...month.burn === null ? [] : [[BURN, StrategyPane.compact(month.burn)]]] });
736
+ if (pane !== y) StrategyPane.axis(ctx, "burn", pane, 2, StrategyPane.compact);
737
+ const edge = path.length ? [centre(latest) + x.step() / 2] : [];
738
+ const divider = ctx.marks("axis-now", "line", edge).attr("stroke", theme.axis).attr("stroke-dasharray", "2 3");
739
+ ctx.set(divider, { x1: (at) => at, x2: (at) => at, y1: 0, y2: plot.height });
740
+ const frame = new (0, _chunkNEXADWQScjs.BarFrame)(true, pane, x), thick = Math.min(x.bandwidth(), THICK);
741
+ const spent = recorded.flatMap((month, i) => month.burn === null ? [] : [{ key: `${i}`, month, burn: month.burn }]);
742
+ const bars = ctx.marks("burn", "path", spent, (bar) => bar.key).attr("fill", spend);
743
+ ctx.set(bars, { d: (bar) => frame.bar(centre(+bar.key) - thick / 2, thick, 0, bar.burn, 3) }, { d: (bar) => frame.bar(centre(+bar.key) - thick / 2, thick, 0, 0, 0) }, 10);
744
+ ctx.hover(bars, (bar) => ({ ...told(bar.month), color: spend }));
745
+ const averaged = rate === null ? [] : [{ from: centre(Math.max(0, recorded.length - outlook.averaged)) - x.step() / 2, to: path.length ? centre(latest + path.at(-1).ahead) : centre(latest) + x.step() / 2 }];
746
+ const level = ctx.marks("burn-rate", "line", averaged).attr("stroke", spend).attr("stroke-width", 1.5).attr("stroke-dasharray", "5 4");
747
+ ctx.set(level, { x1: (span) => span.from, x2: (span) => span.to, y1: pane(_nullishCoalesce(rate, () => ( 0))), y2: pane(_nullishCoalesce(rate, () => ( 0))) });
748
+ ctx.hover(level, () => ({ title: "Recent burn rate", color: spend, rows: [["Mean net burn", `${StrategyPane.compact(_nullishCoalesce(rate, () => ( 0)))} a month`], ["Months averaged", outlook.averaged]] }));
749
+ const past = recorded.map((month, i) => [centre(i), y(month.balance)]), ahead = path.map((step) => [centre(latest + step.ahead), y(step.balance)]);
750
+ const under = _d3.area.call(void 0, ).x((point) => point[0]).y0(y(0)).y1((point) => point[1]);
751
+ const filled = balanceMark === "area" /* Area */ ? [{ key: "recorded", points: past, opacity: 0.2 }, { key: "projected", points: ahead, opacity: 0.08 }].filter((part) => part.points.length > 1) : [];
752
+ const fills = ctx.marks("balance-area", "path", filled, (part) => part.key).attr("fill", cash).attr("fill-opacity", (part) => part.opacity);
753
+ ctx.set(fills, { d: (part) => _nullishCoalesce(under(part.points), () => ( "")) });
754
+ const traced = ctx.marks("balance", "path", past.length > 1 ? [past] : []).attr("fill", "none").attr("stroke", cash).attr("stroke-width", 2).attr("stroke-linejoin", "round");
755
+ ctx.set(traced, { d: (points2) => _nullishCoalesce(_d3.line.call(void 0, )(points2), () => ( "")) });
756
+ ctx.drawOn(traced);
757
+ ctx.hover(traced, () => ({ title: CASH, color: cash, rows: [["Latest", StrategyPane.compact(recorded[latest].balance)], ["Months recorded", recorded.length]] }));
758
+ const runway = outlook.months === null ? "None at this rate" : lasting(outlook.months);
759
+ const dashed = ctx.marks("projection", "path", ahead.length > 1 ? [ahead] : []).attr("fill", "none").attr("stroke", cash).attr("stroke-width", 2).attr("stroke-dasharray", "6 4");
760
+ ctx.set(dashed, { d: (points2) => _nullishCoalesce(_d3.line.call(void 0, )(points2), () => ( "")) });
761
+ ctx.hover(dashed, () => ({ title: "Balance at the recent burn rate", color: cash, rows: [["Burn rate", `${StrategyPane.compact(_nullishCoalesce(rate, () => ( 0)))} a month`], ["Runway", runway]] }));
762
+ const dotted = recorded.map((month, i) => ({ key: `${i}`, month, at: past[i] })).filter((dot, i) => i === latest || balanceMark === "line" /* Line */ && x.step() >= 12);
763
+ const dots = ctx.marks("months", "circle", dotted, (dot) => dot.key).attr("fill", cash).attr("stroke", theme.surface).attr("stroke-width", 2);
764
+ ctx.set(dots, { cx: (dot) => dot.at[0], cy: (dot) => dot.at[1], r: 4 }, { r: 0 }, 10);
765
+ ctx.hover(dots, (dot) => ({ ...told(dot.month), color: cash }));
766
+ const spentOut = path.length && path.at(-1).ahead === outlook.months ? [ahead.at(-1)] : [];
767
+ const end = ctx.marks("cash-out", "circle", spentOut).attr("fill", theme.surface).attr("stroke", cash).attr("stroke-width", 2);
768
+ ctx.set(end, { cx: (point) => point[0], cy: (point) => point[1], r: 4.5 }, { r: 0 });
769
+ ctx.hover(end, () => ({ title: `Reaches zero in ${labels.at(-1)}`, color: cash, rows: [["Runway", runway], ["Burn rate", `${StrategyPane.compact(_nullishCoalesce(rate, () => ( 0)))} a month`]] }));
770
+ StrategyWords.draw(ctx, "notes", this.#notes(recorded, outlook, plot.width));
771
+ }
772
+ /** The runway in words: at the right over the projection, or at the left when there is none to draw. */
773
+ #notes(recorded, { rate, averaged, months: runway, path }, width) {
774
+ if (!recorded.length) return [];
775
+ const span = averaged === 1 ? "month" : `${averaged} months`, room = Math.min(width - 8, width * 0.6);
776
+ const rated = (lead, burn) => [`, the mean of the last ${span}`, ` (${averaged}-month mean)`, ""].map((tail) => `${lead} ${StrategyPane.compact(burn)} a month${tail}`).filter((text) => _chunkQ5A2TY2Acjs.FrameworkText.width(text, 10.5) <= room).slice(0, 1);
777
+ const lines = path.length ? [`Runway ${lasting(runway)}`, ...rated("at", rate)] : runway === 0 ? ["Balance is at or below zero"] : rate === null ? ["No net burn recorded to project from"] : ["Cash is not falling at the recent rate", ...rated("net burn", rate)];
778
+ return lines.map((text, row) => ({
779
+ key: `note/${row}`,
780
+ text: _chunkQ5A2TY2Acjs.FrameworkText.fit(text, width - 8, 11),
781
+ full: text,
782
+ x: path.length ? width - 2 : 4,
783
+ y: 7 + row * 14,
784
+ anchor: path.length ? "end" : "start",
785
+ size: row ? 10.5 : 11.5,
786
+ weight: row ? 400 : 600,
787
+ tone: row ? "secondary" : "ink",
788
+ halo: true
789
+ }));
790
+ }
791
+ }, _class2.__initStatic2(), _class2);
792
+
793
+ // src/charts/strategycharts/StrategyNotes.ts
794
+ var SIZES = [11, 10, 9];
795
+ var DOT = 3;
796
+ var INDENT = 10;
797
+ var CARD_PAD = 4;
798
+ var TIP_WIDTH = 320;
799
+ var StrategyNotes = class _StrategyNotes {
800
+ static plan(boxes, style) {
801
+ let blocks = [];
802
+ for (const size of SIZES) {
803
+ const filled = boxes.map((box) => _StrategyNotes.#fill(box, size, style));
804
+ blocks = filled.flatMap((fill) => fill.blocks);
805
+ if (filled.every((fill) => fill.whole)) break;
806
+ }
807
+ return blocks;
808
+ }
809
+ static #fill(box, size, style) {
810
+ const { notes } = box, lead = Math.round(size * 1.25), pad = style === "card" ? CARD_PAD : 0, gap = style === "bullet" ? 2 : 3;
811
+ const indent = style === "bullet" ? INDENT : pad, width = box.width - indent - pad;
812
+ if (width < size * 2 || box.height < lead) return { blocks: [], whole: !notes.length };
813
+ const wrapped = notes.map((note) => _chunkQ5A2TY2Acjs.FrameworkText.wrap(note.text, width, size));
814
+ const tall = (lines) => lines.length * lead + pad;
815
+ const cost = (count2) => wrapped.slice(0, count2).reduce((sum5, lines) => sum5 + tall(lines) + gap, 0);
816
+ let shown = notes.length;
817
+ if (cost(shown) - gap > box.height) {
818
+ shown--;
819
+ while (shown > 0 && cost(shown) + lead > box.height) shown--;
820
+ }
821
+ let cut = false;
822
+ if (shown === 0 && notes.length) {
823
+ const rows = Math.floor((box.height - pad - (notes.length > 1 ? lead + gap : 0)) / lead);
824
+ if (rows >= 1) {
825
+ cut = wrapped[0].length > rows;
826
+ wrapped[0] = _chunkQ5A2TY2Acjs.FrameworkText.clamp(wrapped[0], rows, width, size);
827
+ shown = 1;
828
+ }
829
+ }
830
+ let top = box.y;
831
+ const place = (note, hidden2, lines, key) => {
832
+ const height = note ? tall(lines) : lead, inset = note ? pad / 2 : 0;
833
+ const block = { key, box, note, hidden: hidden2, lines, x: box.x + (note ? indent : 0), y: top + inset + size - 1, lead, left: box.x, top, width: box.width, height, size };
834
+ top += height + gap;
835
+ return block;
836
+ };
837
+ const blocks = notes.slice(0, shown).map((note, i) => place(note, [], wrapped[i], `${box.key}:${i}`));
838
+ const hidden = notes.slice(shown);
839
+ if (hidden.length && top + lead <= box.y + box.height + 0.5) blocks.push(place(null, hidden, [`+${hidden.length} more`], `${box.key}:more`));
840
+ return { blocks, whole: !hidden.length && !cut };
841
+ }
842
+ static draw(ctx, name, blocks, style) {
843
+ const items = ctx.marks(name, "g", blocks, (block) => block.key), tint = (block) => _nullishCoalesce(_optionalChain([block, 'access', _21 => _21.note, 'optionalAccess', _22 => _22.color]), () => ( block.box.color));
844
+ ctx.hover(items, (block) => {
845
+ if (block.note) return _chunkQ5A2TY2Acjs.FrameworkText.tip(block.note.text, _nullishCoalesce(block.note.rows, () => ( [])), tint(block));
846
+ return { title: `${block.hidden.length} more`, color: block.box.color, rows: block.hidden.flatMap((note) => _chunkQ5A2TY2Acjs.FrameworkText.wrap(note.text, TIP_WIDTH, 12).map((line8) => [line8, ""])) };
847
+ });
848
+ const carded = (block) => style === "card" && !!block.note;
849
+ const backs = items.selectAll(":scope > rect").data((block) => [block]).join("rect").attr("rx", 3).attr("fill", (block) => carded(block) ? tint(block) : "transparent").attr("fill-opacity", (block) => carded(block) ? 0.22 : null);
850
+ ctx.set(backs, { x: (block) => block.left, y: (block) => block.top, width: (block) => block.width, height: (block) => block.height });
851
+ const dots = items.selectAll("circle").data((block) => style === "bullet" && block.note ? [block] : []).join("circle").attr("r", DOT).attr("fill", tint).attr("stroke", ctx.theme.surface).attr("stroke-width", 2);
852
+ ctx.set(dots, { cx: (block) => block.left + DOT + 1, cy: (block) => block.top + block.lead / 2 });
853
+ const body = ctx.text(items.selectAll("text").data((block) => [block]).join("text"), 11, "ink").attr("font-size", (block) => block.size).attr("fill", (block) => block.note ? ctx.theme.ink : ctx.theme.inkSecondary).attr("pointer-events", "none");
854
+ _chunkQ5A2TY2Acjs.FrameworkText.write(ctx, body);
855
+ return items;
856
+ }
857
+ };
858
+
344
859
  // src/charts/strategycharts/BusinessModelCanvas.ts
345
860
  var BusinessModelCanvasKind = /* @__PURE__ */ ((BusinessModelCanvasKind2) => {
346
861
  BusinessModelCanvasKind2["BusinessModel"] = "business-model";
@@ -352,7 +867,7 @@ var BusinessModelCanvasNotes = /* @__PURE__ */ ((BusinessModelCanvasNotes2) => {
352
867
  BusinessModelCanvasNotes2["Sticky"] = "sticky";
353
868
  return BusinessModelCanvasNotes2;
354
869
  })(BusinessModelCanvasNotes || {});
355
- var slot = (name, short, area3, step, column, row, columns, rows, pattern) => ({ name, short, area: area3, step, column, row, columns, rows, pattern });
870
+ var slot = (name, short, area5, step, column, row, columns, rows, pattern) => ({ name, short, area: area5, step, column, row, columns, rows, pattern });
356
871
  var finances = (cost, revenue) => [slot("Cost Structure", "Costs", "Finances", cost, 0, 2, 5, 1, /cost/), slot("Revenue Streams", "Revenue", "Finances", revenue, 5, 2, 5, 1, /revenue/)];
357
872
  var SLOTS = {
358
873
  ["business-model" /* BusinessModel */]: [
@@ -382,8 +897,8 @@ var GAP = 4;
382
897
  var PAD = 4;
383
898
  var HEAD_SIZE = 10;
384
899
  var BADGE = 7;
385
- var BusinessModelCanvas = (_class = class extends _chunkEEF5WRRZcjs.Chart2D {
386
- static __initStatic() {this.meta = {
900
+ var BusinessModelCanvas = (_class3 = class extends _chunkEEF5WRRZcjs.Chart2D {
901
+ static __initStatic3() {this.meta = {
387
902
  id: "business-model-canvas",
388
903
  name: "Business model canvas",
389
904
  family: "matrix" /* Matrix */,
@@ -459,10 +974,211 @@ var BusinessModelCanvas = (_class = class extends _chunkEEF5WRRZcjs.Chart2D {
459
974
  const style = noteStyle === "sticky" /* Sticky */ ? "card" : "bullet";
460
975
  StrategyNotes.draw(ctx, "notes", StrategyNotes.plan(lists, style), style);
461
976
  }
462
- }, _class.__initStatic(), _class);
977
+ }, _class3.__initStatic3(), _class3);
978
+
979
+ // src/charts/strategycharts/CapTableChart.ts
980
+
981
+ var CapTableView = /* @__PURE__ */ ((CapTableView2) => {
982
+ CapTableView2["Rounds"] = "rounds";
983
+ CapTableView2["Single"] = "single-round";
984
+ CapTableView2["Dilution"] = "dilution";
985
+ return CapTableView2;
986
+ })(CapTableView || {});
987
+ var CapTableBasis = /* @__PURE__ */ ((CapTableBasis2) => {
988
+ CapTableBasis2["Percent"] = "percent";
989
+ CapTableBasis2["Shares"] = "shares";
990
+ return CapTableBasis2;
991
+ })(CapTableBasis || {});
992
+ var LATEST = "Latest";
993
+ var SINGLE = 84;
994
+ var SIZE2 = 10.5;
995
+ var HEAD = 14;
996
+ var figure3 = (value, digits = 1) => value.toLocaleString("en", { maximumFractionDigits: digits });
997
+ var percent = (share, digits = 1) => `${figure3(share * 100, digits)}%`;
998
+ var points = (change) => `${change > 0 ? "+" : change < 0 ? "\u2212" : ""}${figure3(Math.abs(change) * 100)} pts`;
999
+ var count = (shares) => Intl.NumberFormat("en", { notation: "compact", maximumFractionDigits: 1 }).format(shares);
1000
+ var CapTableChart = (_class4 = class _CapTableChart extends _chunkXX2YTCORcjs.CartesianChart {
1001
+ static __initStatic4() {this.meta = {
1002
+ id: "cap-table",
1003
+ name: "Cap table chart",
1004
+ family: "composition" /* Composition */,
1005
+ dimension: 2 /* Two */,
1006
+ shape: "table" /* Table */,
1007
+ description: "Stacks each holder's share of the fully diluted total for every funding round, with ribbons that show dilution from one round to the next.",
1008
+ tags: ["capitalisation table", "ownership", "dilution", "funding rounds", "equity", "start-up"],
1009
+ sample: (seed) => StrategySamples.capTable(seed),
1010
+ variants: {
1011
+ view: ["rounds" /* Rounds */, "single-round" /* Single */, "dilution" /* Dilution */],
1012
+ orientation: ["vertical" /* Vertical */, "horizontal" /* Horizontal */],
1013
+ basis: ["percent" /* Percent */, "shares" /* Shares */],
1014
+ ribbons: [true, false]
1015
+ },
1016
+ /** One bar has no neighbour to join and the same proportions on either basis, and the waterfall is in points of ownership. */
1017
+ valid: (values) => values.view === "rounds" /* Rounds */ || values.basis === "percent" /* Percent */ && values.ribbons === true
1018
+ }}
1019
+ /** The waterfall of `holder`'s ownership: its share after the first round it holds in, the change at each later round, and where it stands. */
1020
+ static dilution(rounds, holder) {
1021
+ const shares = rounds.map((round2) => _nullishCoalesce(_optionalChain([round2, 'access', _23 => _23.stakes, 'access', _24 => _24.find, 'call', _25 => _25((stake) => stake.holder === holder), 'optionalAccess', _26 => _26.share]), () => ( 0))), first = shares.findIndex((share) => share > 0);
1022
+ if (first < 0) return [];
1023
+ const steps = shares.slice(first).map((share, i) => ({ label: rounds[first + i].round, from: i ? shares[first + i - 1] : 0, to: share, total: !i }));
1024
+ return steps.length > 1 ? [...steps, { label: LATEST, from: 0, to: shares.at(-1), total: true }] : steps;
1025
+ }
1026
+ #room = 84;
1027
+ defaults() {
1028
+ return { round: "round", holder: "holder", shares: "shares", view: "rounds" /* Rounds */, orientation: "vertical" /* Vertical */, basis: "percent" /* Percent */, ribbons: true };
1029
+ }
1030
+ get #vertical() {
1031
+ return this.options.orientation !== "horizontal" /* Horizontal */;
1032
+ }
1033
+ #ledger() {
1034
+ const { round: round2, holder, shares } = this.options;
1035
+ const held = /* @__PURE__ */ new Map(), holders = /* @__PURE__ */ new Set();
1036
+ for (const row of StrategyRows.of(this.options.data)) {
1037
+ const name = _chunkQ5A2TY2Acjs.FrameworkText.clean(row[round2]), who = _chunkQ5A2TY2Acjs.FrameworkText.clean(row[holder]), amount = StrategyRows.number(row[shares]);
1038
+ if (!name || !who || amount === null || amount < 0) continue;
1039
+ holders.add(who);
1040
+ const stakes = _nullishCoalesce(held.get(name), () => ( /* @__PURE__ */ new Map()));
1041
+ held.set(name, stakes.set(who, (_nullishCoalesce(stakes.get(who), () => ( 0))) + amount));
1042
+ }
1043
+ let earlier = null;
1044
+ const rounds = [...held].map(([name, stakes]) => {
1045
+ const total = _d3.sum.call(void 0, stakes.values()), before = earlier;
1046
+ const listed = [...holders].filter((who) => stakes.get(who)).map((who) => ({ round: name, holder: who, shares: stakes.get(who), share: stakes.get(who) / total, before: before ? _nullishCoalesce(before.get(who), () => ( 0)) : null }));
1047
+ earlier = new Map(listed.map((stake) => [stake.holder, stake.share]));
1048
+ return { round: name, total, stakes: listed };
1049
+ });
1050
+ return { rounds, holders: [...holders] };
1051
+ }
1052
+ /** Each round in order, with every holder's stake in it. */
1053
+ get rounds() {
1054
+ return this.#ledger().rounds;
1055
+ }
1056
+ /** What the view draws: the stacked slices of the rounds shown, or the steps of the followed holder's waterfall. */
1057
+ #plan() {
1058
+ const { view, basis, focusRound, focusHolder } = this.options, { rounds, holders } = this.#ledger();
1059
+ const holder = holders.includes(_nullishCoalesce(focusHolder, () => ( ""))) ? focusHolder : _nullishCoalesce(holders[0], () => ( ""));
1060
+ if (view === "dilution" /* Dilution */) return { rounds, holders, holder, shown: [], slices: [], steps: _CapTableChart.dilution(rounds, holder).map((step, i) => ({ ...step, key: `${i}` })) };
1061
+ const shown = view === "single-round" /* Single */ ? rounds.filter((round2, i) => rounds.some((other) => other.round === focusRound) ? round2.round === focusRound : i === rounds.length - 1) : rounds;
1062
+ const slices = shown.flatMap((round2) => {
1063
+ let at = 0;
1064
+ return round2.stakes.map((stake, i) => {
1065
+ const from = at;
1066
+ at += basis === "shares" /* Shares */ ? stake.shares : stake.share * 100;
1067
+ return { key: `${stake.round}/${stake.holder}`, stake, from, to: at, outer: i === round2.stakes.length - 1 };
1068
+ });
1069
+ });
1070
+ return { rounds, holders, holder, shown, slices, steps: [] };
1071
+ }
1072
+ get #stepped() {
1073
+ return this.options.view === "dilution" /* Dilution */;
1074
+ }
1075
+ /** The followed holder is named over the waterfall, where a legend of one entry would not show. */
1076
+ plotMargin() {
1077
+ const base = super.plotMargin();
1078
+ return { ...base, top: base.top + (this.#stepped ? HEAD : 0) };
1079
+ }
1080
+ legendItems() {
1081
+ return this.#stepped ? [] : super.legendItems();
1082
+ }
1083
+ tickFormat(scale) {
1084
+ if ("bandwidth" in scale) {
1085
+ const steps = this.#stepped ? this.#plan().steps : null;
1086
+ return (name) => _chunkQ5A2TY2Acjs.FrameworkText.fit(steps ? _nullishCoalesce(_optionalChain([steps, 'access', _27 => _27[+name], 'optionalAccess', _28 => _28.label]), () => ( "")) : String(name), this.#room, 11);
1087
+ }
1088
+ return this.#stepped || this.options.basis !== "shares" /* Shares */ ? (value) => `${figure3(+value)}%` : super.tickFormat(scale);
1089
+ }
1090
+ scales(ctx) {
1091
+ const { view, basis, ribbons } = this.options, vertical = this.#vertical, { width, height } = ctx.plot;
1092
+ const { steps, shown } = this.#plan();
1093
+ const names = this.#stepped ? steps.map((step) => step.key) : shown.map((round2) => round2.round);
1094
+ const top = this.#stepped ? (_nullishCoalesce(_d3.max.call(void 0, steps, (step) => Math.max(step.from, step.to)), () => ( 1))) * 125 : basis === "shares" /* Shares */ ? _d3.max.call(void 0, shown, (round2) => round2.total) || 1 : 100;
1095
+ const band = _d3.scaleBand.call(void 0, names, [0, vertical ? width : height]).padding(view === "rounds" /* Rounds */ && ribbons ? 0.45 : 0.3);
1096
+ const value = _d3.scaleLinear.call(void 0, [0, top], vertical ? [height, 0] : [0, width]);
1097
+ this.#room = vertical ? Math.max(12, band.step() - 6) : 84;
1098
+ return vertical ? { x: band, y: value } : { x: value, y: band };
1099
+ }
1100
+ plotMarks(ctx, { x, y }) {
1101
+ const { view, basis, ribbons } = this.options, { palette, theme, plot } = ctx;
1102
+ const vertical = this.#vertical, frame = new (0, _chunkNEXADWQScjs.BarFrame)(vertical, vertical ? y : x, vertical ? x : y);
1103
+ const { rounds, holders, holder, slices, steps } = this.#plan();
1104
+ for (const name of holders) palette.color(name);
1105
+ const thick = view === "single-round" /* Single */ ? Math.min(frame.thick, SINGLE) : frame.thick;
1106
+ const at = (name) => (_nullishCoalesce(frame.band(name), () => ( 0))) + (frame.thick - thick) / 2;
1107
+ const joins = view === "rounds" /* Rounds */ && ribbons ? slices.flatMap((left) => {
1108
+ const next = rounds[rounds.findIndex((round2) => round2.round === left.stake.round) + 1];
1109
+ const right = next && slices.find((slice) => slice.stake.round === next.round && slice.stake.holder === left.stake.holder);
1110
+ return right ? [{ key: left.key, holder: left.stake.holder, left, right }] : [];
1111
+ }) : [];
1112
+ const ribbon = ({ left, right }) => {
1113
+ const near = at(left.stake.round) + thick, far = at(right.stake.round);
1114
+ return `M${frame.point(near, left.from)}L${frame.point(near, left.to)}L${frame.point(far, right.to)}L${frame.point(far, right.from)}Z`;
1115
+ };
1116
+ const bands = ctx.marks("ribbons", "path", joins, (join) => join.key).attr("fill", (join) => palette.color(join.holder)).attr("fill-opacity", 0.22);
1117
+ ctx.set(bands, { d: ribbon });
1118
+ ctx.hover(bands, ({ left, right }) => ({
1119
+ title: left.stake.holder,
1120
+ color: palette.color(left.stake.holder),
1121
+ rows: [[left.stake.round, percent(left.stake.share)], [right.stake.round, percent(right.stake.share)], ["Change", points(right.stake.share - left.stake.share)]]
1122
+ }));
1123
+ const bars = ctx.marks("stakes", "path", slices, (slice) => slice.key).attr("fill", (slice) => palette.color(slice.stake.holder));
1124
+ const shape = (slice, to) => frame.bar(at(slice.stake.round), thick, slice.from, to, slice.outer ? 4 : 0, slice.from ? 2 : 0);
1125
+ ctx.set(bars, { d: (slice) => shape(slice, slice.to) }, { d: (slice) => shape(slice, slice.from) }, 12);
1126
+ ctx.hover(bars, ({ stake }) => ({
1127
+ title: stake.holder,
1128
+ color: palette.color(stake.holder),
1129
+ rows: [["Round", stake.round], ["Shares", stake.shares.toLocaleString("en")], ["Ownership", percent(stake.share, 2)], ...stake.before === null ? [] : [["Since last round", points(stake.share - stake.before)]]]
1130
+ }));
1131
+ const words = slices.flatMap((slice) => {
1132
+ const { stake } = slice, across = Math.abs(frame.value(slice.to) - frame.value(slice.from)), start = at(stake.round);
1133
+ if (view === "single-round" /* Single */) return _CapTableChart.#named(slice, frame, start, thick, across, plot);
1134
+ const text = basis === "shares" /* Shares */ ? count(stake.shares) : percent(stake.share, 0), wide = _chunkQ5A2TY2Acjs.FrameworkText.width(text, SIZE2) + 6;
1135
+ if (vertical ? across < 14 || thick < wide : across < wide || thick < 14) return [];
1136
+ const [px, py] = frame.point(start + thick / 2, (slice.from + slice.to) / 2);
1137
+ return [{ key: slice.key, text, x: px, y: py, anchor: "middle", size: SIZE2, weight: 600, fill: palette.inkOn(palette.color(stake.holder)) }];
1138
+ });
1139
+ const fill = (step) => step.total ? palette.color(holder) : palette.diverging(step.to < step.from ? 0.9 : -0.9);
1140
+ const rules = steps.slice(0, -1).map((step, i) => ({ key: step.key, ...frame.rule(step.to * 100, at(step.key) + thick, at(steps[i + 1].key)) }));
1141
+ const links = ctx.marks("connectors", "line", rules, (rule) => rule.key).attr("stroke", theme.axis).attr("stroke-width", 1);
1142
+ ctx.set(links, { x1: (rule) => rule.x1, x2: (rule) => rule.x2, y1: (rule) => rule.y1, y2: (rule) => rule.y2 });
1143
+ const falls = ctx.marks("steps", "path", steps, (step) => step.key).attr("fill", fill);
1144
+ ctx.set(falls, { d: (step) => frame.bar(at(step.key), thick, step.from * 100, step.to * 100, 4) }, { d: (step) => frame.bar(at(step.key), thick, step.from * 100, step.from * 100, 0) }, 30);
1145
+ ctx.hover(falls, (step) => ({
1146
+ title: step.label,
1147
+ color: fill(step),
1148
+ rows: step.total ? [[holder, percent(step.to, 2)]] : [["Before", percent(step.from, 2)], ["After", percent(step.to, 2)], ["Change", points(step.to - step.from)]]
1149
+ }));
1150
+ words.push(...steps.flatMap((step) => {
1151
+ const end = Math.max(step.from, step.to) * 100, room = vertical ? frame.band.step() - 4 : plot.width - frame.value(end) - 5;
1152
+ const text = (step.total ? [percent(step.to), percent(step.to, 0)] : [points(step.to - step.from), points(step.to - step.from).replace(" pts", "")]).find((option) => _chunkQ5A2TY2Acjs.FrameworkText.width(option, SIZE2) <= room);
1153
+ if (!text) return [];
1154
+ const [px, py] = frame.point(at(step.key) + thick / 2, end, vertical ? -9 : 5);
1155
+ return [{ key: `step/${step.key}`, text, x: px, y: py, anchor: vertical ? "middle" : "start", size: SIZE2, weight: step.total ? 600 : 400, tone: "ink" }];
1156
+ }));
1157
+ if (steps.length) words.push({ key: "followed", text: _chunkQ5A2TY2Acjs.FrameworkText.fit(`${holder}: ownership after each round`, plot.width, 11), x: 0, y: 3 - HEAD, weight: 600, tone: "ink" });
1158
+ StrategyWords.draw(ctx, "labels", words);
1159
+ }
1160
+ /** The single bar names each slice outside it: its share before a column and its holder after, or both under a bar. Slices too thin for a line of text go unnamed. */
1161
+ static #named(slice, frame, start, thick, across, plot) {
1162
+ const { stake } = slice, [px, py] = frame.point(start + thick, (slice.from + slice.to) / 2), share = percent(stake.share);
1163
+ if (frame.vertical) {
1164
+ const name2 = _chunkQ5A2TY2Acjs.FrameworkText.fit(stake.holder, plot.width - px - 8, SIZE2);
1165
+ if (across < 13) return [];
1166
+ return [
1167
+ ...start - 8 >= _chunkQ5A2TY2Acjs.FrameworkText.width(share, SIZE2) ? [{ key: slice.key, text: share, x: start - 8, y: py, anchor: "end", size: SIZE2 }] : [],
1168
+ ...name2.length >= 4 ? [{ key: `${slice.key}/name`, text: name2, full: stake.holder, x: px + 8, y: py, size: SIZE2, tone: "ink" }] : []
1169
+ ];
1170
+ }
1171
+ const name = _chunkQ5A2TY2Acjs.FrameworkText.fit(stake.holder, across - 4, SIZE2), named = name.length >= 4;
1172
+ if (py + 28 > plot.height || _chunkQ5A2TY2Acjs.FrameworkText.width(share, SIZE2) > across - 4) return [];
1173
+ return [
1174
+ ...named ? [{ key: `${slice.key}/name`, text: name, full: stake.holder, x: px, y: py + 11, anchor: "middle", size: SIZE2, tone: "ink" }] : [],
1175
+ { key: slice.key, text: share, x: px, y: py + (named ? 24 : 11), anchor: "middle", size: SIZE2 }
1176
+ ];
1177
+ }
1178
+ }, _class4.__initStatic4(), _class4);
463
1179
 
464
1180
  // src/charts/strategycharts/CustomerJourneyMap.ts
465
- var _d3 = require('d3');
1181
+
466
1182
  var CustomerJourneyStageMark = /* @__PURE__ */ ((CustomerJourneyStageMark2) => {
467
1183
  CustomerJourneyStageMark2["Chevron"] = "chevron";
468
1184
  CustomerJourneyStageMark2["Box"] = "box";
@@ -479,12 +1195,12 @@ var CustomerJourneyEmotionPlace = /* @__PURE__ */ ((CustomerJourneyEmotionPlace2
479
1195
  return CustomerJourneyEmotionPlace2;
480
1196
  })(CustomerJourneyEmotionPlace || {});
481
1197
  var GAP2 = 3;
482
- var HEAD = 22;
1198
+ var HEAD2 = 22;
483
1199
  var POINT = 5;
484
1200
  var PAD2 = 4;
485
1201
  var LANE_NAME = 10.5;
486
- var CustomerJourneyMap = (_class2 = class extends _chunkEEF5WRRZcjs.Chart2D {
487
- static __initStatic2() {this.meta = {
1202
+ var CustomerJourneyMap = (_class5 = class extends _chunkEEF5WRRZcjs.Chart2D {
1203
+ static __initStatic5() {this.meta = {
488
1204
  id: "customer-journey-map",
489
1205
  name: "Customer journey map",
490
1206
  family: "flow" /* Flow */,
@@ -532,21 +1248,21 @@ var CustomerJourneyMap = (_class2 = class extends _chunkEEF5WRRZcjs.Chart2D {
532
1248
  const felt = stages.some((stage) => stage.emotion !== null);
533
1249
  const gutter = Math.min(72, plot.width * 0.22), across = Math.max(0, plot.width - gutter - GAP2 * Math.max(0, stages.length - 1)) / Math.max(1, stages.length);
534
1250
  const columns = stages.map((stage, i) => ({ ...stage, x: gutter + i * (across + GAP2), width: across }));
535
- const body = Math.max(0, plot.height - HEAD - GAP2);
1251
+ const body = Math.max(0, plot.height - HEAD2 - GAP2);
536
1252
  const moodRoom = felt ? lanes.length ? Math.min(72, Math.max(34, body * 0.28)) : body : 0;
537
1253
  const laneRoom = lanes.length ? Math.max(0, body - moodRoom - GAP2 * (lanes.length - (felt ? 0 : 1))) / lanes.length : 0;
538
1254
  const top = emotionPlace === "top" /* Top */ && felt;
539
- const moodTop = top ? HEAD + GAP2 : HEAD + GAP2 + lanes.length * (laneRoom + GAP2);
540
- const laneTop = (i) => HEAD + GAP2 + (top ? moodRoom + GAP2 : 0) + i * (laneRoom + GAP2);
1255
+ const moodTop = top ? HEAD2 + GAP2 : HEAD2 + GAP2 + lanes.length * (laneRoom + GAP2);
1256
+ const laneTop = (i) => HEAD2 + GAP2 + (top ? moodRoom + GAP2 : 0) + i * (laneRoom + GAP2);
541
1257
  const header = (column, i) => {
542
1258
  const { x, width } = column, point = Math.min(POINT, width / 3), end = x + width;
543
- if (stageMark === "box" /* Box */) return `M${x + 3},0H${end - 3}Q${end},0 ${end},3V${HEAD - 3}Q${end},${HEAD} ${end - 3},${HEAD}H${x + 3}Q${x},${HEAD} ${x},${HEAD - 3}V3Q${x},0 ${x + 3},0Z`;
544
- const tip = i < columns.length - 1 ? `L${end + point},${HEAD / 2}L${end},${HEAD}` : `V${HEAD}`;
545
- return `M${x},0H${end}${tip}H${x}${i ? `L${x + point},${HEAD / 2}` : ""}Z`;
1259
+ if (stageMark === "box" /* Box */) return `M${x + 3},0H${end - 3}Q${end},0 ${end},3V${HEAD2 - 3}Q${end},${HEAD2} ${end - 3},${HEAD2}H${x + 3}Q${x},${HEAD2} ${x},${HEAD2 - 3}V3Q${x},0 ${x + 3},0Z`;
1260
+ const tip = i < columns.length - 1 ? `L${end + point},${HEAD2 / 2}L${end},${HEAD2}` : `V${HEAD2}`;
1261
+ return `M${x},0H${end}${tip}H${x}${i ? `L${x + point},${HEAD2 / 2}` : ""}Z`;
546
1262
  };
547
1263
  const heads = ctx.marks("stages", "path", columns, (column) => column.name).attr("fill", theme.axis);
548
1264
  ctx.set(heads, { d: header });
549
- ctx.hover(heads, (column) => ({ title: column.name, rows: [["Notes", [...column.notes.values()].reduce((sum, notes) => sum + notes.length, 0)], ...column.emotion === null ? [] : [["Emotion", +column.emotion.toFixed(2)]]] }));
1265
+ ctx.hover(heads, (column) => ({ title: column.name, rows: [["Notes", [...column.notes.values()].reduce((sum5, notes) => sum5 + notes.length, 0)], ...column.emotion === null ? [] : [["Emotion", +column.emotion.toFixed(2)]]] }));
550
1266
  const cells = lanes.flatMap((lane, row) => columns.map((column) => ({ key: `${lane}/${column.name}`, lane, column, x: column.x, y: laneTop(row), width: column.width, height: laneRoom, color: palette.color(lane) })));
551
1267
  const panels = ctx.marks("cells", "rect", cells, (cell) => cell.key).attr("rx", 3).attr("fill", (cell) => cell.color).attr("fill-opacity", 0.12);
552
1268
  ctx.set(panels, { x: (cell) => cell.x, y: (cell) => cell.y, width: (cell) => cell.width, height: (cell) => cell.height });
@@ -562,7 +1278,7 @@ var CustomerJourneyMap = (_class2 = class extends _chunkEEF5WRRZcjs.Chart2D {
562
1278
  const lined = emotionMark === "line" /* Line */;
563
1279
  const path = _d3.line.call(void 0, ).x((mood) => mood.x).y((mood) => mood.y).curve(_chunkPY4R3IFFcjs.Scales.curve("monotone" /* Monotone */));
564
1280
  const trace = ctx.marks("emotion-line", "path", lined && moods.length > 1 ? [moods] : []).attr("fill", "none").attr("stroke", theme.inkSecondary).attr("stroke-width", 2);
565
- ctx.set(trace, { d: (points) => _nullishCoalesce(path(points), () => ( "")) });
1281
+ ctx.set(trace, { d: (points2) => _nullishCoalesce(path(points2), () => ( "")) });
566
1282
  ctx.drawOn(trace);
567
1283
  const dots = ctx.marks("emotion-dots", "circle", lined ? moods : [], (mood) => mood.column.name).attr("fill", (mood) => mood.fill).attr("stroke", theme.surface).attr("stroke-width", 2);
568
1284
  ctx.set(dots, { cx: (mood) => mood.x, cy: (mood) => mood.y, r: 5 }, { r: 0 }, 30);
@@ -579,7 +1295,7 @@ var CustomerJourneyMap = (_class2 = class extends _chunkEEF5WRRZcjs.Chart2D {
579
1295
  const words = [
580
1296
  ...columns.map((column, i) => {
581
1297
  const lead = stageMark === "chevron" /* Chevron */ && i ? Math.min(POINT, column.width / 3) : 0;
582
- return { key: `stage/${column.name}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(column.name, column.width - lead - 2, 10.5), full: column.name, x: column.x + lead + (column.width - lead) / 2, y: HEAD / 2, anchor: "middle", size: 10.5, weight: 600, fill: palette.inkOn(theme.axis) };
1298
+ return { key: `stage/${column.name}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(column.name, column.width - lead - 2, 10.5), full: column.name, x: column.x + lead + (column.width - lead) / 2, y: HEAD2 / 2, anchor: "middle", size: 10.5, weight: 600, fill: palette.inkOn(theme.axis) };
583
1299
  }),
584
1300
  ...lanes.flatMap((lane, row) => laneWords(lane, laneTop(row), laneRoom, `lane/${lane}`)),
585
1301
  ...felt ? laneWords("Emotion", moodTop, moodRoom, "lane-emotion") : [],
@@ -597,7 +1313,7 @@ var CustomerJourneyMap = (_class2 = class extends _chunkEEF5WRRZcjs.Chart2D {
597
1313
  }));
598
1314
  StrategyNotes.draw(ctx, "notes", StrategyNotes.plan(lists, "plain"), "plain");
599
1315
  }
600
- }, _class2.__initStatic2(), _class2);
1316
+ }, _class5.__initStatic5(), _class5);
601
1317
 
602
1318
  // src/charts/strategycharts/EisenhowerMatrix.ts
603
1319
  var EisenhowerQuadrant = /* @__PURE__ */ ((EisenhowerQuadrant2) => {
@@ -625,12 +1341,12 @@ var KINDS = [
625
1341
  ];
626
1342
  var GAP3 = 6;
627
1343
  var RAIL = 18;
628
- var HEAD2 = 22;
1344
+ var HEAD3 = 22;
629
1345
  var SIDE = 128;
630
1346
  var PAD3 = 6;
631
1347
  var NOTE = 16;
632
- var EisenhowerMatrix = (_class3 = class _EisenhowerMatrix extends _chunkEEF5WRRZcjs.Chart2D {
633
- static __initStatic3() {this.meta = {
1348
+ var EisenhowerMatrix = (_class6 = class _EisenhowerMatrix extends _chunkEEF5WRRZcjs.Chart2D {
1349
+ static __initStatic6() {this.meta = {
634
1350
  id: "eisenhower-matrix",
635
1351
  name: "Eisenhower matrix",
636
1352
  family: "matrix" /* Matrix */,
@@ -695,16 +1411,16 @@ var EisenhowerMatrix = (_class3 = class _EisenhowerMatrix extends _chunkEEF5WRRZ
695
1411
  const panels = ctx.marks("panels", "rect", boxes, (box) => box.kind.quadrant).attr("rx", 4).attr("fill", (box) => box.color).attr("fill-opacity", 0.1);
696
1412
  ctx.set(panels, { x: (box) => box.x, y: (box) => box.y, width: (box) => box.width, height: (box) => box.height });
697
1413
  const bands = ctx.marks("bands", "rect", boxes, (box) => box.kind.quadrant).attr("rx", 4).attr("fill", (box) => box.color);
698
- ctx.set(bands, { x: (box) => box.x, y: (box) => box.y, width: (box) => box.side || box.width, height: (box) => box.side ? box.height : Math.min(HEAD2, box.height) });
1414
+ ctx.set(bands, { x: (box) => box.x, y: (box) => box.y, width: (box) => box.side || box.width, height: (box) => box.side ? box.height : Math.min(HEAD3, box.height) });
699
1415
  ctx.hover(bands, (box) => ({ title: box.kind.quadrant, color: box.color, rows: [["Tasks", box.tasks.length], [box.kind.why, ""]] }));
700
1416
  const headed = (box) => box.side || box.width;
701
1417
  const words = boxes.filter((box) => box.height >= 16).flatMap((box) => {
702
1418
  const ink = palette.inkOn(box.color), room = headed(box) - PAD3 * 2 - 20, name = _chunkQ5A2TY2Acjs.FrameworkText.fit(box.kind.quadrant, room, 12), left = box.x + PAD3;
703
1419
  const used = _chunkQ5A2TY2Acjs.FrameworkText.width(name, 12) + 8, why = _chunkQ5A2TY2Acjs.FrameworkText.fit(box.kind.why, box.side ? room + 20 : room - used, 10.5);
704
1420
  const title = { key: `title/${box.kind.quadrant}`, text: name, x: left, y: box.y + 11, size: 12, weight: 600, fill: ink };
705
- const count = { key: `count/${box.kind.quadrant}`, text: `${box.tasks.length}`, x: box.x + headed(box) - PAD3, y: box.y + 11, anchor: "end", size: 12, fill: ink };
1421
+ const count2 = { key: `count/${box.kind.quadrant}`, text: `${box.tasks.length}`, x: box.x + headed(box) - PAD3, y: box.y + 11, anchor: "end", size: 12, fill: ink };
706
1422
  const reason = box.side && box.height >= 38 ? [{ key: `why/${box.kind.quadrant}`, text: why, full: box.kind.why, x: left, y: box.y + 27, size: 10.5, fill: ink }] : !box.side && !framing && why === box.kind.why ? [{ key: `why/${box.kind.quadrant}`, text: why, x: left + used, y: box.y + 11, size: 10.5, fill: ink }] : [];
707
- return [title, ...headed(box) >= 70 ? [count] : [], ...reason];
1423
+ return [title, ...headed(box) >= 70 ? [count2] : [], ...reason];
708
1424
  });
709
1425
  if (rail) {
710
1426
  const columns = (frame.width - GAP3) / 2, rows = (frame.height - GAP3) / 2;
@@ -714,7 +1430,7 @@ var EisenhowerMatrix = (_class3 = class _EisenhowerMatrix extends _chunkEEF5WRRZ
714
1430
  if (skipped) words.push({ key: "note", text: _chunkQ5A2TY2Acjs.FrameworkText.fit(`${skipped} ${skipped === 1 ? "row" : "rows"} left out: no task, or urgent or important not stated`, plot.width, 10.5), x: 0, y: plot.height - 6, size: 10.5, tone: "muted" });
715
1431
  StrategyWords.draw(ctx, "words", words);
716
1432
  const lists = boxes.map((box) => {
717
- const top = box.side ? PAD3 : HEAD2 + PAD3 - 1;
1433
+ const top = box.side ? PAD3 : HEAD3 + PAD3 - 1;
718
1434
  return {
719
1435
  key: box.kind.quadrant,
720
1436
  color: box.color,
@@ -728,7 +1444,7 @@ var EisenhowerMatrix = (_class3 = class _EisenhowerMatrix extends _chunkEEF5WRRZ
728
1444
  const style = taskMark === "card" /* Card */ ? "card" : "bullet";
729
1445
  StrategyNotes.draw(ctx, "tasks", StrategyNotes.plan(lists, style), style);
730
1446
  }
731
- }, _class3.__initStatic3(), _class3);
1447
+ }, _class6.__initStatic6(), _class6);
732
1448
 
733
1449
  // src/charts/strategycharts/FiveForcesDiagram.ts
734
1450
 
@@ -759,12 +1475,12 @@ var KINDS2 = [
759
1475
  ];
760
1476
  var GAP4 = 20;
761
1477
  var PAD4 = 6;
762
- var HEAD3 = 18;
1478
+ var HEAD4 = 18;
763
1479
  var PIP = 6;
764
1480
  var METER = 32;
765
1481
  var WIDE = 1.7;
766
- var FiveForcesDiagram = (_class4 = class _FiveForcesDiagram extends _chunkEEF5WRRZcjs.Chart2D {
767
- static __initStatic4() {this.meta = {
1482
+ var FiveForcesDiagram = (_class7 = class _FiveForcesDiagram extends _chunkEEF5WRRZcjs.Chart2D {
1483
+ static __initStatic7() {this.meta = {
768
1484
  id: "five-forces",
769
1485
  name: "Five forces diagram",
770
1486
  family: "matrix" /* Matrix */,
@@ -856,7 +1572,7 @@ var FiveForcesDiagram = (_class4 = class _FiveForcesDiagram extends _chunkEEF5WR
856
1572
  const box = by.get(arrow.key);
857
1573
  return { title: `${box.rated.name} on rivalry`, color: box.color, rows: [["Strength", score(box)], ["Level", box.rated.level]] };
858
1574
  });
859
- const metered = (box) => box.width >= METER + 60 && box.height >= HEAD3;
1575
+ const metered = (box) => box.width >= METER + 60 && box.height >= HEAD4;
860
1576
  const pips = top <= 10 && Number.isInteger(top) ? top : 5, step = (METER + 2) / pips;
861
1577
  const marks = boxes.filter(metered).flatMap((box) => {
862
1578
  const left = box.x + box.width - PAD4 - METER, y = box.y + 6;
@@ -868,8 +1584,8 @@ var FiveForcesDiagram = (_class4 = class _FiveForcesDiagram extends _chunkEEF5WR
868
1584
  const words = boxes.flatMap((box) => {
869
1585
  const room = box.width - PAD4 * 2 - (metered(box) ? METER + 6 : 0), whole = _chunkQ5A2TY2Acjs.FrameworkText.fit(box.rated.name, room, 11);
870
1586
  const head2 = { key: `name/${box.rated.force}`, text: whole === box.rated.name ? whole : _chunkQ5A2TY2Acjs.FrameworkText.fit(box.kind.short, room, 11), full: box.rated.name, x: box.x + PAD4, y: box.y + 9, size: 11, weight: 600, tone: "ink" };
871
- if (drivers || box.height < HEAD3 + 30) return box.height < 16 ? [] : [head2];
872
- const middle = box.y + HEAD3 + (box.height - HEAD3) / 2;
1587
+ if (drivers || box.height < HEAD4 + 30) return box.height < 16 ? [] : [head2];
1588
+ const middle = box.y + HEAD4 + (box.height - HEAD4) / 2;
873
1589
  return [
874
1590
  head2,
875
1591
  { key: `score/${box.rated.force}`, text: box.rated.strength === null ? "n/a" : `${+box.rated.strength.toFixed(1)}`, x: box.x + box.width / 2, y: middle - 7, anchor: "middle", size: 18, weight: 600, tone: "ink" },
@@ -881,14 +1597,14 @@ var FiveForcesDiagram = (_class4 = class _FiveForcesDiagram extends _chunkEEF5WR
881
1597
  key: box.rated.force,
882
1598
  color: box.color,
883
1599
  x: box.x + PAD4,
884
- y: box.y + HEAD3,
1600
+ y: box.y + HEAD4,
885
1601
  width: Math.max(0, box.width - PAD4 * 2),
886
- height: Math.max(0, box.height - HEAD3 - 2),
1602
+ height: Math.max(0, box.height - HEAD4 - 2),
887
1603
  notes: box.rated.drivers.map((driver) => ({ text: driver.text, rows: [["Force", box.rated.name], ["Strength", driver.strength === null ? "Not rated" : `${driver.strength} of ${top}`]] }))
888
1604
  }));
889
1605
  StrategyNotes.draw(ctx, "drivers", StrategyNotes.plan(lists, "bullet"), "bullet");
890
1606
  }
891
- }, _class4.__initStatic4(), _class4);
1607
+ }, _class7.__initStatic7(), _class7);
892
1608
 
893
1609
  // src/charts/strategycharts/FootballFieldChart.ts
894
1610
 
@@ -902,11 +1618,11 @@ var FootballFieldOrder = /* @__PURE__ */ ((FootballFieldOrder2) => {
902
1618
  FootballFieldOrder2["Midpoint"] = "by-midpoint";
903
1619
  return FootballFieldOrder2;
904
1620
  })(FootballFieldOrder || {});
905
- var THICK = 22;
1621
+ var THICK2 = 22;
906
1622
  var END = 5;
907
1623
  var NOTE2 = 13;
908
- var FootballFieldChart = (_class5 = class _FootballFieldChart extends _chunkXX2YTCORcjs.CartesianChart {
909
- static __initStatic5() {this.meta = {
1624
+ var FootballFieldChart = (_class8 = class _FootballFieldChart extends _chunkXX2YTCORcjs.CartesianChart {
1625
+ static __initStatic8() {this.meta = {
910
1626
  id: "football-field",
911
1627
  name: "Football field valuation chart",
912
1628
  family: "financial" /* Financial */,
@@ -934,8 +1650,8 @@ var FootballFieldChart = (_class5 = class _FootballFieldChart extends _chunkXX2Y
934
1650
  price ??= StrategyRows.number(row[current]);
935
1651
  const a = StrategyRows.number(row[low]), b = StrategyRows.number(row[high]), name = _chunkQ5A2TY2Acjs.FrameworkText.clean(row[method]);
936
1652
  if (a === null || b === null || !name) continue;
937
- const held = spans.get(name), from = Math.min(a, b, _nullishCoalesce(_optionalChain([held, 'optionalAccess', _7 => _7.low]), () => ( Infinity))), to = Math.max(a, b, _nullishCoalesce(_optionalChain([held, 'optionalAccess', _8 => _8.high]), () => ( -Infinity)));
938
- spans.set(name, { method: name, group: _nullishCoalesce(_optionalChain([held, 'optionalAccess', _9 => _9.group]), () => ( (_chunkQ5A2TY2Acjs.FrameworkText.clean(row[group]) || "Range"))), low: from, high: to, middle: (from + to) / 2 });
1653
+ const held = spans.get(name), from = Math.min(a, b, _nullishCoalesce(_optionalChain([held, 'optionalAccess', _29 => _29.low]), () => ( Infinity))), to = Math.max(a, b, _nullishCoalesce(_optionalChain([held, 'optionalAccess', _30 => _30.high]), () => ( -Infinity)));
1654
+ spans.set(name, { method: name, group: _nullishCoalesce(_optionalChain([held, 'optionalAccess', _31 => _31.group]), () => ( (_chunkQ5A2TY2Acjs.FrameworkText.clean(row[group]) || "Range"))), low: from, high: to, middle: (from + to) / 2 });
939
1655
  }
940
1656
  const listed = [...spans.values()];
941
1657
  if (order === "by-midpoint" /* Midpoint */) listed.sort((a, b) => _d3.descending.call(void 0, a.middle, b.middle));
@@ -969,7 +1685,7 @@ var FootballFieldChart = (_class5 = class _FootballFieldChart extends _chunkXX2Y
969
1685
  plotMarks(ctx, { x, y }) {
970
1686
  const { mark, midpoint, consensus } = this.options, { palette, theme, plot } = ctx;
971
1687
  const { spans, current } = this.model;
972
- const thick = Math.min(THICK, y.bandwidth()), centre = (span) => (_nullishCoalesce(y(span.method), () => ( 0))) + y.bandwidth() / 2;
1688
+ const thick = Math.min(THICK2, y.bandwidth()), centre = (span) => (_nullishCoalesce(y(span.method), () => ( 0))) + y.bandwidth() / 2;
973
1689
  const reach = _nullishCoalesce(_d3.max.call(void 0, spans, (span) => Math.max(Math.abs(span.low), Math.abs(span.high))), () => ( 0)), text = this.#format(Math.max(reach, Math.abs(_nullishCoalesce(current, () => ( 0)))));
974
1690
  for (const span of spans) palette.color(span.group);
975
1691
  const tell = (span) => ({
@@ -1009,7 +1725,7 @@ var FootballFieldChart = (_class5 = class _FootballFieldChart extends _chunkXX2Y
1009
1725
  if (agreed) words.push({ ...headed(`Median range ${text(agreed[0])} to ${text(agreed[1])}`, (x(agreed[0]) + x(agreed[1])) / 2, current === null ? 0 : 1, "consensus"), weight: 400, tone: "secondary" });
1010
1726
  StrategyWords.draw(ctx, "labels", words);
1011
1727
  }
1012
- }, _class5.__initStatic5(), _class5);
1728
+ }, _class8.__initStatic8(), _class8);
1013
1729
 
1014
1730
  // src/charts/strategycharts/HypeCycleChart.ts
1015
1731
 
@@ -1017,10 +1733,10 @@ var FootballFieldChart = (_class5 = class _FootballFieldChart extends _chunkXX2Y
1017
1733
  // src/charts/strategycharts/StrategyLabels.ts
1018
1734
  var SIDES = ["right", "left", "above", "below"];
1019
1735
  var GAP5 = 4;
1020
- var LEAST = 5;
1736
+ var LEAST2 = 5;
1021
1737
  var hits = (a, b) => a.x0 < b.x1 && a.x1 > b.x0 && a.y0 < b.y1 && a.y1 > b.y0;
1022
1738
  var StrategyLabels = class {
1023
- static place(anchors, area3, size = 10.5, widest = 130, blocked = [], soft = []) {
1739
+ static place(anchors, area5, size = 10.5, widest = 130, blocked = [], soft = []) {
1024
1740
  const marks = anchors.map((anchor) => ({ x0: anchor.x - anchor.r, y0: anchor.y - anchor.r, x1: anchor.x + anchor.r, y1: anchor.y + anchor.r }));
1025
1741
  const boxed = (rect) => ({ x0: rect.x, y0: rect.y, x1: rect.x + rect.width, y1: rect.y + rect.height });
1026
1742
  const taken = blocked.map(boxed), lines = soft.map(boxed);
@@ -1030,15 +1746,15 @@ var StrategyLabels = class {
1030
1746
  const full = _chunkQ5A2TY2Acjs.FrameworkText.clean(anchor.text);
1031
1747
  if (!full || named.has(i)) return;
1032
1748
  for (const side of SIDES) {
1033
- const across = side === "right" ? area3.x + area3.width - anchor.x - anchor.r - GAP5 : side === "left" ? anchor.x - anchor.r - GAP5 - area3.x : Math.min(anchor.x - area3.x, area3.x + area3.width - anchor.x) * 2;
1749
+ const across = side === "right" ? area5.x + area5.width - anchor.x - anchor.r - GAP5 : side === "left" ? anchor.x - anchor.r - GAP5 - area5.x : Math.min(anchor.x - area5.x, area5.x + area5.width - anchor.x) * 2;
1034
1750
  const text = _chunkQ5A2TY2Acjs.FrameworkText.fit(full, Math.min(widest, across), size);
1035
- if (whole ? text !== full : text.length <= LEAST) continue;
1751
+ if (whole ? text !== full : text.length <= LEAST2) continue;
1036
1752
  const width = _chunkQ5A2TY2Acjs.FrameworkText.width(text, size), reach = anchor.r + GAP5;
1037
1753
  const x = side === "right" ? anchor.x + reach : side === "left" ? anchor.x - reach : anchor.x;
1038
1754
  const y = side === "above" ? anchor.y - reach - size / 2 : side === "below" ? anchor.y + reach + size / 2 : anchor.y;
1039
1755
  const x0 = side === "right" ? x : side === "left" ? x - width : x - width / 2;
1040
1756
  const box = { x0, y0: y - size / 2 - 1, x1: x0 + width, y1: y + size / 2 + 1 };
1041
- if (box.y0 < area3.y || box.y1 > area3.y + area3.height || box.x0 < area3.x || box.x1 > area3.x + area3.width) continue;
1757
+ if (box.y0 < area5.y || box.y1 > area5.y + area5.height || box.x0 < area5.x || box.x1 > area5.x + area5.width) continue;
1042
1758
  if (taken.some((other) => hits(box, other)) || marks.some((other, j) => j !== i && hits(box, other)) || clear && lines.some((other) => hits(box, other))) continue;
1043
1759
  taken.push(box);
1044
1760
  named.add(i);
@@ -1091,8 +1807,8 @@ var LIST_ROW = 13;
1091
1807
  var SYMBOL_AREA = 78;
1092
1808
  var SMALLEST = 4;
1093
1809
  var LARGEST = 11;
1094
- var HypeCycleChart = (_class6 = class _HypeCycleChart extends _chunkEEF5WRRZcjs.Chart2D {
1095
- static __initStatic6() {this.meta = {
1810
+ var HypeCycleChart = (_class9 = class _HypeCycleChart extends _chunkEEF5WRRZcjs.Chart2D {
1811
+ static __initStatic9() {this.meta = {
1096
1812
  id: "hype-cycle",
1097
1813
  name: "Hype cycle",
1098
1814
  family: "temporal" /* Temporal */,
@@ -1243,7 +1959,150 @@ var HypeCycleChart = (_class6 = class _HypeCycleChart extends _chunkEEF5WRRZcjs.
1243
1959
  if (over && rows) words.push({ key: "list-more", text: `+${placed.length - shown} more`, x: left + 20, y: frame.y + shown * LIST_ROW + LIST_ROW / 2, size: 10.5 });
1244
1960
  return words;
1245
1961
  }
1246
- }, _class6.__initStatic6(), _class6);
1962
+ }, _class9.__initStatic9(), _class9);
1963
+
1964
+ // src/charts/strategycharts/KanbanBoard.ts
1965
+
1966
+ var KanbanCardDetail = /* @__PURE__ */ ((KanbanCardDetail2) => {
1967
+ KanbanCardDetail2["Title"] = "title";
1968
+ KanbanCardDetail2["Full"] = "full";
1969
+ return KanbanCardDetail2;
1970
+ })(KanbanCardDetail || {});
1971
+ var GAP6 = 6;
1972
+ var HEAD5 = 20;
1973
+ var HEAD_LIMITS = 42;
1974
+ var METER2 = 21;
1975
+ var OVER = 33;
1976
+ var RAIL2 = 18;
1977
+ var PAD5 = 4;
1978
+ var CARD_GAP = 3;
1979
+ var INSET = 5;
1980
+ var EDGE = 4;
1981
+ var LEAD = 12;
1982
+ var SIZE3 = 10.5;
1983
+ var MORE = 11;
1984
+ var NARROWEST = 28;
1985
+ var KanbanBoard = (_class10 = class _KanbanBoard extends _chunkEEF5WRRZcjs.Chart2D {
1986
+ static __initStatic10() {this.meta = {
1987
+ id: "kanban-board",
1988
+ name: "Kanban board",
1989
+ family: "project" /* Project */,
1990
+ dimension: 2 /* Two */,
1991
+ shape: "table" /* Table */,
1992
+ description: "Sets task cards in a column per workflow stage, with each stage's work-in-progress limit on a meter and breached stages marked.",
1993
+ tags: ["kanban", "workflow", "wip limit", "task board", "swimlanes", "agile"],
1994
+ sample: (seed) => StrategySamples.kanban(seed),
1995
+ variants: {
1996
+ swimlanes: [false, true],
1997
+ cardDetail: ["title" /* Title */, "full" /* Full */],
1998
+ limits: [true, false]
1999
+ }
2000
+ }}
2001
+ /** How many of `count` cards, each `card` px tall, stack in `room` px. */
2002
+ static capacity(room, card, count2) {
2003
+ return Math.max(0, Math.min(count2, Math.floor((room + CARD_GAP) / (card + CARD_GAP))));
2004
+ }
2005
+ defaults() {
2006
+ return { task: "task", stage: "stage", limit: "limit", lane: "lane", group: "kind", owner: "owner", swimlanes: false, cardDetail: "title" /* Title */, limits: true };
2007
+ }
2008
+ plotMargin() {
2009
+ return { top: 8, right: 12, bottom: 8, left: 12 };
2010
+ }
2011
+ /** The stages in workflow order with their cards and limits, and the lanes in the order first seen. */
2012
+ get board() {
2013
+ const { task, stage, limit, lane, group, owner } = this.options;
2014
+ const stages = /* @__PURE__ */ new Map(), lanes = /* @__PURE__ */ new Set();
2015
+ for (const row of StrategyRows.of(this.options.data)) {
2016
+ const name = _chunkQ5A2TY2Acjs.FrameworkText.clean(row[stage]), title = _chunkQ5A2TY2Acjs.FrameworkText.clean(row[task]), cap = StrategyRows.number(row[limit]);
2017
+ if (!name) continue;
2018
+ const held = _nullishCoalesce(stages.get(name), () => ( { name, limit: null, cards: [], over: 0 }));
2019
+ stages.set(name, held);
2020
+ if (held.limit === null && cap !== null && cap >= 0) held.limit = cap;
2021
+ if (!title) continue;
2022
+ const card = { task: title, stage: name, lane: _chunkQ5A2TY2Acjs.FrameworkText.clean(row[lane]) || "No lane", group: _chunkQ5A2TY2Acjs.FrameworkText.clean(row[group]) || "Card", owner: _chunkQ5A2TY2Acjs.FrameworkText.clean(row[owner]) };
2023
+ lanes.add(card.lane);
2024
+ held.cards.push(card);
2025
+ }
2026
+ for (const held of stages.values()) held.over = held.limit === null ? 0 : Math.max(0, held.cards.length - held.limit);
2027
+ return { stages: [...stages.values()], lanes: [...lanes] };
2028
+ }
2029
+ /**
2030
+ * The card height in use and the height of each lane. Cards take the tallest of `sizes` at which every lane holds its
2031
+ * fullest stack, and lanes grow with their stacks. When no size fits, each lane is first given room for one card.
2032
+ */
2033
+ static lanes(stacks, sizes, free) {
2034
+ const need = (card2) => stacks.map((stack) => Math.max(1, stack) * (card2 + CARD_GAP) - CARD_GAP + PAD5 * 2);
2035
+ const card = _nullishCoalesce(_nullishCoalesce(sizes.find((size) => _d3.sum.call(void 0, need(size)) <= free), () => ( sizes.at(-1))), () => ( 0)), wanted = need(card), all = _d3.sum.call(void 0, wanted);
2036
+ if (all <= free) return { card, heights: wanted.map((height) => free * height / all) };
2037
+ const least = Math.min(card + PAD5 * 2, free / Math.max(1, stacks.length)), spare = free - least * stacks.length, short = all - least * stacks.length;
2038
+ return { card, heights: wanted.map((height) => least + (short > 0 ? spare * (height - least) / short : 0)) };
2039
+ }
2040
+ draw(ctx) {
2041
+ const { swimlanes, cardDetail, limits } = this.options, { plot, theme, palette } = ctx;
2042
+ const { stages, lanes } = this.board;
2043
+ const rows = swimlanes && lanes.length ? lanes : [null];
2044
+ const rail = rows[0] === null ? 0 : RAIL2, head = limits ? HEAD_LIMITS : HEAD5, full = cardDetail === "full" /* Full */;
2045
+ const wide = Math.max(0, plot.width - rail - GAP6 * (stages.length - 1)) / Math.max(1, stages.length);
2046
+ const held = (stage, lane) => stage.cards.filter((card) => lane === null || card.lane === lane);
2047
+ const size = (lines2) => INSET * 2 + lines2 * LEAD + (full ? LEAD : 0);
2048
+ const { card: height, heights } = _KanbanBoard.lanes(rows.map((lane) => _nullishCoalesce(_d3.max.call(void 0, stages, (stage) => held(stage, lane).length), () => ( 0))), [size(2), size(1)], Math.max(0, plot.height - head - GAP6 * (rows.length - 1)));
2049
+ const tops = heights.map((_, j) => head + _d3.sum.call(void 0, heights.slice(0, j)) + GAP6 * j), lines = height === size(2) ? 2 : 1;
2050
+ const cells = stages.flatMap((stage, i) => rows.map((lane, j) => ({ key: `${i}/${j}`, stage, lane, x: rail + i * (wide + GAP6), y: tops[j], width: wide, height: heights[j], cards: held(stage, lane) })));
2051
+ for (const stage of stages) for (const card of stage.cards) palette.color(card.group);
2052
+ const breached = (stage) => !!limits && stage.over > 0;
2053
+ const panels = ctx.marks("columns", "rect", cells, (cell) => cell.key).attr("rx", 4).attr("fill", (cell) => breached(cell.stage) ? theme.critical : theme.grid).attr("fill-opacity", (cell) => breached(cell.stage) ? 0.12 : 0.6);
2054
+ ctx.set(panels, { x: (cell) => cell.x, y: (cell) => cell.y, width: (cell) => cell.width, height: (cell) => cell.height });
2055
+ ctx.hover(panels, ({ stage, lane, cards: cards2 }) => ({
2056
+ title: lane === null ? stage.name : `${stage.name}, ${lane}`,
2057
+ rows: [["Cards here", cards2.length], ["Cards in stage", stage.cards.length], ["Limit", _nullishCoalesce(stage.limit, () => ( "None"))], ...stage.over ? [["Over the limit by", stage.over]] : []]
2058
+ }));
2059
+ const tally = (stage) => limits && stage.limit !== null ? `${stage.cards.length} / ${stage.limit}` : `${stage.cards.length}`;
2060
+ const metered = limits ? stages.map((stage, i) => ({ stage, x: rail + i * (wide + GAP6) + 4, width: Math.max(0, wide - 14 - _chunkQ5A2TY2Acjs.FrameworkText.width(tally(stage), SIZE3)) })).filter((meter) => meter.stage.limit !== null && meter.width >= 12) : [];
2061
+ const tracks = ctx.marks("axis-limits", "rect", metered, (meter) => meter.stage.name).attr("rx", 2.5).attr("fill", theme.grid);
2062
+ ctx.set(tracks, { x: (meter) => meter.x, y: METER2 - 2.5, width: (meter) => meter.width, height: 5 });
2063
+ const filled = ctx.marks("load", "rect", metered, (meter) => meter.stage.name).attr("rx", 2.5).attr("fill", (meter) => meter.stage.over ? theme.critical : theme.inkSecondary);
2064
+ const load = ({ stage, width }) => width * (stage.limit ? Math.min(1, stage.cards.length / stage.limit) : stage.cards.length ? 1 : 0);
2065
+ ctx.set(filled, { x: (meter) => meter.x, y: METER2 - 2.5, width: load, height: 5 }, { width: 0 }, 30);
2066
+ const flagged = limits ? stages.map((stage, i) => ({ stage, x: rail + i * (wide + GAP6) + 8 })).filter((flag) => flag.stage.over && wide >= 16) : [];
2067
+ const flags = ctx.marks("breaches", "path", flagged, (flag) => flag.stage.name).attr("fill", theme.critical);
2068
+ ctx.set(flags, { d: _nullishCoalesce(_d3.symbol.call(void 0, _d3.symbolTriangle, 40)(), () => ( "")), transform: (flag) => `translate(${flag.x},${OVER})` });
2069
+ const across = wide - PAD5 * 2, room = across - EDGE - 9;
2070
+ const words = [], more = [], hidden = /* @__PURE__ */ new Map();
2071
+ const placed = across < NARROWEST ? [] : cells.flatMap((cell) => {
2072
+ const inner = cell.height - PAD5 * 2, shown = _KanbanBoard.capacity(inner, height, cell.cards.length), left = cell.x + PAD5, rest = cell.cards.slice(shown);
2073
+ const tag = rest.length ? `+${rest.length}` : "", taken = tag ? _chunkQ5A2TY2Acjs.FrameworkText.width(tag, 9.5) + 5 : 0;
2074
+ if (rest.length) hidden.set(cell.key, rest);
2075
+ if (rest.length && !shown && inner >= MORE) more.push({ key: cell.key, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(`${tag} more`, across, 9.5), x: left + 2, y: cell.y + cell.height / 2, size: 9.5 });
2076
+ return cell.cards.slice(0, shown).map((card, k) => {
2077
+ const top = cell.y + PAD5 + k * (height + CARD_GAP), last = k === shown - 1 && !!tag, span = room - (last && !full ? taken : 0);
2078
+ const text = lines > 1 ? _chunkQ5A2TY2Acjs.FrameworkText.clamp(_chunkQ5A2TY2Acjs.FrameworkText.wrap(card.task, span, SIZE3), lines, span, SIZE3) : [_chunkQ5A2TY2Acjs.FrameworkText.fit(card.task, span, SIZE3)];
2079
+ if (full && card.owner) words.push({ key: `owner/${cell.key}/${k}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(card.owner, room - (last ? taken : 0), 9.5), full: card.owner, x: left + EDGE + 5, y: top + height - INSET - 5, size: 9.5 });
2080
+ if (last) more.push({ key: cell.key, text: tag, x: left + across - 4, y: full ? top + height - INSET - 5 : top + INSET + (lines - 1) * LEAD + 5.5, anchor: "end", size: 9.5, weight: 600 });
2081
+ return { key: `${cell.key}/${k}`, card, left, top, width: across, height, color: palette.color(card.group), lines: text, x: left + EDGE + 5, y: top + INSET + 9, lead: LEAD };
2082
+ });
2083
+ });
2084
+ const cards = ctx.marks("cards", "g", placed, (card) => card.key);
2085
+ ctx.hover(cards, ({ card }) => _chunkQ5A2TY2Acjs.FrameworkText.tip(card.task, [["Stage", card.stage], ["Lane", card.lane], ["Kind", card.group], ...card.owner ? [["Owner", card.owner]] : []], palette.color(card.group)));
2086
+ const faces = cards.selectAll("rect.face").data((card) => [card]).join("rect").attr("class", "face").attr("rx", 3).attr("fill", theme.surface);
2087
+ ctx.set(faces, { x: (card) => card.left, y: (card) => card.top, width: (card) => card.width, height: (card) => card.height });
2088
+ const edges = cards.selectAll("rect.kind").data((card) => [card]).join("rect").attr("class", "kind").attr("rx", 2).attr("fill", (card) => card.color);
2089
+ ctx.set(edges, { x: (card) => card.left, y: (card) => card.top, width: EDGE, height: (card) => card.height });
2090
+ const titles = ctx.text(cards.selectAll("text").data((card) => [card]).join("text"), SIZE3, "ink").attr("pointer-events", "none");
2091
+ _chunkQ5A2TY2Acjs.FrameworkText.write(ctx, titles);
2092
+ const beside = (stage) => _chunkQ5A2TY2Acjs.FrameworkText.width(tally(stage), SIZE3) + 8;
2093
+ const counted = stages.every((stage) => limits ? wide >= beside(stage) : _chunkQ5A2TY2Acjs.FrameworkText.width(stage.name, 11) + beside(stage) + 8 <= wide);
2094
+ for (const [i, stage] of stages.entries()) {
2095
+ const left = rail + i * (wide + GAP6), count2 = tally(stage);
2096
+ if (counted) words.push({ key: `count/${i}`, text: count2, x: left + wide - 4, y: limits ? METER2 : 8, anchor: "end", size: SIZE3, weight: breached(stage) ? 600 : 400, tone: breached(stage) ? "ink" : "secondary" });
2097
+ words.push({ key: `stage/${i}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(stage.name, wide - 8, 11), full: stage.name, x: left + 4, y: 8, size: 11, weight: 600, tone: "ink" });
2098
+ const over = [`Over by ${stage.over}`, `+${stage.over}`].find((text) => _chunkQ5A2TY2Acjs.FrameworkText.width(text, 10) <= wide - 18);
2099
+ if (breached(stage) && over) words.push({ key: `over/${i}`, text: over, x: left + 15, y: OVER, size: 10, weight: 600, tone: "ink" });
2100
+ }
2101
+ words.push(...rows.flatMap((lane, j) => lane === null ? [] : [{ key: `lane/${j}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(lane, heights[j], SIZE3), full: lane, x: RAIL2 / 2 - 3, y: tops[j] + heights[j] / 2, anchor: "middle", size: SIZE3, weight: 600, turned: true }]));
2102
+ StrategyWords.draw(ctx, "words", words);
2103
+ ctx.hover(StrategyWords.draw(ctx, "more", more), (word) => ({ title: `${_nullishCoalesce(_optionalChain([hidden, 'access', _32 => _32.get, 'call', _33 => _33(word.key), 'optionalAccess', _34 => _34.length]), () => ( 0))} more cards`, rows: (_nullishCoalesce(hidden.get(word.key), () => ( []))).map((card) => [_chunkQ5A2TY2Acjs.FrameworkText.fit(card.task, 260, 12), card.owner]) }));
2104
+ }
2105
+ }, _class10.__initStatic10(), _class10);
1247
2106
 
1248
2107
  // src/charts/strategycharts/KanoModelChart.ts
1249
2108
 
@@ -1277,8 +2136,8 @@ var SHAPES = {
1277
2136
  };
1278
2137
  var GUTTER2 = 16;
1279
2138
  var AREA = 80;
1280
- var KanoModelChart = (_class7 = class extends _chunkEEF5WRRZcjs.Chart2D {
1281
- static __initStatic7() {this.meta = {
2139
+ var KanoModelChart = (_class11 = class extends _chunkEEF5WRRZcjs.Chart2D {
2140
+ static __initStatic11() {this.meta = {
1282
2141
  id: "kano-model",
1283
2142
  name: "Kano model",
1284
2143
  family: "relationship" /* Relationship */,
@@ -1350,7 +2209,7 @@ var KanoModelChart = (_class7 = class extends _chunkEEF5WRRZcjs.Chart2D {
1350
2209
  words.push(...StrategyLabels.place(anchors, frame, 10.5, 130, [], traced));
1351
2210
  StrategyWords.draw(ctx, "words", words);
1352
2211
  }
1353
- }, _class7.__initStatic7(), _class7);
2212
+ }, _class11.__initStatic11(), _class11);
1354
2213
 
1355
2214
  // src/charts/strategycharts/NineBoxGrid.ts
1356
2215
 
@@ -1364,13 +2223,13 @@ var TALENT = [["Potential gem", "High potential", "Star"], ["Inconsistent player
1364
2223
  var TIERS = ["Low", "Medium", "High"];
1365
2224
  var WORDS = [[/^(l|low)$/, 0], [/^(m|med|medium|moderate)$/, 1], [/^(h|high)$/, 2]];
1366
2225
  var GUTTER3 = 28;
1367
- var GAP6 = 3;
1368
- var PAD5 = 5;
2226
+ var GAP7 = 3;
2227
+ var PAD6 = 5;
1369
2228
  var R = 5;
1370
2229
  var LARGEST2 = 13;
1371
2230
  var titled = (column) => column.charAt(0).toUpperCase() + column.slice(1);
1372
- var NineBoxGrid = (_class8 = class _NineBoxGrid extends _chunkEEF5WRRZcjs.Chart2D {
1373
- static __initStatic8() {this.meta = {
2231
+ var NineBoxGrid = (_class12 = class _NineBoxGrid extends _chunkEEF5WRRZcjs.Chart2D {
2232
+ static __initStatic12() {this.meta = {
1374
2233
  id: "nine-box-grid",
1375
2234
  name: "Nine-box grid",
1376
2235
  family: "matrix" /* Matrix */,
@@ -1406,10 +2265,10 @@ var NineBoxGrid = (_class8 = class _NineBoxGrid extends _chunkEEF5WRRZcjs.Chart2
1406
2265
  }
1407
2266
  /** Every row with both ratings, each with its cell and its ratings on the scale. A worded rating sits mid-cell. */
1408
2267
  get entries() {
1409
- const { item, performance, potential, group, size } = this.options, range5 = this.#range(), [low, high] = range5;
2268
+ const { item, performance, potential, group, size } = this.options, range6 = this.#range(), [low, high] = range6;
1410
2269
  const rating = (cell, third) => _nullishCoalesce(StrategyRows.number(cell), () => ( low + (third + 0.5) * (high - low) / 3));
1411
2270
  return StrategyRows.of(this.options.data).flatMap((row) => {
1412
- const column = _NineBoxGrid.third(row[performance], range5), tier = _NineBoxGrid.third(row[potential], range5);
2271
+ const column = _NineBoxGrid.third(row[performance], range6), tier = _NineBoxGrid.third(row[potential], range6);
1413
2272
  if (column === null || tier === null) return [];
1414
2273
  return [{
1415
2274
  name: _chunkQ5A2TY2Acjs.FrameworkText.clean(row[item]) || "Unnamed",
@@ -1427,15 +2286,15 @@ var NineBoxGrid = (_class8 = class _NineBoxGrid extends _chunkEEF5WRRZcjs.Chart2
1427
2286
  const { performance, potential, placement, sized, cellLabels, cellNames } = this.options, { plot, theme, palette } = ctx;
1428
2287
  const entries = this.entries, [low, high] = this.#range(), third = (high - low) / 3;
1429
2288
  const frame = { x: GUTTER3, y: 0, width: Math.max(1, plot.width - GUTTER3), height: Math.max(1, plot.height - GUTTER3) };
1430
- const wide = Math.max(0, frame.width - GAP6 * 2) / 3, tall = Math.max(0, frame.height - GAP6 * 2) / 3;
2289
+ const wide = Math.max(0, frame.width - GAP7 * 2) / 3, tall = Math.max(0, frame.height - GAP7 * 2) / 3;
1431
2290
  const names = _nullishCoalesce(cellNames, () => ( TALENT));
1432
2291
  const cells = [2, 1, 0].flatMap((tier) => [0, 1, 2].map((column) => ({
1433
2292
  key: `${column}/${tier}`,
1434
2293
  column,
1435
2294
  tier,
1436
- name: _chunkQ5A2TY2Acjs.FrameworkText.clean(_optionalChain([names, 'access', _10 => _10[2 - tier], 'optionalAccess', _11 => _11[column]])),
1437
- x: frame.x + column * (wide + GAP6),
1438
- y: frame.y + (2 - tier) * (tall + GAP6),
2295
+ name: _chunkQ5A2TY2Acjs.FrameworkText.clean(_optionalChain([names, 'access', _35 => _35[2 - tier], 'optionalAccess', _36 => _36[column]])),
2296
+ x: frame.x + column * (wide + GAP7),
2297
+ y: frame.y + (2 - tier) * (tall + GAP7),
1439
2298
  width: wide,
1440
2299
  height: tall,
1441
2300
  entries: entries.filter((entry) => entry.column === column && entry.tier === tier)
@@ -1451,10 +2310,10 @@ var NineBoxGrid = (_class8 = class _NineBoxGrid extends _chunkEEF5WRRZcjs.Chart2
1451
2310
  { key: "axis-x", text: _chunkQ5A2TY2Acjs.FrameworkText.fit(titled(performance), frame.width, 11), x: frame.x + frame.width / 2, y: plot.height - 6, anchor: "middle", weight: 600 },
1452
2311
  { key: "axis-y", text: _chunkQ5A2TY2Acjs.FrameworkText.fit(titled(potential), frame.height, 11), x: 6, y: frame.y + frame.height / 2, anchor: "middle", weight: 600, turned: true },
1453
2312
  ...TIERS.flatMap((text, i) => [
1454
- { key: `tier-x/${text}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(text, wide, 10), x: frame.x + i * (wide + GAP6) + wide / 2, y: frame.y + frame.height + 8, anchor: "middle", size: 10 },
1455
- { key: `tier-y/${text}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(text, tall, 10), x: 20, y: frame.y + (2 - i) * (tall + GAP6) + tall / 2, anchor: "middle", size: 10, turned: true }
2313
+ { key: `tier-x/${text}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(text, wide, 10), x: frame.x + i * (wide + GAP7) + wide / 2, y: frame.y + frame.height + 8, anchor: "middle", size: 10 },
2314
+ { key: `tier-y/${text}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(text, tall, 10), x: 20, y: frame.y + (2 - i) * (tall + GAP7) + tall / 2, anchor: "middle", size: 10, turned: true }
1456
2315
  ]),
1457
- ...labelled ? cells.map((cell) => ({ key: `cell/${cell.key}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(cell.name, cell.width - PAD5 * 2, 10), full: cell.name, x: cell.x + PAD5, y: cell.y + 9, size: 10, weight: 600 })) : []
2316
+ ...labelled ? cells.map((cell) => ({ key: `cell/${cell.key}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(cell.name, cell.width - PAD6 * 2, 10), full: cell.name, x: cell.x + PAD6, y: cell.y + 9, size: 10, weight: 600 })) : []
1458
2317
  ];
1459
2318
  const largest = _d3.max.call(void 0, entries, (entry) => Math.max(0, _nullishCoalesce(entry.size, () => ( 0)))) || 1;
1460
2319
  const dots = placement !== "scatter" /* Scatter */ ? [] : cells.flatMap((cell) => cell.entries.map((entry, i) => {
@@ -1471,7 +2330,7 @@ var NineBoxGrid = (_class8 = class _NineBoxGrid extends _chunkEEF5WRRZcjs.Chart2
1471
2330
  const marks = ctx.marks("placed", "circle", [...dots].sort((a, b) => b.r - a.r), (dot) => dot.key).attr("fill", (dot) => dot.fill).attr("stroke", theme.surface).attr("stroke-width", 2);
1472
2331
  ctx.set(marks, { cx: (dot) => dot.x, cy: (dot) => dot.y, r: (dot) => dot.r }, { r: 0 }, 15);
1473
2332
  ctx.hover(marks, (dot) => tell(dot.entry, dot.cell));
1474
- const headers = labelled ? cells.map((cell) => ({ x: cell.x, y: cell.y, width: Math.min(cell.width, _chunkQ5A2TY2Acjs.FrameworkText.width(cell.name, 10) + PAD5 * 2), height: head })) : [];
2333
+ const headers = labelled ? cells.map((cell) => ({ x: cell.x, y: cell.y, width: Math.min(cell.width, _chunkQ5A2TY2Acjs.FrameworkText.width(cell.name, 10) + PAD6 * 2), height: head })) : [];
1475
2334
  words.push(...StrategyLabels.place(dots.map((dot) => ({ key: `name/${dot.key}`, text: dot.entry.name, x: dot.x, y: dot.y, r: dot.r + 1 })), frame, 10, 90, headers));
1476
2335
  const counted = placement === "count" /* Count */ ? cells : [];
1477
2336
  const most = _d3.max.call(void 0, cells, (cell) => cell.entries.length) || 1, reach = Math.max(0, Math.min(wide, tall - head) / 2 - 3);
@@ -1494,15 +2353,180 @@ var NineBoxGrid = (_class8 = class _NineBoxGrid extends _chunkEEF5WRRZcjs.Chart2
1494
2353
  const lists = placement !== "list" /* List */ ? [] : cells.map((cell) => ({
1495
2354
  key: cell.key,
1496
2355
  color: theme.inkMuted,
1497
- x: cell.x + PAD5,
2356
+ x: cell.x + PAD6,
1498
2357
  y: cell.y + head + 3,
1499
- width: Math.max(0, cell.width - PAD5 * 2),
2358
+ width: Math.max(0, cell.width - PAD6 * 2),
1500
2359
  height: Math.max(0, cell.height - head - 6),
1501
2360
  notes: cell.entries.map((entry) => ({ text: entry.name, color: color(entry), rows: tell(entry, cell).rows }))
1502
2361
  }));
1503
2362
  StrategyNotes.draw(ctx, "names", StrategyNotes.plan(lists, "bullet"), "bullet");
1504
2363
  }
1505
- }, _class8.__initStatic8(), _class8);
2364
+ }, _class12.__initStatic12(), _class12);
2365
+
2366
+ // src/charts/strategycharts/OkrTree.ts
2367
+
2368
+ var OkrTreeLayout = /* @__PURE__ */ ((OkrTreeLayout2) => {
2369
+ OkrTreeLayout2["Tree"] = "tree";
2370
+ OkrTreeLayout2["List"] = "list";
2371
+ return OkrTreeLayout2;
2372
+ })(OkrTreeLayout || {});
2373
+ var OkrTreeRollup = /* @__PURE__ */ ((OkrTreeRollup2) => {
2374
+ OkrTreeRollup2["Mean"] = "mean";
2375
+ OkrTreeRollup2["Weakest"] = "weakest";
2376
+ return OkrTreeRollup2;
2377
+ })(OkrTreeRollup || {});
2378
+ var BAR = 6;
2379
+ var GROUP = 10;
2380
+ var INDENT2 = 18;
2381
+ var SIZE4 = 10.5;
2382
+ var FIGURE = 30;
2383
+ var PIP2 = 34;
2384
+ var LEVELS = [[0.7, "On track", "good"], [0.4, "At risk", "warning"], [-Infinity, "Off track", "critical"]];
2385
+ var OkrTree = (_class13 = class _OkrTree extends _chunkEEF5WRRZcjs.Chart2D {
2386
+ static __initStatic13() {this.meta = {
2387
+ id: "okr-tree",
2388
+ name: "OKR tree",
2389
+ family: "hierarchy" /* Hierarchy */,
2390
+ dimension: 2 /* Two */,
2391
+ shape: "table" /* Table */,
2392
+ description: "Lists objectives over their key results with a progress bar and confidence on each, and scores every objective from its key results.",
2393
+ tags: ["okr", "objectives", "key results", "goals", "progress", "planning"],
2394
+ sample: (seed) => StrategySamples.okr(seed),
2395
+ variants: {
2396
+ layout: ["tree" /* Tree */, "list" /* List */],
2397
+ rollup: ["mean" /* Mean */, "weakest" /* Weakest */],
2398
+ confidenceMarks: [true, false]
2399
+ }
2400
+ }}
2401
+ /** One score for several: their mean, or the lowest. Null when there are none. */
2402
+ static rollup(values, how = "mean" /* Mean */) {
2403
+ return _nullishCoalesce((how === "weakest" /* Weakest */ ? _d3.min.call(void 0, values) : _d3.mean.call(void 0, values)), () => ( null));
2404
+ }
2405
+ /** What a confidence from 0 to 1 is called: on track from 0.7, at risk from 0.4, off track below. */
2406
+ static status(confidence) {
2407
+ return LEVELS.find(([floor]) => confidence >= floor)[1];
2408
+ }
2409
+ defaults() {
2410
+ return { objective: "objective", keyResult: "keyResult", progress: "progress", confidence: "confidence", layout: "tree" /* Tree */, rollup: "mean" /* Mean */, confidenceMarks: true };
2411
+ }
2412
+ plotMargin() {
2413
+ return { top: 8, right: 12, bottom: 8, left: 12 };
2414
+ }
2415
+ /** Every objective is named where it is drawn. */
2416
+ legendItems() {
2417
+ return [];
2418
+ }
2419
+ /** The objectives in order, each scored from its key results. */
2420
+ get objectives() {
2421
+ const { objective, keyResult, progress, confidence, rollup } = this.options, rows = StrategyRows.of(this.options.data);
2422
+ const most = _nullishCoalesce(_d3.max.call(void 0, rows, (row) => _nullishCoalesce(StrategyRows.number(row[confidence]), () => ( 0))), () => ( 0)), unit = most <= 1 ? 1 : most <= 10 ? 10 : 100;
2423
+ const held = /* @__PURE__ */ new Map();
2424
+ for (const row of rows) {
2425
+ const name = _chunkQ5A2TY2Acjs.FrameworkText.clean(row[objective]), done = StrategyRows.number(row[progress]), sure = StrategyRows.number(row[confidence]);
2426
+ if (!name || done === null) continue;
2427
+ held.set(name, [..._nullishCoalesce(held.get(name), () => ( [])), { name: _chunkQ5A2TY2Acjs.FrameworkText.clean(row[keyResult]) || "Unnamed", progress: StrategyRows.clamp(done, 0, 100), confidence: sure === null ? null : StrategyRows.clamp(sure / unit, 0, 1) }]);
2428
+ }
2429
+ return [...held].map(([name, keyResults]) => ({
2430
+ name,
2431
+ keyResults,
2432
+ progress: _nullishCoalesce(_OkrTree.rollup(keyResults.map((result) => result.progress), rollup), () => ( 0)),
2433
+ confidence: _OkrTree.rollup(keyResults.flatMap((result) => _nullishCoalesce(result.confidence, () => ( []))), rollup)
2434
+ }));
2435
+ }
2436
+ draw(ctx) {
2437
+ const { theme } = ctx, parts = this.options.layout === "list" /* List */ ? this.#list(ctx) : this.#tree(ctx);
2438
+ const cards = ctx.marks("objectives", "rect", parts.cards, (card) => card.key).attr("rx", 4).attr("fill", (card) => card.color).attr("fill-opacity", 0.14);
2439
+ ctx.set(cards, { x: (card) => card.x, y: (card) => card.y, width: (card) => card.width, height: (card) => card.height });
2440
+ const links = ctx.marks("links", "path", parts.links, (link) => link.key).attr("fill", "none").attr("stroke", theme.axis).attr("stroke-width", 1.5);
2441
+ ctx.set(links, { d: (link) => link.d });
2442
+ const guides = ctx.marks("axis-guides", "path", parts.guides, (guide) => guide.key).attr("fill", "none").attr("stroke", theme.axis);
2443
+ ctx.set(guides, { d: (guide) => guide.d });
2444
+ const meters = ctx.marks("meters", "g", parts.meters, (meter) => meter.key);
2445
+ ctx.hover(meters, (meter) => meter.tip);
2446
+ const tracks = meters.selectAll("rect.track").data((meter) => [meter]).join("rect").attr("class", "track").attr("rx", BAR / 2).attr("fill", theme.grid);
2447
+ ctx.set(tracks, { x: (meter) => meter.x, y: (meter) => meter.y, width: (meter) => meter.width, height: BAR });
2448
+ const fills = meters.selectAll("rect.done").data((meter) => [meter]).join("rect").attr("class", "done").attr("rx", BAR / 2).attr("fill", (meter) => meter.color);
2449
+ ctx.set(fills, { x: (meter) => meter.x, y: (meter) => meter.y, width: (meter) => meter.width * meter.share, height: BAR }, { width: 0 }, 25);
2450
+ const pips = ctx.marks("confidence", "circle", parts.pips, (pip) => pip.key).attr("fill", (pip) => pip.color).attr("stroke", theme.surface).attr("stroke-width", 2);
2451
+ ctx.set(pips, { cx: (pip) => pip.x, cy: (pip) => pip.y, r: 4.5 }, { r: 0 }, 15);
2452
+ StrategyWords.draw(ctx, "words", parts.words);
2453
+ }
2454
+ /** Room after a bar for its percentage and, with confidence shown, its dot and figure. */
2455
+ get #trail() {
2456
+ return FIGURE + (this.options.confidenceMarks ? PIP2 : 0);
2457
+ }
2458
+ /** A bar from `x` across `width`, centred on `y`, with what follows it. */
2459
+ #meter(ctx, parts, key, item, color, x, y, width, tip, bold) {
2460
+ const { theme } = ctx, after = x + width + 6;
2461
+ parts.meters.push({ key, x, y: y - BAR / 2, width, height: BAR, share: item.progress / 100, color, tip });
2462
+ parts.words.push({ key: `done/${key}`, text: `${Math.round(item.progress)}%`, x: after, y, size: SIZE4, weight: bold ? 600 : 400, tone: "ink" });
2463
+ if (!this.options.confidenceMarks || item.confidence === null) return;
2464
+ const level = LEVELS.find(([floor]) => item.confidence >= floor);
2465
+ parts.pips.push({ key, x: after + FIGURE + 3, y, color: theme[level[2]] });
2466
+ parts.words.push({ key: `sure/${key}`, text: item.confidence.toFixed(1), x: after + FIGURE + 11, y, size: SIZE4 });
2467
+ }
2468
+ #tips(objective, color) {
2469
+ const sure = (item) => item.confidence === null ? [] : [["Confidence", `${item.confidence.toFixed(2)}, ${_OkrTree.status(item.confidence).toLowerCase()}`]];
2470
+ const how = this.options.rollup === "weakest" /* Weakest */ ? "weakest key result" : "mean of key results";
2471
+ return {
2472
+ own: _chunkQ5A2TY2Acjs.FrameworkText.tip(objective.name, [["Key results", objective.keyResults.length], [`Progress, ${how}`, `${Math.round(objective.progress)}%`], ...sure(objective)], color),
2473
+ of: (result) => _chunkQ5A2TY2Acjs.FrameworkText.tip(result.name, [["Progress", `${Math.round(result.progress)}%`], ...sure(result)], color)
2474
+ };
2475
+ }
2476
+ /** The objectives and the height of a row: with their key results while a row gets `least` px, and alone, as a list, in a plot too short for that. */
2477
+ #fitted(least, height) {
2478
+ const all = this.objectives, bare = all.map((objective) => ({ ...objective, keyResults: [] }));
2479
+ const rowOf = (list, units2) => Math.max(0, height - GROUP * (list.length - 1)) / Math.max(1, _d3.sum.call(void 0, list, units2));
2480
+ const units = this.options.layout === "list" /* List */ ? (objective) => objective.keyResults.length + 1 : (objective) => Math.max(1.4, objective.keyResults.length);
2481
+ const row = rowOf(all, units);
2482
+ return row >= least ? { shown: all, row } : { shown: bare, row: rowOf(bare, units) };
2483
+ }
2484
+ #tree(ctx) {
2485
+ const { plot, palette } = ctx, parts = { cards: [], links: [], guides: [], meters: [], pips: [], words: [] };
2486
+ const { shown, row: free } = this.#fitted(12, plot.height), row = Math.min(46, free), trail = this.#trail;
2487
+ if (!shown.some((objective) => objective.keyResults.length)) return this.#list(ctx);
2488
+ const left = Math.min(250, plot.width * 0.37), reach = Math.max(18, plot.width * 0.06), start = left + reach, across = Math.max(0, plot.width - start - trail - 6);
2489
+ let top = 0;
2490
+ shown.forEach((objective, i) => {
2491
+ const color = palette.color(objective.name), tips = this.#tips(objective, color), tall = Math.max(1.4, objective.keyResults.length) * row;
2492
+ const card = { key: `${i}`, color, x: 0, y: top + 2, width: left, height: Math.max(0, tall - 4) }, middle = top + tall / 2, room = left - 16;
2493
+ parts.cards.push(card);
2494
+ const barred = card.height >= 20 && room - trail >= 24, lines = Math.floor((card.height - 8 - (barred ? 14 : 0)) / 13);
2495
+ const name = _chunkQ5A2TY2Acjs.FrameworkText.clamp(_chunkQ5A2TY2Acjs.FrameworkText.wrap(objective.name, room, 11), Math.max(0, lines), room, 11), from = middle - (name.length * 13 + (barred ? 14 : 0)) / 2 + 6;
2496
+ parts.words.push(...name.map((text, line8) => ({ key: `objective/${i}/${line8}`, text, full: objective.name, x: 8, y: from + line8 * 13, size: 11, weight: 600, tone: "ink" })));
2497
+ if (barred) this.#meter(ctx, parts, `${i}`, objective, color, 8, from + name.length * 13 + 2, room - trail, tips.own, true);
2498
+ const first = top + (tall - objective.keyResults.length * row) / 2;
2499
+ objective.keyResults.forEach((result, k) => {
2500
+ const centre = first + (k + 0.5) * row, over = row >= 25, beside = over ? 0 : Math.round(across * 0.5), key = `${i}/${k}`;
2501
+ parts.links.push({ key, d: `M${left},${middle}C${left + reach * 0.55},${middle} ${left + reach * 0.45},${centre} ${start - 4},${centre}` });
2502
+ parts.words.push({ key: `result/${key}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(result.name, over ? plot.width - start : beside - 6, SIZE4), full: result.name, x: start, y: centre - (over ? 7 : 0), size: SIZE4, tone: "ink" });
2503
+ this.#meter(ctx, parts, key, result, color, start + beside, centre + (over ? 7 : 0), across - beside, tips.of(result), false);
2504
+ });
2505
+ top += tall + GROUP;
2506
+ });
2507
+ return parts;
2508
+ }
2509
+ #list(ctx) {
2510
+ const { plot, palette } = ctx, parts = { cards: [], links: [], guides: [], meters: [], pips: [], words: [] };
2511
+ const { shown, row: free } = this.#fitted(13, plot.height), row = Math.min(32, free), trail = this.#trail;
2512
+ const bar = Math.max(40, Math.min(220, plot.width * 0.3)), at = Math.max(0, plot.width - trail - 6 - bar), named = row >= 12;
2513
+ let top = 0;
2514
+ shown.forEach((objective, i) => {
2515
+ const color = palette.color(objective.name), tips = this.#tips(objective, color), head = top + row / 2;
2516
+ if (named) parts.words.push({ key: `objective/${i}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(objective.name, at - 10, 11.5), full: objective.name, x: 0, y: head, size: 11.5, weight: 600, tone: "ink" });
2517
+ this.#meter(ctx, parts, `${i}`, objective, color, at, head, bar, tips.own, true);
2518
+ const centres = objective.keyResults.map((_, k) => top + (k + 1.5) * row);
2519
+ if (centres.length) parts.guides.push({ key: `${i}`, d: `M6,${head + Math.min(9, row / 2)}V${centres.at(-1)}${centres.map((centre) => `M6,${centre}H${INDENT2 - 5}`).join("")}` });
2520
+ objective.keyResults.forEach((result, k) => {
2521
+ const key = `${i}/${k}`;
2522
+ parts.words.push({ key: `result/${key}`, text: _chunkQ5A2TY2Acjs.FrameworkText.fit(result.name, at - INDENT2 - 10, SIZE4), full: result.name, x: INDENT2, y: centres[k], size: SIZE4, tone: "ink" });
2523
+ this.#meter(ctx, parts, key, result, color, at, centres[k], bar, tips.of(result), false);
2524
+ });
2525
+ top += (objective.keyResults.length + 1) * row + GROUP;
2526
+ });
2527
+ return parts;
2528
+ }
2529
+ }, _class13.__initStatic13(), _class13);
1506
2530
 
1507
2531
  // src/charts/strategycharts/StrategyCanvasChart.ts
1508
2532
 
@@ -1514,8 +2538,8 @@ var StrategyCanvasOrder = /* @__PURE__ */ ((StrategyCanvasOrder2) => {
1514
2538
  })(StrategyCanvasOrder || {});
1515
2539
  var LABEL = 10;
1516
2540
  var ROWS = 2;
1517
- var StrategyCanvasChart = (_class9 = class _StrategyCanvasChart extends _chunkXX2YTCORcjs.CartesianChart {
1518
- static __initStatic9() {this.meta = {
2541
+ var StrategyCanvasChart = (_class14 = class _StrategyCanvasChart extends _chunkXX2YTCORcjs.CartesianChart {
2542
+ static __initStatic14() {this.meta = {
1519
2543
  id: "strategy-canvas",
1520
2544
  name: "Strategy canvas",
1521
2545
  family: "comparison" /* Comparison */,
@@ -1596,7 +2620,7 @@ var StrategyCanvasChart = (_class9 = class _StrategyCanvasChart extends _chunkXX
1596
2620
  });
1597
2621
  const band = _d3.area.call(void 0, ).x((point) => at(point.factor)).y0((point) => y(point.others)).y1((point) => y(point.value)).curve(_chunkPY4R3IFFcjs.Scales.curve(curve));
1598
2622
  const shade = ctx.marks("gap", "path", apart.length > 1 ? [apart] : []).attr("fill", focal ? palette.color(focal.offering) : "none").attr("fill-opacity", 0.16);
1599
- ctx.set(shade, { d: (points) => _nullishCoalesce(band(points), () => ( "")) });
2623
+ ctx.set(shade, { d: (points2) => _nullishCoalesce(band(points2), () => ( "")) });
1600
2624
  const path = _d3.line.call(void 0, ).x((point) => at(point.factor)).y((point) => y(point.value)).curve(_chunkPY4R3IFFcjs.Scales.curve(curve));
1601
2625
  const lines = ctx.marks("curves", "path", curves, (item) => item.offering).attr("fill", "none").attr("stroke", (item) => palette.color(item.offering)).attr("stroke-width", 2).attr("stroke-linejoin", "round");
1602
2626
  ctx.set(lines, { d: (item) => _nullishCoalesce(path(item.points), () => ( "")) });
@@ -1608,7 +2632,7 @@ var StrategyCanvasChart = (_class9 = class _StrategyCanvasChart extends _chunkXX
1608
2632
  const names = _StrategyCanvasChart.#names(factors, x.step()).flatMap((lines2, i) => lines2.flatMap((text, row) => text ? [{ key: `${factors[i]}/${row}`, text, full: factors[i], x: at(factors[i]), y: ctx.plot.height + 13 + row * 11, anchor: "middle", size: LABEL }] : []));
1609
2633
  StrategyWords.draw(ctx, "axis-factors", names);
1610
2634
  }
1611
- }, _class9.__initStatic9(), _class9);
2635
+ }, _class14.__initStatic14(), _class14);
1612
2636
 
1613
2637
  // src/charts/strategycharts/TechnologyAdoptionCurve.ts
1614
2638
 
@@ -1619,13 +2643,13 @@ var TechnologyAdoptionSegments = /* @__PURE__ */ ((TechnologyAdoptionSegments2)
1619
2643
  })(TechnologyAdoptionSegments || {});
1620
2644
  var SHARES = [["Innovators", 2.5], ["Early adopters", 13.5], ["Early majority", 34], ["Late majority", 34], ["Laggards", 16]];
1621
2645
  var REACH = 3.1;
1622
- var GAP7 = 18;
2646
+ var GAP8 = 18;
1623
2647
  var BELL = 0.8;
1624
2648
  var NAME_SIZE2 = 10;
1625
2649
  var SERIES = "Cumulative adoption";
1626
2650
  var density = (z) => Math.exp(-(z * z) / 2);
1627
- var TechnologyAdoptionCurve = (_class10 = class _TechnologyAdoptionCurve extends _chunkEEF5WRRZcjs.Chart2D {
1628
- static __initStatic10() {this.meta = {
2651
+ var TechnologyAdoptionCurve = (_class15 = class _TechnologyAdoptionCurve extends _chunkEEF5WRRZcjs.Chart2D {
2652
+ static __initStatic15() {this.meta = {
1629
2653
  id: "technology-adoption-curve",
1630
2654
  name: "Technology adoption curve",
1631
2655
  family: "distribution" /* Distribution */,
@@ -1682,7 +2706,7 @@ var TechnologyAdoptionCurve = (_class10 = class _TechnologyAdoptionCurve extends
1682
2706
  }
1683
2707
  draw(ctx) {
1684
2708
  const { item, adoption, segments, cumulative, chasm } = this.options, { plot, theme, palette } = ctx;
1685
- const groups = _TechnologyAdoptionCurve.groups(), gap = chasm ? GAP7 : 0, split = groups[1].to;
2709
+ const groups = _TechnologyAdoptionCurve.groups(), gap = chasm ? GAP8 : 0, split = groups[1].to;
1686
2710
  const right = cumulative ? 30 : 0;
1687
2711
  const scale = Math.max(1, plot.width - right - gap) / (REACH * 2);
1688
2712
  const names = groups.map((group) => _chunkQ5A2TY2Acjs.FrameworkText.clamp(_chunkQ5A2TY2Acjs.FrameworkText.wrap(group.name, (group.to - group.from) * scale - 4, NAME_SIZE2), 2, (group.to - group.from) * scale - 4, NAME_SIZE2));
@@ -1713,7 +2737,7 @@ var TechnologyAdoptionCurve = (_class10 = class _TechnologyAdoptionCurve extends
1713
2737
  ctx.set(baseline, { x1: 0, x2: frame.width, y1: bottom, y2: bottom });
1714
2738
  const climb = [...steps(-REACH, split).map((z) => [x(z, false), rise2(z)]), ...steps(split, REACH).map((z) => [x(z, true), rise2(z)])];
1715
2739
  const curve = ctx.marks("cumulative", "path", cumulative ? [climb] : []).attr("fill", "none").attr("stroke", stroke).attr("stroke-width", 2).attr("stroke-linecap", "round");
1716
- ctx.set(curve, { d: (points) => _nullishCoalesce(_d3.line.call(void 0, )(points), () => ( "")) });
2740
+ ctx.set(curve, { d: (points2) => _nullishCoalesce(_d3.line.call(void 0, )(points2), () => ( "")) });
1717
2741
  ctx.drawOn(curve);
1718
2742
  const marked = StrategyRows.of(this.options.data).flatMap((row, i) => {
1719
2743
  const share = StrategyRows.number(row[adoption]);
@@ -1747,7 +2771,7 @@ var TechnologyAdoptionCurve = (_class10 = class _TechnologyAdoptionCurve extends
1747
2771
  words.push(...StrategyLabels.place(anchors, frame, 10.5, 140, [...under, ...titled2], traced));
1748
2772
  StrategyWords.draw(ctx, "words", words);
1749
2773
  }
1750
- }, _class10.__initStatic10(), _class10);
2774
+ }, _class15.__initStatic15(), _class15);
1751
2775
 
1752
2776
  // src/charts/strategycharts/WardleyMap.ts
1753
2777
  var WardleyStages = /* @__PURE__ */ ((WardleyStages2) => {
@@ -1760,14 +2784,14 @@ var WardleyAxis = /* @__PURE__ */ ((WardleyAxis2) => {
1760
2784
  WardleyAxis2["Even"] = "even";
1761
2785
  return WardleyAxis2;
1762
2786
  })(WardleyAxis || {});
1763
- var STAGES = [{ name: "Genesis", to: 0.175 }, { name: "Custom built", to: 0.4 }, { name: "Product", to: 0.7 }, { name: "Commodity", to: 1 }];
2787
+ var STAGES2 = [{ name: "Genesis", to: 0.175 }, { name: "Custom built", to: 0.4 }, { name: "Product", to: 0.7 }, { name: "Commodity", to: 1 }];
1764
2788
  var GUTTER4 = 16;
1765
2789
  var R2 = 5;
1766
- var HEAD4 = 7;
2790
+ var HEAD6 = 7;
1767
2791
  var COMPONENT = "Component";
1768
2792
  var MOVEMENT = "Evolving";
1769
- var WardleyMap = (_class11 = class _WardleyMap extends _chunkEEF5WRRZcjs.Chart2D {
1770
- static __initStatic11() {this.meta = {
2793
+ var WardleyMap = (_class16 = class _WardleyMap extends _chunkEEF5WRRZcjs.Chart2D {
2794
+ static __initStatic16() {this.meta = {
1771
2795
  id: "wardley-map",
1772
2796
  name: "Wardley map",
1773
2797
  family: "network" /* Network */,
@@ -1784,12 +2808,12 @@ var WardleyMap = (_class11 = class _WardleyMap extends _chunkEEF5WRRZcjs.Chart2D
1784
2808
  }}
1785
2809
  /** The stage of evolution that holds `evolution`, 0 to 1. */
1786
2810
  static stage(evolution) {
1787
- return (_nullishCoalesce(STAGES.find((stage) => evolution < stage.to), () => ( STAGES[STAGES.length - 1]))).name;
2811
+ return (_nullishCoalesce(STAGES2.find((stage) => evolution < stage.to), () => ( STAGES2[STAGES2.length - 1]))).name;
1788
2812
  }
1789
2813
  /** Where `evolution` falls when the four stages are drawn equally wide, 0 to 1. */
1790
2814
  static even(evolution) {
1791
- const at = StrategyRows.clamp(evolution, 0, 1), index = Math.max(0, STAGES.findIndex((stage) => at <= stage.to)), from = index ? STAGES[index - 1].to : 0;
1792
- return (index + (at - from) / (STAGES[index].to - from)) / STAGES.length;
2815
+ const at = StrategyRows.clamp(evolution, 0, 1), index = Math.max(0, STAGES2.findIndex((stage) => at <= stage.to)), from = index ? STAGES2[index - 1].to : 0;
2816
+ return (index + (at - from) / (STAGES2[index].to - from)) / STAGES2.length;
1793
2817
  }
1794
2818
  defaults() {
1795
2819
  return { name: "name", visibility: "visibility", evolution: "evolution", evolveTo: "evolveTo", stages: "bands" /* Bands */, axis: "standard" /* Standard */, movement: true };
@@ -1801,15 +2825,15 @@ var WardleyMap = (_class11 = class _WardleyMap extends _chunkEEF5WRRZcjs.Chart2D
1801
2825
  get model() {
1802
2826
  const { data, name, visibility, evolution, evolveTo } = this.options;
1803
2827
  const byId = /* @__PURE__ */ new Map();
1804
- for (const node of StrategyRows.of(_optionalChain([data, 'optionalAccess', _12 => _12.nodes]))) {
2828
+ for (const node of StrategyRows.of(_optionalChain([data, 'optionalAccess', _37 => _37.nodes]))) {
1805
2829
  const id = _chunkQ5A2TY2Acjs.FrameworkText.clean(node.id), up = StrategyRows.number(node[visibility]), along = StrategyRows.number(node[evolution]), next = StrategyRows.number(node[evolveTo]);
1806
2830
  if (!id || byId.has(id) || up === null || along === null) continue;
1807
2831
  const at = StrategyRows.clamp(along, 0, 1);
1808
2832
  byId.set(id, { id, name: _chunkQ5A2TY2Acjs.FrameworkText.clean(node[name]) || id, visibility: StrategyRows.clamp(up, 0, 1), evolution: at, evolveTo: next === null ? null : StrategyRows.clamp(next, 0, 1), stage: _WardleyMap.stage(at), node });
1809
2833
  }
1810
2834
  const seen = /* @__PURE__ */ new Set();
1811
- const needs = StrategyRows.of(_optionalChain([data, 'optionalAccess', _13 => _13.links])).flatMap((link) => {
1812
- const from = byId.get(_chunkQ5A2TY2Acjs.FrameworkText.clean(link.source)), to = byId.get(_chunkQ5A2TY2Acjs.FrameworkText.clean(link.target)), key = `${_optionalChain([from, 'optionalAccess', _14 => _14.id])}>${_optionalChain([to, 'optionalAccess', _15 => _15.id])}`;
2835
+ const needs = StrategyRows.of(_optionalChain([data, 'optionalAccess', _38 => _38.links])).flatMap((link) => {
2836
+ const from = byId.get(_chunkQ5A2TY2Acjs.FrameworkText.clean(link.source)), to = byId.get(_chunkQ5A2TY2Acjs.FrameworkText.clean(link.target)), key = `${_optionalChain([from, 'optionalAccess', _39 => _39.id])}>${_optionalChain([to, 'optionalAccess', _40 => _40.id])}`;
1813
2837
  if (!from || !to || from === to || seen.has(key)) return [];
1814
2838
  seen.add(key);
1815
2839
  return [[from, to]];
@@ -1830,7 +2854,7 @@ var WardleyMap = (_class11 = class _WardleyMap extends _chunkEEF5WRRZcjs.Chart2D
1830
2854
  const bottom = frame.y + frame.height, inset = R2 + 3;
1831
2855
  const { components, needs } = this.model;
1832
2856
  const spots = new Map(components.map((item) => [item, { ...item, x: along(item.evolution), y: frame.y + inset + (1 - item.visibility) * (frame.height - inset * 2) }]));
1833
- const spans = STAGES.map((stage, i) => ({ name: stage.name, from: along(i ? STAGES[i - 1].to : 0), to: along(stage.to) }));
2857
+ const spans = STAGES2.map((stage, i) => ({ name: stage.name, from: along(i ? STAGES2[i - 1].to : 0), to: along(stage.to) }));
1834
2858
  const bands = ctx.marks("stage-bands", "rect", stages === "bands" /* Bands */ ? spans.filter((_, i) => i % 2 === 0) : [], (span) => span.name).attr("fill", theme.grid).attr("fill-opacity", 0.55);
1835
2859
  ctx.set(bands, { x: (span) => span.from, y: frame.y, width: (span) => span.to - span.from, height: frame.height });
1836
2860
  const rules = ctx.marks("stage-rules", "line", stages === "rules" /* Rules */ ? spans.slice(1) : [], (span) => span.name).attr("stroke", theme.axis).attr("stroke-dasharray", "3 3");
@@ -1845,13 +2869,13 @@ var WardleyMap = (_class11 = class _WardleyMap extends _chunkEEF5WRRZcjs.Chart2D
1845
2869
  const moves = !movement ? [] : [...spots.values()].flatMap((spot) => {
1846
2870
  if (spot.evolveTo === null) return [];
1847
2871
  const target = along(spot.evolveTo), way = Math.sign(target - spot.x);
1848
- return Math.abs(target - spot.x) > R2 + HEAD4 + 2 ? [{ key: spot.id, spot, x1: spot.x + way * (R2 + 2), x2: target }] : [];
2872
+ return Math.abs(target - spot.x) > R2 + HEAD6 + 2 ? [{ key: spot.id, spot, x1: spot.x + way * (R2 + 2), x2: target }] : [];
1849
2873
  });
1850
2874
  const heading = moves.length ? palette.color(MOVEMENT) : fill;
1851
2875
  const arrows = ctx.marks("movement", "line", moves, (move) => move.key).attr("stroke", heading).attr("stroke-width", 2).attr("stroke-dasharray", "4 3");
1852
- ctx.set(arrows, { x1: (move) => move.x1, x2: (move) => move.x2 - Math.sign(move.x2 - move.x1) * HEAD4, y1: (move) => move.spot.y, y2: (move) => move.spot.y });
2876
+ ctx.set(arrows, { x1: (move) => move.x1, x2: (move) => move.x2 - Math.sign(move.x2 - move.x1) * HEAD6, y1: (move) => move.spot.y, y2: (move) => move.spot.y });
1853
2877
  const heads = ctx.marks("movement-heads", "path", moves, (move) => move.key).attr("fill", heading);
1854
- ctx.set(heads, { d: `M0,0L${-HEAD4},${-HEAD4 / 2}V${HEAD4 / 2}Z`, transform: (move) => `translate(${move.x2},${move.spot.y})${move.x2 < move.x1 ? " rotate(180)" : ""}` });
2878
+ ctx.set(heads, { d: `M0,0L${-HEAD6},${-HEAD6 / 2}V${HEAD6 / 2}Z`, transform: (move) => `translate(${move.x2},${move.spot.y})${move.x2 < move.x1 ? " rotate(180)" : ""}` });
1855
2879
  const moved = (move) => ({ title: move.spot.name, color: heading, rows: [["Now", move.spot.stage], ["Heading for", _WardleyMap.stage(move.spot.evolveTo)]] });
1856
2880
  ctx.hover(arrows, moved);
1857
2881
  ctx.hover(heads, moved);
@@ -1871,12 +2895,12 @@ var WardleyMap = (_class11 = class _WardleyMap extends _chunkEEF5WRRZcjs.Chart2D
1871
2895
  ];
1872
2896
  const traced = [
1873
2897
  ...links.flatMap((link) => Array.from({ length: 9 }, (_, i) => ({ x: link.from.x + (link.to.x - link.from.x) * (i + 1) / 10 - 2, y: link.from.y + (link.to.y - link.from.y) * (i + 1) / 10 - 2, width: 4, height: 4 }))),
1874
- ...moves.map((move) => ({ x: Math.min(move.x1, move.x2), y: move.spot.y - HEAD4 / 2, width: Math.abs(move.x2 - move.x1), height: HEAD4 }))
2898
+ ...moves.map((move) => ({ x: Math.min(move.x1, move.x2), y: move.spot.y - HEAD6 / 2, width: Math.abs(move.x2 - move.x1), height: HEAD6 }))
1875
2899
  ];
1876
2900
  words.push(...StrategyLabels.place(placed.map((spot) => ({ key: `name/${spot.id}`, text: spot.name, x: spot.x, y: spot.y, r: R2 + 1 })), frame, 10.5, 120, [], traced));
1877
2901
  StrategyWords.draw(ctx, "words", words);
1878
2902
  }
1879
- }, _class11.__initStatic11(), _class11);
2903
+ }, _class16.__initStatic16(), _class16);
1880
2904
 
1881
2905
  // src/charts/strategycharts/index.ts
1882
2906
  var strategychartsCatalog = [
@@ -1890,7 +2914,12 @@ var strategychartsCatalog = [
1890
2914
  CustomerJourneyMap,
1891
2915
  EisenhowerMatrix,
1892
2916
  FootballFieldChart,
1893
- NineBoxGrid
2917
+ NineBoxGrid,
2918
+ CapTableChart,
2919
+ BurnRunwayChart,
2920
+ KanbanBoard,
2921
+ OkrTree,
2922
+ BassDiffusionChart
1894
2923
  ];
1895
2924
 
1896
2925
 
@@ -1932,4 +2961,17 @@ var strategychartsCatalog = [
1932
2961
 
1933
2962
 
1934
2963
 
1935
- exports.KanoCategory = KanoCategory; exports.BusinessModelCanvasKind = BusinessModelCanvasKind; exports.BusinessModelCanvasNotes = BusinessModelCanvasNotes; exports.BusinessModelCanvas = BusinessModelCanvas; exports.CustomerJourneyStageMark = CustomerJourneyStageMark; exports.CustomerJourneyEmotionMark = CustomerJourneyEmotionMark; exports.CustomerJourneyEmotionPlace = CustomerJourneyEmotionPlace; exports.CustomerJourneyMap = CustomerJourneyMap; exports.EisenhowerQuadrant = EisenhowerQuadrant; exports.EisenhowerLayout = EisenhowerLayout; exports.EisenhowerTaskMark = EisenhowerTaskMark; exports.EisenhowerMatrix = EisenhowerMatrix; exports.FiveForcesForce = FiveForcesForce; exports.FiveForcesRating = FiveForcesRating; exports.FiveForcesArrows = FiveForcesArrows; exports.FiveForcesDiagram = FiveForcesDiagram; exports.FootballFieldMark = FootballFieldMark; exports.FootballFieldOrder = FootballFieldOrder; exports.FootballFieldChart = FootballFieldChart; exports.HypeCycleMarker = HypeCycleMarker; exports.HypeCyclePhases = HypeCyclePhases; exports.HypeCycleLabels = HypeCycleLabels; exports.HypeCycleChart = HypeCycleChart; exports.KanoCurveSet = KanoCurveSet; exports.KanoAxes = KanoAxes; exports.KanoMarker = KanoMarker; exports.KanoPlacement = KanoPlacement; exports.KanoModelChart = KanoModelChart; exports.NineBoxPlacement = NineBoxPlacement; exports.NineBoxGrid = NineBoxGrid; exports.StrategyCanvasOrder = StrategyCanvasOrder; exports.StrategyCanvasChart = StrategyCanvasChart; exports.TechnologyAdoptionSegments = TechnologyAdoptionSegments; exports.TechnologyAdoptionCurve = TechnologyAdoptionCurve; exports.WardleyStages = WardleyStages; exports.WardleyAxis = WardleyAxis; exports.WardleyMap = WardleyMap; exports.strategychartsCatalog = strategychartsCatalog;
2964
+
2965
+
2966
+
2967
+
2968
+
2969
+
2970
+
2971
+
2972
+
2973
+
2974
+
2975
+
2976
+
2977
+ exports.KanoCategory = KanoCategory; exports.BassDiffusionView = BassDiffusionView; exports.BassDiffusionChart = BassDiffusionChart; exports.BurnRunwayBalance = BurnRunwayBalance; exports.BurnRunwayLayout = BurnRunwayLayout; exports.BurnRunwayChart = BurnRunwayChart; exports.BusinessModelCanvasKind = BusinessModelCanvasKind; exports.BusinessModelCanvasNotes = BusinessModelCanvasNotes; exports.BusinessModelCanvas = BusinessModelCanvas; exports.CapTableView = CapTableView; exports.CapTableBasis = CapTableBasis; exports.CapTableChart = CapTableChart; exports.CustomerJourneyStageMark = CustomerJourneyStageMark; exports.CustomerJourneyEmotionMark = CustomerJourneyEmotionMark; exports.CustomerJourneyEmotionPlace = CustomerJourneyEmotionPlace; exports.CustomerJourneyMap = CustomerJourneyMap; exports.EisenhowerQuadrant = EisenhowerQuadrant; exports.EisenhowerLayout = EisenhowerLayout; exports.EisenhowerTaskMark = EisenhowerTaskMark; exports.EisenhowerMatrix = EisenhowerMatrix; exports.FiveForcesForce = FiveForcesForce; exports.FiveForcesRating = FiveForcesRating; exports.FiveForcesArrows = FiveForcesArrows; exports.FiveForcesDiagram = FiveForcesDiagram; exports.FootballFieldMark = FootballFieldMark; exports.FootballFieldOrder = FootballFieldOrder; exports.FootballFieldChart = FootballFieldChart; exports.HypeCycleMarker = HypeCycleMarker; exports.HypeCyclePhases = HypeCyclePhases; exports.HypeCycleLabels = HypeCycleLabels; exports.HypeCycleChart = HypeCycleChart; exports.KanbanCardDetail = KanbanCardDetail; exports.KanbanBoard = KanbanBoard; exports.KanoCurveSet = KanoCurveSet; exports.KanoAxes = KanoAxes; exports.KanoMarker = KanoMarker; exports.KanoPlacement = KanoPlacement; exports.KanoModelChart = KanoModelChart; exports.NineBoxPlacement = NineBoxPlacement; exports.NineBoxGrid = NineBoxGrid; exports.OkrTreeLayout = OkrTreeLayout; exports.OkrTreeRollup = OkrTreeRollup; exports.OkrTree = OkrTree; exports.StrategyCanvasOrder = StrategyCanvasOrder; exports.StrategyCanvasChart = StrategyCanvasChart; exports.TechnologyAdoptionSegments = TechnologyAdoptionSegments; exports.TechnologyAdoptionCurve = TechnologyAdoptionCurve; exports.WardleyStages = WardleyStages; exports.WardleyAxis = WardleyAxis; exports.WardleyMap = WardleyMap; exports.strategychartsCatalog = strategychartsCatalog;