@diagrammo/dgmo 0.48.2 → 0.50.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 (244) hide show
  1. package/.cursorrules +12 -3
  2. package/.github/copilot-instructions.md +12 -3
  3. package/.windsurfrules +12 -3
  4. package/SKILL.md +12 -3
  5. package/dist/advanced.d.ts +851 -1
  6. package/dist/advanced.js +601 -177
  7. package/dist/auto.css +63 -0
  8. package/dist/auto.js +220 -110
  9. package/dist/auto.mjs +45920 -33167
  10. package/dist/block.css +63 -0
  11. package/dist/block.d.ts +13 -5
  12. package/dist/block.js +239 -62
  13. package/dist/{charts-d3-QOZHKTCT.js → charts-d3-DKUD7MQE.js} +9 -8
  14. package/dist/{chunk-3MQQNXPD.js → chunk-2C56LEML.js} +3 -3
  15. package/dist/{chunk-L66GEFB6.js → chunk-2JJ2KNPI.js} +4 -4
  16. package/dist/{chunk-6SM5NJQH.js → chunk-2QYTMIRR.js} +4 -4
  17. package/dist/{chunk-RJE5JTVK.js → chunk-3G6TMNVF.js} +7 -7
  18. package/dist/{chunk-MO5YHHMQ.js → chunk-3LKM6FMW.js} +2 -2
  19. package/dist/{chunk-76OWZ3BA.js → chunk-3P2DKJCG.js} +2 -2
  20. package/dist/chunk-3TDRHT4J.js +1043 -0
  21. package/dist/chunk-3XPUDB7B.js +420 -0
  22. package/dist/{chunk-2LACINWN.js → chunk-3ZPC476N.js} +7 -7
  23. package/dist/{chunk-G2H74XJZ.js → chunk-4BMJQFNK.js} +8 -8
  24. package/dist/{chunk-THXCFRTU.js → chunk-4S723I74.js} +9 -9
  25. package/dist/{chunk-6NYWYNBI.js → chunk-4XK3FLFB.js} +3 -3
  26. package/dist/chunk-5JSWBPZZ.js +607 -0
  27. package/dist/{chunk-WCT3NYCV.js → chunk-5LWQH6QV.js} +1 -1
  28. package/dist/{chunk-7DTWEFUE.js → chunk-5Z736BSU.js} +8 -8
  29. package/dist/{chunk-ERLBPDGU.js → chunk-6BFZKBGD.js} +2 -2
  30. package/dist/{chunk-6HO5ZTXK.js → chunk-6IAA2QQ2.js} +2 -2
  31. package/dist/{chunk-H6PI3KJT.js → chunk-6IUAK7RZ.js} +2 -2
  32. package/dist/{chunk-RTLBSQ3G.js → chunk-6M5PJFQG.js} +3 -3
  33. package/dist/{chunk-Z5CGSFJB.js → chunk-6X4AKWLF.js} +4 -4
  34. package/dist/{chunk-OJR3MQYV.js → chunk-6ZT4U37Q.js} +291 -52
  35. package/dist/{chunk-5QXL4NYS.js → chunk-7G2ER4CY.js} +10 -5
  36. package/dist/chunk-7PQYTZMA.js +681 -0
  37. package/dist/{chunk-OURHMODR.js → chunk-7RB5Q6MB.js} +11 -11
  38. package/dist/{chunk-YAA6IID3.js → chunk-7UEMZREK.js} +2 -2
  39. package/dist/{chunk-AN2MOO5T.js → chunk-A3WQVFBS.js} +3 -3
  40. package/dist/{chunk-VOKGH627.js → chunk-AHGF2YYA.js} +13 -3
  41. package/dist/{chunk-CI2G3OEB.js → chunk-ASS5YYIZ.js} +12 -12
  42. package/dist/{chunk-TYS6CSS5.js → chunk-BCYVE3N5.js} +2 -2
  43. package/dist/chunk-BDXC7MDK.js +2395 -0
  44. package/dist/chunk-BTUTZMPT.js +482 -0
  45. package/dist/{chunk-YGJTDXVR.js → chunk-C4GQDB5L.js} +2 -2
  46. package/dist/{chunk-Y2ZE3MSG.js → chunk-C63UWAKM.js} +2 -2
  47. package/dist/{chunk-725LDASD.js → chunk-CLD2OKV7.js} +2 -2
  48. package/dist/{chunk-WBRZJOEC.js → chunk-CMCR5WBW.js} +3 -3
  49. package/dist/{chunk-IZMRON6C.js → chunk-CVV36CWI.js} +2 -2
  50. package/dist/chunk-DMJJ3CEQ.js +254 -0
  51. package/dist/{chunk-MZSBFAPJ.js → chunk-EJTKV7CY.js} +9 -9
  52. package/dist/{chunk-FITOLXSX.js → chunk-EOFPYPAU.js} +26 -2
  53. package/dist/{chunk-X5LCYCL5.js → chunk-ER5SCQWQ.js} +5 -5
  54. package/dist/{chunk-4OHACBGX.js → chunk-F2L5GCQ4.js} +2 -2
  55. package/dist/{chunk-FCIIHT24.js → chunk-F5UDBSJY.js} +7 -7
  56. package/dist/{chunk-3JLKYGBQ.js → chunk-F7BFXWNQ.js} +2 -2
  57. package/dist/{chunk-FANX6UJR.js → chunk-FAL7NOK3.js} +11 -11
  58. package/dist/{chunk-BUPDIHML.js → chunk-FB2WHOEQ.js} +4 -4
  59. package/dist/chunk-FL4IOQ37.js +379 -0
  60. package/dist/{chunk-LIOHW36Z.js → chunk-GBE54KY6.js} +6 -5
  61. package/dist/{chunk-RUNNI6VE.js → chunk-GL5UZ6NY.js} +3 -3
  62. package/dist/{chunk-4GRI7MEB.js → chunk-GPWHQ5FJ.js} +6 -6
  63. package/dist/chunk-GROQGHCT.js +960 -0
  64. package/dist/{chunk-SGZYXELT.js → chunk-H73FP42Q.js} +9 -6
  65. package/dist/{chunk-PBAHEPLQ.js → chunk-HGN652MU.js} +7 -6
  66. package/dist/{chunk-3SMGIJDD.js → chunk-HHXOONLX.js} +13 -1
  67. package/dist/{chunk-QOOUC2J5.js → chunk-HQCHYB5F.js} +2 -2
  68. package/dist/{chunk-AELOBFW5.js → chunk-I4IFRCUB.js} +3 -3
  69. package/dist/{chunk-GMR5MFHJ.js → chunk-I7F2A35O.js} +2 -2
  70. package/dist/{chunk-T2OE3YQB.js → chunk-IA3FJYWR.js} +3 -3
  71. package/dist/chunk-IAEC4KLA.js +492 -0
  72. package/dist/chunk-IVKC4GID.js +32 -0
  73. package/dist/{chunk-HSH73DP6.js → chunk-JFYIP7XU.js} +139 -39
  74. package/dist/{chunk-CKNVO24D.js → chunk-JZNMXEIV.js} +2 -2
  75. package/dist/chunk-KJXIHOVL.js +940 -0
  76. package/dist/chunk-L2ZTFHAY.js +331 -0
  77. package/dist/{chunk-B7JUCQUA.js → chunk-M5RXSRO2.js} +4 -4
  78. package/dist/{chunk-ULOEATBZ.js → chunk-NFFIKVNO.js} +106 -29
  79. package/dist/{chunk-PZMETGLY.js → chunk-NISQC5KW.js} +358 -122
  80. package/dist/chunk-O4VUFXIH.js +574 -0
  81. package/dist/{chunk-RVMRZAPB.js → chunk-O76UD6VJ.js} +3 -3
  82. package/dist/{chunk-JM4LEPY3.js → chunk-O7NUCTFU.js} +2 -2
  83. package/dist/{chunk-JED6ZDEE.js → chunk-O7WP4ZD4.js} +2 -2
  84. package/dist/{chunk-EVCVDTXE.js → chunk-OHQEMBLI.js} +3 -3
  85. package/dist/{chunk-ZBWMSD5N.js → chunk-ONA5KPV3.js} +4 -4
  86. package/dist/{chunk-Y3J7VR52.js → chunk-OTAL43EH.js} +34 -2
  87. package/dist/{chunk-WCSOJFU3.js → chunk-OTP5KVLO.js} +3 -3
  88. package/dist/{chunk-RYEGFMUO.js → chunk-PGEGPSCZ.js} +2 -2
  89. package/dist/{chunk-ZO27FGJS.js → chunk-PH5X4GIP.js} +2 -2
  90. package/dist/{chunk-ZJEL4H2R.js → chunk-PJUGRJHJ.js} +9 -9
  91. package/dist/{chunk-ZGR7ULFJ.js → chunk-PLZI6KPM.js} +26 -14
  92. package/dist/{chunk-3R5POCTZ.js → chunk-PMN3Q7RJ.js} +6 -6
  93. package/dist/{chunk-YGJZWZTY.js → chunk-PZFVK3IH.js} +2 -2
  94. package/dist/chunk-Q4V4XQWV.js +158 -0
  95. package/dist/chunk-QDFNCATJ.js +325 -0
  96. package/dist/{chunk-QEBUY5NY.js → chunk-QFQ35BTO.js} +4 -4
  97. package/dist/chunk-QQJUTGQH.js +135 -0
  98. package/dist/{chunk-PWIHZ6NJ.js → chunk-QUJGFNFN.js} +4 -4
  99. package/dist/{chunk-J5FIXQRT.js → chunk-R56LASIN.js} +4 -4
  100. package/dist/{chunk-SRTU6HMQ.js → chunk-RV26LTUU.js} +8 -8
  101. package/dist/chunk-RV6A2B5S.js +354 -0
  102. package/dist/{chunk-EB6FPQUP.js → chunk-S5GRONXL.js} +3 -3
  103. package/dist/{chunk-5MLYVTYM.js → chunk-SCHXJTZL.js} +2 -2
  104. package/dist/{chunk-T3UBLACL.js → chunk-SCQ5VPUF.js} +19 -5
  105. package/dist/{chunk-PBHE5UG6.js → chunk-SGFZZAUO.js} +46 -12
  106. package/dist/{chunk-BUVJFRPY.js → chunk-SU2VBK4L.js} +4 -4
  107. package/dist/{chunk-SML67VPV.js → chunk-T4BRO3Z6.js} +3 -3
  108. package/dist/{chunk-NURGB5Z4.js → chunk-TSA237IM.js} +2 -2
  109. package/dist/chunk-TWCLK2GA.js +273 -0
  110. package/dist/{chunk-IJZFN3HM.js → chunk-TWQUYVP3.js} +4 -4
  111. package/dist/{chunk-DKEPS5LH.js → chunk-U2HGPLZS.js} +36 -2
  112. package/dist/{chunk-B65G5DNL.js → chunk-URSQLCTR.js} +3 -3
  113. package/dist/{chunk-ILKORZ3H.js → chunk-UUS2GIJZ.js} +7 -7
  114. package/dist/{chunk-XAKEUMEJ.js → chunk-UXOSVCLJ.js} +4 -4
  115. package/dist/{chunk-QLCCJEJI.js → chunk-WCUHAQKB.js} +2 -2
  116. package/dist/{chunk-WVAJFAIA.js → chunk-WWN566I7.js} +257 -101
  117. package/dist/{chunk-IPWPWM6R.js → chunk-X2NMFTG3.js} +111 -10
  118. package/dist/{chunk-UWN33VNX.js → chunk-XCLHOZAM.js} +10 -10
  119. package/dist/{chunk-P235SVAH.js → chunk-XDXNDSKO.js} +2 -2
  120. package/dist/chunk-XHVV4NVW.js +51 -0
  121. package/dist/{chunk-33LCUH4H.js → chunk-XMVQ5F4M.js} +4 -4
  122. package/dist/{chunk-MITI6NOL.js → chunk-YA7D2N2O.js} +11 -11
  123. package/dist/{chunk-7JEGTRLD.js → chunk-YB3FW24O.js} +3 -3
  124. package/dist/chunk-YNRDWYZP.js +295 -0
  125. package/dist/{chunk-44CM72SQ.js → chunk-YZLMKW4T.js} +3 -3
  126. package/dist/chunk-Z6XJQ6KO.js +452 -0
  127. package/dist/cli.cjs +179 -133
  128. package/dist/clock.d.ts +10 -0
  129. package/dist/clock.js +235 -0
  130. package/dist/countdown.d.ts +12 -0
  131. package/dist/countdown.js +450 -0
  132. package/dist/dgmo-router-QOMFCOOV.js +84 -0
  133. package/dist/dimensions-P5FSX2QN.js +22 -0
  134. package/dist/editor.js +43 -2
  135. package/dist/element.js +220 -110
  136. package/dist/element.mjs +45920 -33167
  137. package/dist/{flowchart-parser-ZNSKIBVR.js → flowchart-parser-OE4WHLTF.js} +4 -4
  138. package/dist/{flowchart-renderer-SNDSII4D.js → flowchart-renderer-GPCSMTOR.js} +8 -8
  139. package/dist/highlight.d.ts +17 -1
  140. package/dist/highlight.js +163 -6
  141. package/dist/index.d.ts +5 -1
  142. package/dist/index.js +199 -233
  143. package/dist/{layout-HRBZPFCN.js → layout-34CLNICW.js} +5 -5
  144. package/dist/layout-46366KBT.js +10 -0
  145. package/dist/{layout-HWDSRX5E.js → layout-5BG6DFCU.js} +6 -6
  146. package/dist/layout-6RDJHS6E.js +9 -0
  147. package/dist/{layout-7QXCNOVS.js → layout-7H4H46CS.js} +3 -3
  148. package/dist/{layout-46N4JJYK.js → layout-7SKMFYHL.js} +5 -5
  149. package/dist/{layout-EE6GE46Y.js → layout-DC4TVXER.js} +5 -5
  150. package/dist/layout-FGQWRYYW.js +14 -0
  151. package/dist/{layout-S2QBYSK2.js → layout-NXG63LWH.js} +3 -3
  152. package/dist/{layout-N76NR4ZO.js → layout-PUQCB6AN.js} +7 -7
  153. package/dist/{layout-HYZPWAK5.js → layout-QNUQLEHU.js} +3 -3
  154. package/dist/{layout-UM5F4DJB.js → layout-T3OZU5QW.js} +5 -5
  155. package/dist/layout-TJIWF7EM.js +14 -0
  156. package/dist/layout-VYELEAW7.js +14 -0
  157. package/dist/{layout-5RA6QWR6.js → layout-WZHNDT2O.js} +6 -6
  158. package/dist/{layout-search-OYV77HHS.js → layout-search-QS44PI5R.js} +6 -6
  159. package/dist/{parser-6BTRLKRZ.js → parser-45DENHFZ.js} +4 -4
  160. package/dist/{parser-TFZFBVWN.js → parser-4AI5ZN5F.js} +3 -3
  161. package/dist/{parser-XDVELHRK.js → parser-4P36TUVD.js} +4 -4
  162. package/dist/{parser-ZSDPZYQP.js → parser-5AURY4A6.js} +4 -4
  163. package/dist/{parser-N5O4IHUN.js → parser-A2BEFMGK.js} +4 -4
  164. package/dist/parser-B5FVS7O6.js +11 -0
  165. package/dist/{parser-NGU3ETO6.js → parser-C2HF2C2E.js} +4 -4
  166. package/dist/parser-CSFUN3CT.js +14 -0
  167. package/dist/{parser-TRTHDFPP.js → parser-D3QT6GWN.js} +5 -5
  168. package/dist/parser-D5637H5H.js +15 -0
  169. package/dist/{parser-VQP2UJ6W.js → parser-DFFEDKHH.js} +3 -3
  170. package/dist/parser-DOKMZXVZ.js +13 -0
  171. package/dist/parser-FMPCVFRK.js +15 -0
  172. package/dist/{parser-Y6WTBU76.js → parser-HYRTF3DO.js} +3 -3
  173. package/dist/{parser-I6KXEYFK.js → parser-I2UIJKVQ.js} +4 -4
  174. package/dist/{parser-O5J4VBII.js → parser-IBWNAPY4.js} +3 -3
  175. package/dist/{parser-PQ3POX45.js → parser-KUQWRPIT.js} +4 -4
  176. package/dist/{parser-2MFP2H2E.js → parser-LWKKBNSA.js} +3 -3
  177. package/dist/{parser-OV7NOBW6.js → parser-O4QFCUW7.js} +5 -5
  178. package/dist/{parser-IXSZZQHY.js → parser-PGMQDD4G.js} +4 -4
  179. package/dist/{parser-3STE62GB.js → parser-Q4QKCIWQ.js} +4 -4
  180. package/dist/parser-QTOB4KFL.js +14 -0
  181. package/dist/{parser-2EWECDSA.js → parser-QYYM4QVW.js} +4 -4
  182. package/dist/{parser-4OGOBJJ4.js → parser-RZMQP7MM.js} +4 -4
  183. package/dist/parser-RZPVAQVX.js +11 -0
  184. package/dist/parser-SOUJOEYI.js +13 -0
  185. package/dist/{parser-4FL2CMDG.js → parser-UQE5OWZI.js} +5 -5
  186. package/dist/{parser-NRAI6O25.js → parser-WAV5JRPT.js} +4 -4
  187. package/dist/{parser-KNSQSKQO.js → parser-YLKYBRIT.js} +5 -5
  188. package/dist/{parser-XKRP7QKP.js → parser-YS7TOS2K.js} +3 -3
  189. package/dist/{parser-AQETEVRW.js → parser-ZSOWUBML.js} +5 -5
  190. package/dist/{parser-CFZD5IBL.js → parser-ZTBATMLX.js} +4 -4
  191. package/dist/{renderer-VACVQYML.js → renderer-35HSIDMZ.js} +8 -8
  192. package/dist/{renderer-5MYBMBYO.js → renderer-4ITCHBT7.js} +5 -5
  193. package/dist/{renderer-CLJHQPBJ.js → renderer-67NPCBIS.js} +11 -11
  194. package/dist/{renderer-5NDVNDAZ.js → renderer-6GHYK7DX.js} +9 -9
  195. package/dist/{renderer-Z7I3W2PP.js → renderer-6RNGHC5Z.js} +8 -8
  196. package/dist/renderer-72LGR2YF.js +14 -0
  197. package/dist/{renderer-KQB7UGDS.js → renderer-7RH2SI3B.js} +3 -3
  198. package/dist/renderer-7SWMIFMM.js +21 -0
  199. package/dist/renderer-BBCEFILK.js +24 -0
  200. package/dist/{renderer-JGBKUCZD.js → renderer-BSW7SRIZ.js} +4 -4
  201. package/dist/{renderer-BYCNMBF7.js → renderer-BY533UWU.js} +11 -11
  202. package/dist/{renderer-6W5462RB.js → renderer-BZSBPTZJ.js} +9 -9
  203. package/dist/{renderer-7MVLWWQD.js → renderer-CXUC4KAD.js} +9 -9
  204. package/dist/{renderer-QIWVHWZO.js → renderer-DAXMXIKD.js} +3 -3
  205. package/dist/renderer-FZUKFUNZ.js +23 -0
  206. package/dist/renderer-G2NLGNKF.js +17 -0
  207. package/dist/renderer-GO3FE3RA.js +24 -0
  208. package/dist/{renderer-ZGNTUWC4.js → renderer-HPGR6USK.js} +8 -8
  209. package/dist/{renderer-UV6MI64M.js → renderer-HVCU2C3Z.js} +3 -3
  210. package/dist/renderer-ICJN2SA2.js +24 -0
  211. package/dist/{renderer-AWWAF6XD.js → renderer-INEXO7B6.js} +10 -10
  212. package/dist/{renderer-YY2OSF6E.js → renderer-KDYCFRBX.js} +8 -8
  213. package/dist/renderer-KY4KQBTF.js +19 -0
  214. package/dist/{renderer-B2OMQIQG.js → renderer-LBN65V45.js} +13 -13
  215. package/dist/{renderer-N43WR5GV.js → renderer-MGBWOCXG.js} +10 -10
  216. package/dist/{renderer-PGX2TKVS.js → renderer-O4JKUGKO.js} +8 -8
  217. package/dist/{renderer-4JHRUBE6.js → renderer-OOGFODWP.js} +10 -10
  218. package/dist/{renderer-6EEZHMH4.js → renderer-Q6ZKPLS6.js} +9 -9
  219. package/dist/{renderer-RPOA5YPZ.js → renderer-SZQ326M5.js} +12 -12
  220. package/dist/{renderer-ZRNG54CW.js → renderer-TKG6LS4U.js} +11 -11
  221. package/dist/{renderer-W4M6QLIJ.js → renderer-TQMZGDAX.js} +13 -13
  222. package/dist/renderer-radial-JELMHQ24.js +21 -0
  223. package/dist/{resolver-NOAA7ID7.js → resolver-FHBCO3PL.js} +3 -3
  224. package/dist/{state-parser-Z2V23ATR.js → state-parser-3REXRK3R.js} +4 -4
  225. package/dist/{state-renderer-B4DQBM6M.js → state-renderer-XYLNRWXR.js} +8 -8
  226. package/docs/ai-integration.md +12 -3
  227. package/docs/language-reference.md +429 -24
  228. package/gallery/fixtures/body.dgmo +17 -0
  229. package/gallery/fixtures/bracket.dgmo +30 -0
  230. package/gallery/fixtures/clock.dgmo +8 -0
  231. package/gallery/fixtures/countdown.dgmo +3 -0
  232. package/gallery/fixtures/family.dgmo +23 -0
  233. package/gallery/fixtures/goal.dgmo +4 -0
  234. package/gallery/fixtures/sketch.dgmo +22 -0
  235. package/package.json +12 -4
  236. package/dist/chunk-ODZVHU3R.js +0 -153
  237. package/dist/dgmo-router-X35VLZLM.js +0 -73
  238. package/dist/dimensions-J3FHIMJ6.js +0 -22
  239. package/dist/layout-5T6RH5M6.js +0 -14
  240. package/dist/layout-G23F7LDH.js +0 -9
  241. package/dist/layout-OB3RI63S.js +0 -14
  242. package/dist/parser-JAL2HD4I.js +0 -13
  243. package/dist/renderer-SMIBCRVB.js +0 -24
  244. package/dist/renderer-radial-C32GPJQ7.js +0 -21
@@ -0,0 +1,960 @@
1
+ import {
2
+ parseInlineMarkdown,
3
+ renderInlineText
4
+ } from "./chunk-3HDBAXF5.js";
5
+ import {
6
+ wrapDescriptionLines
7
+ } from "./chunk-BMR4CIEO.js";
8
+ import {
9
+ DAY_MS,
10
+ applyOrdinalTemplate,
11
+ formatCompound,
12
+ formatCount,
13
+ formatDateShort,
14
+ formatFooter,
15
+ formatHuman,
16
+ formatWordsDetail,
17
+ ordinalFor
18
+ } from "./chunk-YNRDWYZP.js";
19
+ import {
20
+ FONT_FAMILY
21
+ } from "./chunk-6KFWC4CO.js";
22
+ import {
23
+ getSeriesColors,
24
+ mix,
25
+ themeBaseBg
26
+ } from "./chunk-P6T66CCZ.js";
27
+ import {
28
+ resolveColor
29
+ } from "./chunk-TLVIHFRO.js";
30
+
31
+ // src/countdown/renderer.ts
32
+ import * as d3Selection from "d3-selection";
33
+ function bakedHero(parsed, now) {
34
+ const resolved = parsed.resolvedMs;
35
+ if (resolved === null) return "\u2014";
36
+ const remaining = resolved - now;
37
+ if (!parsed.rule && remaining <= 0) {
38
+ if (parsed.expired !== null) return parsed.expired;
39
+ const elapsed = -remaining;
40
+ if (elapsed <= 0) return "Now!";
41
+ if (parsed.units === "compound" || parsed.units === "human")
42
+ return `${formatCompound(resolved, now)} ago`;
43
+ const bu = parsed.units === "full" || parsed.units === "clock" ? "days" : parsed.units;
44
+ return `${formatCount(elapsed, { units: bu, round: parsed.round, fields: parsed.fields })} ago`;
45
+ }
46
+ if (parsed.rule && sameLocalDay(resolved, now))
47
+ return parsed.onDay ?? "Today!";
48
+ if (parsed.units === "human") {
49
+ const [hn, ht] = parsed.hasTime ? [now, resolved] : [DAY_START(now), DAY_START(resolved)];
50
+ return formatHuman(hn, ht).big;
51
+ }
52
+ if (parsed.units === "compound") return formatCompound(now, resolved);
53
+ const bakeUnits = parsed.units === "full" || parsed.units === "clock" ? "days" : parsed.units;
54
+ return formatCount(Math.max(0, remaining), {
55
+ units: bakeUnits,
56
+ round: parsed.round,
57
+ fields: parsed.fields
58
+ });
59
+ }
60
+ function sameLocalDay(a, b) {
61
+ const x = new Date(a);
62
+ const y = new Date(b);
63
+ return x.getFullYear() === y.getFullYear() && x.getMonth() === y.getMonth() && x.getDate() === y.getDate();
64
+ }
65
+ function stampRecur(sel, parsed) {
66
+ const r = parsed.rule;
67
+ if (!r) return;
68
+ sel.attr("data-dgmo-recur-kind", r.kind);
69
+ if (r.month !== void 0) sel.attr("data-dgmo-recur-month", r.month);
70
+ if (r.day !== void 0) sel.attr("data-dgmo-recur-day", r.day);
71
+ if (r.nth !== void 0) sel.attr("data-dgmo-recur-nth", r.nth);
72
+ if (r.weekday !== void 0) sel.attr("data-dgmo-recur-weekday", r.weekday);
73
+ sel.attr("data-dgmo-recur-hour", r.hour);
74
+ sel.attr("data-dgmo-recur-minute", r.minute);
75
+ sel.attr("data-dgmo-recur-allday", r.allDay ? "1" : "0");
76
+ if (r.intervalN !== void 0)
77
+ sel.attr("data-dgmo-recur-interval-n", r.intervalN);
78
+ if (r.intervalUnit !== void 0)
79
+ sel.attr("data-dgmo-recur-interval-unit", r.intervalUnit);
80
+ if (r.anchorMs !== void 0) sel.attr("data-dgmo-recur-anchor", r.anchorMs);
81
+ }
82
+ var MON_ABBR = [
83
+ "Jan",
84
+ "Feb",
85
+ "Mar",
86
+ "Apr",
87
+ "May",
88
+ "Jun",
89
+ "Jul",
90
+ "Aug",
91
+ "Sep",
92
+ "Oct",
93
+ "Nov",
94
+ "Dec"
95
+ ];
96
+ var WD_ABBR = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
97
+ var DAY_START = (ms) => {
98
+ const d = new Date(ms);
99
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
100
+ };
101
+ var dayDelta = (a, b) => Math.round((DAY_START(b) - DAY_START(a)) / DAY_MS);
102
+ var keyOf = (ms) => {
103
+ const d = new Date(ms);
104
+ return d.getFullYear() * 1e4 + d.getMonth() * 100 + d.getDate();
105
+ };
106
+ function bandColors(palette, accent, muted, faint) {
107
+ const blue = resolveColor("blue", palette) ?? mix(palette.text, palette.bg, 45);
108
+ const collides = accent.toLowerCase() === blue.toLowerCase();
109
+ const now = collides ? resolveColor("teal", palette) ?? resolveColor("cyan", palette) ?? mix(palette.text, palette.bg, 55) : blue;
110
+ const mid = mix(accent, now, 50);
111
+ return {
112
+ bg: palette.bg,
113
+ text: palette.text,
114
+ muted,
115
+ faint,
116
+ rule: mix(palette.text, palette.bg, 14),
117
+ now,
118
+ event: accent,
119
+ midSoft: mix(mid, palette.bg, 24),
120
+ inert: mix(palette.text, palette.bg, 7),
121
+ inertBorder: mix(palette.text, palette.bg, 22)
122
+ };
123
+ }
124
+ function roleStyle(C, role) {
125
+ switch (role) {
126
+ case "past":
127
+ return { fill: C.inert, stroke: C.inertBorder, text: C.faint };
128
+ case "future":
129
+ return { fill: C.inert, stroke: C.inertBorder, text: C.muted };
130
+ case "today":
131
+ return { fill: C.now, stroke: C.now, text: C.bg };
132
+ case "event":
133
+ return { fill: C.event, stroke: C.event, text: C.bg };
134
+ }
135
+ }
136
+ function gradStyle(C, frac) {
137
+ const t = Math.max(0, Math.min(1, frac));
138
+ const f = mix(C.event, C.now, Math.round(t * 100));
139
+ return { fill: f, stroke: f, text: C.bg };
140
+ }
141
+ function aText(svg, x, y, size, fill, weight, anchor, txt, extra) {
142
+ const t = svg.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", size).attr("font-weight", weight).attr("fill", fill).attr("font-family", FONT_FAMILY).attr("font-variant-numeric", "tabular-nums").text(txt);
143
+ if (extra) for (const k in extra) t.attr(k, extra[k]);
144
+ }
145
+ function aRect(svg, x, y, w, h, rx, fill, stroke, sw) {
146
+ const r = svg.append("rect").attr("x", x).attr("y", y).attr("width", w).attr("height", h).attr("rx", rx).attr("fill", fill);
147
+ if (stroke) r.attr("stroke", stroke).attr("stroke-width", sw ?? 1);
148
+ }
149
+ function aLine(svg, x1, y1, x2, y2, stroke, sw, opacity) {
150
+ const l = svg.append("line").attr("x1", x1).attr("y1", y1).attr("x2", x2).attr("y2", y2).attr("stroke", stroke).attr("stroke-width", sw);
151
+ if (opacity != null) l.attr("opacity", opacity);
152
+ }
153
+ function recurGlyph(svg, cx, cy, r, color) {
154
+ const sw = Math.max(1.5, r * 0.34);
155
+ const pt = (deg) => [
156
+ cx + r * Math.cos(deg * Math.PI / 180),
157
+ cy + r * Math.sin(deg * Math.PI / 180)
158
+ ];
159
+ for (const base of [0, 180]) {
160
+ const [x0, y0] = pt(base + 30);
161
+ const [x1, y1] = pt(base + 175);
162
+ svg.append("path").attr("d", `M ${x0} ${y0} A ${r} ${r} 0 0 1 ${x1} ${y1}`).attr("fill", "none").attr("stroke", color).attr("stroke-width", sw).attr("stroke-linecap", "round");
163
+ const tang = (base + 175 + 90) * Math.PI / 180;
164
+ const hl = r * 0.9;
165
+ svg.append("path").attr(
166
+ "d",
167
+ `M ${x1} ${y1} l ${Math.cos(tang + 2.5) * hl} ${Math.sin(tang + 2.5) * hl} M ${x1} ${y1} l ${Math.cos(tang - 2.5) * hl} ${Math.sin(tang - 2.5) * hl}`
168
+ ).attr("fill", "none").attr("stroke", color).attr("stroke-width", sw).attr("stroke-linecap", "round");
169
+ }
170
+ }
171
+ function haloRect(svg, x, y, w, h, rx, C) {
172
+ aRect(svg, x - 1, y - 1, w + 2, h + 2, rx + 1, "none", C.bg, 2);
173
+ aRect(svg, x - 3, y - 3, w + 6, h + 6, rx + 3, "none", C.event, 2);
174
+ }
175
+ function pickBand(nowMs, resolvedMs, hasTime) {
176
+ const days = dayDelta(nowMs, resolvedMs);
177
+ if (hasTime && days <= 0) return "clock";
178
+ if (days > 365) return "year";
179
+ if (days > 92) return "months";
180
+ if (days > 18) return "monthgrid";
181
+ if (days >= 1) return "weekstrip";
182
+ if (days === 0) return "today";
183
+ return "after";
184
+ }
185
+ function monthSpan(nowMs, resolvedMs) {
186
+ const n = new Date(nowMs);
187
+ const t = new Date(resolvedMs);
188
+ return (t.getFullYear() - n.getFullYear()) * 12 + (t.getMonth() - n.getMonth()) + 1;
189
+ }
190
+ var MONTH_TARGET_PX = 200;
191
+ function monthGridLayout(nowMs, resolvedMs, contentW) {
192
+ const now = new Date(nowMs);
193
+ const ev = new Date(resolvedMs);
194
+ const realSpan = monthSpan(nowMs, resolvedMs);
195
+ const shown = Math.max(realSpan, Math.round(contentW / MONTH_TARGET_PX));
196
+ const padBefore = Math.floor((shown - realSpan) / 2);
197
+ const nowMk = now.getFullYear() * 12 + now.getMonth();
198
+ const evMk = ev.getFullYear() * 12 + ev.getMonth();
199
+ const months = [];
200
+ const dim = [];
201
+ for (let i = 0; i < shown; i++) {
202
+ const d = new Date(now.getFullYear(), now.getMonth() - padBefore + i, 1);
203
+ const mk = d.getFullYear() * 12 + d.getMonth();
204
+ months.push(d);
205
+ dim.push(mk < nowMk || mk > evMk);
206
+ }
207
+ return { months, dim };
208
+ }
209
+ function bandHeightFor(kind, nowMs, resolvedMs, contentW) {
210
+ const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
211
+ switch (kind) {
212
+ case "year": {
213
+ const R = new Date(resolvedMs).getFullYear() - new Date(nowMs).getFullYear() + 1;
214
+ const yearW = 66;
215
+ const gap = 8;
216
+ const cellW = (contentW - yearW - 11 * gap) / 12;
217
+ const cellH = clamp(cellW * 0.6, 28, 44);
218
+ const rowGap = 12;
219
+ return R * cellH + (R - 1) * rowGap;
220
+ }
221
+ case "months": {
222
+ const realSpan = monthSpan(nowMs, resolvedMs);
223
+ const perRow = 6;
224
+ const shown = Math.max(perRow, Math.ceil(realSpan / perRow) * perRow);
225
+ const rows = shown / perRow;
226
+ const cellW = (contentW - 16 * (perRow - 1)) / perRow;
227
+ const cellH = clamp(cellW * 0.5, 58, 84);
228
+ return rows * cellH + (rows - 1) * 16;
229
+ }
230
+ case "monthgrid": {
231
+ const { months } = monthGridLayout(nowMs, resolvedMs, contentW);
232
+ const nM = months.length;
233
+ const mw = (contentW - 20 * (nM - 1)) / nM;
234
+ const cellW = (mw - 20) / 7;
235
+ const cellH = clamp(cellW * 0.8, 15, 22);
236
+ return 26 + 6 * cellH + 8;
237
+ }
238
+ case "weekstrip": {
239
+ const n = Math.max(7, dayDelta(nowMs, resolvedMs) + 1);
240
+ const cw = (contentW - 10 * (n - 1)) / n;
241
+ return clamp(cw * 1.5, 116, 170);
242
+ }
243
+ case "clock":
244
+ return clamp(contentW * 0.26, 150, 205);
245
+ case "today":
246
+ case "after":
247
+ return clamp(contentW * 0.22, 125, 170);
248
+ }
249
+ }
250
+ function vizYear(svg, g, nowMs, resolvedMs, C) {
251
+ const now = new Date(nowMs);
252
+ const ev = new Date(resolvedMs);
253
+ const y0 = now.getFullYear();
254
+ const y1 = ev.getFullYear();
255
+ const years = [];
256
+ for (let y = y0; y <= y1; y++) years.push(y);
257
+ const R = years.length;
258
+ const yearW = 66;
259
+ const gap = 8;
260
+ const rowGap = 12;
261
+ const rowH = (g.height - rowGap * (R - 1)) / R;
262
+ const cellH = rowH;
263
+ const cellW = (g.contentW - yearW - 11 * gap) / 12;
264
+ const nowY = now.getFullYear();
265
+ const nowM = now.getMonth();
266
+ const evY = ev.getFullYear();
267
+ const evM = ev.getMonth();
268
+ const nowOrd = nowY * 12 + nowM;
269
+ const evOrd = evY * 12 + evM;
270
+ years.forEach((yr, r) => {
271
+ const ry = g.top + r * (rowH + rowGap);
272
+ aText(
273
+ svg,
274
+ g.left + yearW - 12,
275
+ ry + rowH / 2,
276
+ Math.min(22, rowH * 0.6),
277
+ C.muted,
278
+ 800,
279
+ "end",
280
+ String(yr),
281
+ { "dominant-baseline": "central" }
282
+ );
283
+ for (let m = 0; m < 12; m++) {
284
+ const before = yr < nowY || yr === nowY && m < nowM;
285
+ const isNow = yr === nowY && m === nowM;
286
+ const isEv = yr === evY && m === evM;
287
+ const between = (yr > nowY || yr === nowY && m > nowM) && (yr < evY || yr === evY && m < evM);
288
+ const anchor = isEv || isNow;
289
+ const st = isEv ? roleStyle(C, "event") : isNow ? roleStyle(C, "today") : between ? gradStyle(C, (yr * 12 + m - nowOrd) / (evOrd - nowOrd)) : roleStyle(C, before ? "past" : "future");
290
+ const x = g.left + yearW + m * (cellW + gap);
291
+ const rx = Math.min(5, Math.min(cellW, cellH) * 0.22);
292
+ aRect(svg, x, ry, cellW, cellH, rx, st.fill, st.stroke, 1);
293
+ if (isEv) haloRect(svg, x, ry, cellW, cellH, rx, C);
294
+ const cx = x + cellW / 2;
295
+ const mFont = Math.min(11, cellW * 0.32);
296
+ if (anchor) {
297
+ aText(
298
+ svg,
299
+ cx,
300
+ ry + cellH * 0.36,
301
+ mFont,
302
+ st.text,
303
+ 700,
304
+ "middle",
305
+ MON_ABBR[m],
306
+ { "dominant-baseline": "central" }
307
+ );
308
+ const dnum = isEv ? ev.getDate() : now.getDate();
309
+ aText(
310
+ svg,
311
+ cx,
312
+ ry + cellH * 0.72,
313
+ Math.min(14, cellW * 0.42),
314
+ st.text,
315
+ 800,
316
+ "middle",
317
+ String(dnum),
318
+ { "dominant-baseline": "central" }
319
+ );
320
+ } else {
321
+ aText(
322
+ svg,
323
+ cx,
324
+ ry + cellH / 2,
325
+ mFont,
326
+ st.text,
327
+ 700,
328
+ "middle",
329
+ MON_ABBR[m],
330
+ { "dominant-baseline": "central" }
331
+ );
332
+ }
333
+ }
334
+ });
335
+ }
336
+ function vizMonths(svg, g, nowMs, resolvedMs, C) {
337
+ const now = new Date(nowMs);
338
+ const ev = new Date(resolvedMs);
339
+ const realSpan = monthSpan(nowMs, resolvedMs);
340
+ const perRow = 6;
341
+ const shown = Math.max(perRow, Math.ceil(realSpan / perRow) * perRow);
342
+ const padBefore = Math.floor((shown - realSpan) / 2);
343
+ const rows = shown / perRow;
344
+ const gap = 16;
345
+ const rowGap = 16;
346
+ const labelH = 27;
347
+ const cellW = (g.contentW - gap * (perRow - 1)) / perRow;
348
+ const cellH = (g.height - rowGap * (rows - 1)) / rows;
349
+ const nowMk = now.getFullYear() * 12 + now.getMonth();
350
+ const evMk = ev.getFullYear() * 12 + ev.getMonth();
351
+ for (let i = 0; i < shown; i++) {
352
+ const d = new Date(now.getFullYear(), now.getMonth() - padBefore + i, 1);
353
+ const mk = d.getFullYear() * 12 + d.getMonth();
354
+ const isNow = mk === nowMk;
355
+ const isEv = mk === evMk;
356
+ const isContext = mk < nowMk || mk > evMk;
357
+ const anchor = isNow || isEv;
358
+ const col = i % perRow;
359
+ const row = Math.floor(i / perRow);
360
+ const x = g.left + col * (cellW + gap);
361
+ const y = g.top + row * (cellH + rowGap);
362
+ const mt = isContext ? svg.append("g").attr("opacity", 0.42) : svg;
363
+ const st = isEv ? roleStyle(C, "event") : isNow ? roleStyle(C, "today") : mk > nowMk && mk < evMk ? gradStyle(C, (mk - nowMk) / (evMk - nowMk)) : roleStyle(C, mk < nowMk ? "past" : "future");
364
+ const rxM = Math.min(12, cellH * 0.14);
365
+ aRect(mt, x, y, cellW, cellH, rxM, st.fill, st.stroke, 1.25);
366
+ if (isEv) haloRect(mt, x, y, cellW, cellH, rxM, C);
367
+ aText(
368
+ mt,
369
+ x + cellW / 2,
370
+ y + 19,
371
+ 16,
372
+ st.text,
373
+ 700,
374
+ "middle",
375
+ MON_ABBR[d.getMonth()]
376
+ );
377
+ aLine(
378
+ mt,
379
+ x,
380
+ y + labelH,
381
+ x + cellW,
382
+ y + labelH,
383
+ st.text,
384
+ 1,
385
+ anchor ? 0.5 : 0.3
386
+ );
387
+ if (anchor) {
388
+ const dnum = isEv ? ev.getDate() : now.getDate();
389
+ const dFont = Math.min(cellH - labelH - 6, cellW * 0.42, 44);
390
+ aText(
391
+ mt,
392
+ x + cellW / 2,
393
+ y + labelH + (cellH - labelH) / 2 + 1,
394
+ dFont,
395
+ st.text,
396
+ 800,
397
+ "middle",
398
+ String(dnum),
399
+ { "dominant-baseline": "central" }
400
+ );
401
+ }
402
+ }
403
+ }
404
+ function vizMonthGrid(svg, g, nowMs, resolvedMs, C) {
405
+ const { months, dim: isContext } = monthGridLayout(
406
+ nowMs,
407
+ resolvedMs,
408
+ g.contentW
409
+ );
410
+ const nM = months.length;
411
+ const gap = 20;
412
+ const mw = (g.contentW - gap * (nM - 1)) / nM;
413
+ const padX = 10;
414
+ const gridLeft = padX;
415
+ const gridW = mw - 2 * padX;
416
+ const cols = 7;
417
+ const cellW = gridW / cols;
418
+ const top = g.top;
419
+ const headH = 26;
420
+ const cellH = (g.height - headH - 8) / 6;
421
+ const gridH = 6 * cellH;
422
+ const weekendShade = mix(C.text, C.bg, 8);
423
+ const todayKey = keyOf(nowMs);
424
+ const evKey = keyOf(resolvedMs);
425
+ months.forEach((m, mi) => {
426
+ const mt = isContext[mi] ? svg.append("g").attr("opacity", 0.42) : svg;
427
+ const mx = g.left + mi * (mw + gap);
428
+ aRect(mt, mx, top, mw, g.height, 14, C.inert, C.inertBorder, 1.25);
429
+ const gy = top + headH;
430
+ for (const wcol of [0, 6])
431
+ aRect(
432
+ mt,
433
+ mx + gridLeft + wcol * cellW,
434
+ gy,
435
+ cellW,
436
+ gridH,
437
+ 6,
438
+ weekendShade
439
+ );
440
+ aText(
441
+ mt,
442
+ mx + mw / 2,
443
+ top + 16,
444
+ 14,
445
+ C.text,
446
+ 700,
447
+ "middle",
448
+ `${MON_ABBR[m.getMonth()]} ${m.getFullYear()}`
449
+ );
450
+ aLine(mt, mx, top + headH - 6, mx + mw, top + headH - 6, C.rule, 1.25);
451
+ const first = new Date(m.getFullYear(), m.getMonth(), 1).getDay();
452
+ const dim = new Date(m.getFullYear(), m.getMonth() + 1, 0).getDate();
453
+ for (let day = 1; day <= dim; day++) {
454
+ const pos = first + day - 1;
455
+ const wk = Math.floor(pos / 7);
456
+ const dk = keyOf(new Date(m.getFullYear(), m.getMonth(), day).getTime());
457
+ const wd = pos % 7;
458
+ const cx = mx + gridLeft + wd * cellW;
459
+ const cy = gy + wk * cellH;
460
+ const isEvent = dk === evKey;
461
+ const isToday = dk === todayKey;
462
+ const between = dk > todayKey && dk < evKey;
463
+ const anchor = isEvent || isToday;
464
+ const dtMs = new Date(m.getFullYear(), m.getMonth(), day).getTime();
465
+ const st = isEvent ? roleStyle(C, "event") : isToday ? roleStyle(C, "today") : between ? gradStyle(C, dayDelta(nowMs, dtMs) / dayDelta(nowMs, resolvedMs)) : roleStyle(C, dk < todayKey ? "past" : "future");
466
+ if (anchor) {
467
+ const s = Math.min(cellW, cellH) * 1.02;
468
+ const sx = cx + (cellW - s) / 2;
469
+ const sy = cy + (cellH - s) / 2;
470
+ aRect(mt, sx, sy, s, s, 7, st.fill, st.stroke, 2);
471
+ if (isEvent) haloRect(mt, sx, sy, s, s, 7, C);
472
+ aText(
473
+ mt,
474
+ cx + cellW / 2,
475
+ cy + cellH / 2,
476
+ Math.min(16, cellH * 0.62),
477
+ st.text,
478
+ 750,
479
+ "middle",
480
+ String(day),
481
+ { "dominant-baseline": "central" }
482
+ );
483
+ } else {
484
+ const s = Math.min(cellW, cellH) * 0.5;
485
+ aRect(
486
+ mt,
487
+ cx + (cellW - s) / 2,
488
+ cy + (cellH - s) / 2,
489
+ s,
490
+ s,
491
+ Math.min(3, s * 0.3),
492
+ st.fill,
493
+ st.stroke,
494
+ 1
495
+ );
496
+ }
497
+ }
498
+ });
499
+ }
500
+ function vizWeekStrip(svg, g, nowMs, resolvedMs, C) {
501
+ const now = new Date(nowMs);
502
+ const nReal = dayDelta(nowMs, resolvedMs) + 1;
503
+ const n = Math.max(7, nReal);
504
+ const padBefore = Math.floor((n - nReal) / 2);
505
+ const gap = n <= 7 ? 14 : n <= 12 ? 10 : 7;
506
+ const cw = (g.contentW - gap * (n - 1)) / n;
507
+ const cellTop = g.top;
508
+ const ch = g.height;
509
+ const showWd = cw >= 30;
510
+ const showTag = cw >= 44;
511
+ const nowOrd = DAY_START(nowMs);
512
+ const evOrd = DAY_START(resolvedMs);
513
+ for (let i = 0; i < n; i++) {
514
+ const dt = new Date(
515
+ now.getFullYear(),
516
+ now.getMonth(),
517
+ now.getDate() + i - padBefore
518
+ );
519
+ const dtOrd = DAY_START(dt.getTime());
520
+ const x = g.left + i * (cw + gap);
521
+ const isToday = dtOrd === nowOrd;
522
+ const isEvent = dtOrd === evOrd;
523
+ const isContext = dtOrd < nowOrd || dtOrd > evOrd;
524
+ const st = isEvent ? roleStyle(C, "event") : isToday ? roleStyle(C, "today") : isContext ? roleStyle(C, dtOrd < nowOrd ? "past" : "future") : gradStyle(C, (dtOrd - nowOrd) / (evOrd - nowOrd));
525
+ const ct = isContext ? svg.append("g").attr("opacity", 0.5) : svg;
526
+ const sw = isToday || isEvent ? 2 : 1.25;
527
+ aRect(ct, x, cellTop, cw, ch, 14, st.fill, st.stroke, sw);
528
+ if (isEvent) haloRect(ct, x, cellTop, cw, ch, 14, C);
529
+ if (showWd) {
530
+ aText(
531
+ ct,
532
+ x + cw / 2,
533
+ cellTop + 18,
534
+ Math.min(12, cw * 0.3),
535
+ st.text,
536
+ 700,
537
+ "middle",
538
+ WD_ABBR[dt.getDay()],
539
+ { "letter-spacing": "0.04em" }
540
+ );
541
+ aLine(
542
+ ct,
543
+ x,
544
+ cellTop + 27,
545
+ x + cw,
546
+ cellTop + 27,
547
+ st.text,
548
+ 1,
549
+ isToday || isEvent ? 0.5 : 0.3
550
+ );
551
+ }
552
+ aText(
553
+ ct,
554
+ x + cw / 2,
555
+ cellTop + (showWd ? ch * 0.6 : ch * 0.54),
556
+ Math.min(44, cw * 0.62),
557
+ st.text,
558
+ 750,
559
+ "middle",
560
+ String(dt.getDate())
561
+ );
562
+ if (showTag && isToday)
563
+ aText(
564
+ ct,
565
+ x + cw / 2,
566
+ cellTop + ch - 13,
567
+ 10,
568
+ st.text,
569
+ 700,
570
+ "middle",
571
+ "TODAY",
572
+ { "letter-spacing": "0.04em" }
573
+ );
574
+ }
575
+ }
576
+ function vizToday(svg, g, resolvedMs, C) {
577
+ const ev = new Date(resolvedMs);
578
+ const cx = g.left + g.contentW / 2;
579
+ const cy = g.top + g.height / 2;
580
+ aLine(svg, g.left, cy, g.left + g.contentW, cy, C.rule, 2);
581
+ aLine(svg, cx, cy, g.left + g.contentW, cy, C.midSoft, 2);
582
+ const rays = 16;
583
+ const r0 = g.height * 0.3;
584
+ const r1 = g.height * 0.44;
585
+ for (let i = 0; i < rays; i++) {
586
+ const a = i / rays * Math.PI * 2;
587
+ svg.append("line").attr("x1", cx + Math.cos(a) * r0).attr("y1", cy + Math.sin(a) * r0).attr("x2", cx + Math.cos(a) * r1).attr("y2", cy + Math.sin(a) * r1).attr("stroke", C.event).attr("stroke-width", 2.5).attr("stroke-linecap", "round").attr("opacity", 0.45);
588
+ }
589
+ const w = Math.min(120, g.contentW * 0.16);
590
+ const h = g.height * 0.52;
591
+ aRect(svg, cx - w / 2, cy - h / 2, w, h, 18, C.event, C.event, 2);
592
+ aText(
593
+ svg,
594
+ cx,
595
+ cy - h * 0.14,
596
+ 14,
597
+ C.bg,
598
+ 700,
599
+ "middle",
600
+ MON_ABBR[ev.getMonth()].toUpperCase(),
601
+ { "letter-spacing": "0.08em" }
602
+ );
603
+ aText(
604
+ svg,
605
+ cx,
606
+ cy + h * 0.22,
607
+ Math.min(48, h * 0.4),
608
+ C.bg,
609
+ 800,
610
+ "middle",
611
+ String(ev.getDate())
612
+ );
613
+ aText(
614
+ svg,
615
+ cx,
616
+ cy + h / 2 + 26,
617
+ 13,
618
+ C.event,
619
+ 700,
620
+ "middle",
621
+ "THE DAY IS HERE",
622
+ { "letter-spacing": "0.12em" }
623
+ );
624
+ }
625
+ function vizAfter(svg, g, nowMs, resolvedMs, C) {
626
+ const ev = new Date(resolvedMs);
627
+ const elapsed = dayDelta(resolvedMs, nowMs);
628
+ const n = elapsed + 1;
629
+ const gap = 10;
630
+ const cw = (g.contentW - gap * (n - 1)) / n;
631
+ const ch = Math.min(cw * 1.1, g.height * 0.62);
632
+ const top = g.top + (g.height - ch) / 2 - 8;
633
+ for (let i = 0; i < n; i++) {
634
+ const dt = new Date(ev);
635
+ dt.setDate(ev.getDate() + i);
636
+ const x = g.left + i * (cw + gap);
637
+ const isEvent = i === 0;
638
+ const isToday = i === n - 1;
639
+ const st = roleStyle(C, isEvent ? "event" : "past");
640
+ const fill = st.fill;
641
+ const stroke = st.stroke;
642
+ const tcol = st.text;
643
+ const sw = isEvent ? 2.5 : 1;
644
+ aRect(svg, x, top, cw, ch, 12, fill, stroke, sw);
645
+ if (isEvent) haloRect(svg, x, top, cw, ch, 12, C);
646
+ aText(
647
+ svg,
648
+ x + cw / 2,
649
+ top + ch * 0.46,
650
+ Math.min(34, cw * 0.34),
651
+ tcol,
652
+ isEvent ? 750 : 500,
653
+ "middle",
654
+ String(dt.getDate())
655
+ );
656
+ aText(
657
+ svg,
658
+ x + cw / 2,
659
+ top + ch * 0.72,
660
+ 11,
661
+ tcol,
662
+ 600,
663
+ "middle",
664
+ MON_ABBR[dt.getMonth()]
665
+ );
666
+ if (isEvent)
667
+ aText(
668
+ svg,
669
+ x + cw / 2,
670
+ top - 8,
671
+ 11,
672
+ C.event,
673
+ 700,
674
+ "middle",
675
+ "IT HAPPENED",
676
+ { "letter-spacing": "0.05em" }
677
+ );
678
+ if (isToday)
679
+ aText(svg, x + cw / 2, top - 8, 11, C.now, 700, "middle", "TODAY", {
680
+ "letter-spacing": "0.05em"
681
+ });
682
+ }
683
+ aText(
684
+ svg,
685
+ g.left,
686
+ top + ch + 28,
687
+ 14,
688
+ C.muted,
689
+ 400,
690
+ "start",
691
+ `${elapsed} day${elapsed === 1 ? "" : "s"} ago \u2014 the day has passed`
692
+ );
693
+ }
694
+ function polar(cx, cy, r, deg) {
695
+ const a = (deg - 90) * Math.PI / 180;
696
+ return [cx + r * Math.cos(a), cy + r * Math.sin(a)];
697
+ }
698
+ function arcPath(cx, cy, r, frac) {
699
+ frac = Math.max(0, Math.min(0.9999, frac));
700
+ const [x0, y0] = polar(cx, cy, r, 0);
701
+ const [x1, y1] = polar(cx, cy, r, frac * 360);
702
+ return `M ${x0} ${y0} A ${r} ${r} 0 ${frac > 0.5 ? 1 : 0} 1 ${x1} ${y1}`;
703
+ }
704
+ function vizClock(svg, g, nowMs, targetMs, C) {
705
+ const ahead = targetMs >= nowMs;
706
+ const rem = Math.abs(targetMs - nowMs);
707
+ const h = Math.floor(rem / 36e5);
708
+ const m = Math.floor(rem % 36e5 / 6e4);
709
+ const s = Math.floor(rem % 6e4 / 1e3);
710
+ const R = Math.min(g.contentW / 3 * 0.3, g.height * 0.34);
711
+ const cy = g.top + g.height * 0.42;
712
+ const sw = Math.max(8, R * 0.17);
713
+ const gauges = [
714
+ { frac: h % 24 / 24, val: h, label: "HOURS", col: C.event, key: "h" },
715
+ { frac: m / 60, val: m, label: "MINUTES", col: C.event, key: "m" },
716
+ { frac: s / 60, val: s, label: "SECONDS", col: C.event, key: "s" }
717
+ ];
718
+ gauges.forEach((gg, i) => {
719
+ const cx = g.left + g.contentW * (i + 0.5) / 3;
720
+ svg.append("circle").attr("cx", cx).attr("cy", cy).attr("r", R).attr("fill", "none").attr("stroke", C.inert).attr("stroke-width", sw);
721
+ const arc = svg.append("path").attr("d", gg.frac > 1e-3 ? arcPath(cx, cy, R, gg.frac) : "").attr("fill", "none").attr("stroke", gg.col).attr("stroke-width", sw).attr("stroke-linecap", "round").attr("data-dgmo-gauge-arc", gg.key).attr("data-cx", cx).attr("data-cy", cy).attr("data-r", R);
722
+ void arc;
723
+ aText(
724
+ svg,
725
+ cx,
726
+ cy + R * 0.22,
727
+ R * 0.62,
728
+ C.text,
729
+ 800,
730
+ "middle",
731
+ pad2(gg.val),
732
+ {
733
+ "data-dgmo-gauge-val": gg.key
734
+ }
735
+ );
736
+ aText(svg, cx, cy + R + 22, 12, C.muted, 700, "middle", gg.label, {
737
+ "letter-spacing": "0.1em"
738
+ });
739
+ });
740
+ const cxMid = g.left + g.contentW * 0.5;
741
+ aText(
742
+ svg,
743
+ cxMid,
744
+ cy - R - 14,
745
+ 13,
746
+ ahead ? C.event : C.muted,
747
+ 700,
748
+ "middle",
749
+ ahead ? "TO GO" : "AGO",
750
+ {
751
+ "letter-spacing": "0.12em",
752
+ "data-dgmo-gauge-caption": ""
753
+ }
754
+ );
755
+ }
756
+ function pad2(n) {
757
+ return n < 10 ? "0" + n : String(n);
758
+ }
759
+ function drawBand(svg, kind, g, nowMs, resolvedMs, C) {
760
+ switch (kind) {
761
+ case "year":
762
+ return vizYear(svg, g, nowMs, resolvedMs, C);
763
+ case "months":
764
+ return vizMonths(svg, g, nowMs, resolvedMs, C);
765
+ case "monthgrid":
766
+ return vizMonthGrid(svg, g, nowMs, resolvedMs, C);
767
+ case "weekstrip":
768
+ return vizWeekStrip(svg, g, nowMs, resolvedMs, C);
769
+ case "today":
770
+ return vizToday(svg, g, resolvedMs, C);
771
+ case "after":
772
+ return vizAfter(svg, g, nowMs, resolvedMs, C);
773
+ case "clock":
774
+ return vizClock(svg, g, nowMs, resolvedMs, C);
775
+ }
776
+ }
777
+ function renderCountdown(container, parsed, palette, isDark, exportDims) {
778
+ d3Selection.select(container).selectAll(":not([data-d3-tooltip])").remove();
779
+ const width = exportDims?.width ?? container.clientWidth;
780
+ const height = exportDims?.height ?? container.clientHeight;
781
+ if (width <= 0 || height <= 0) return;
782
+ const now = Date.now();
783
+ const resolved = parsed.resolvedMs;
784
+ const label = parsed.sinceLabel ?? parsed.title ?? "";
785
+ const ordinal = parsed.since !== null && resolved !== null ? ordinalFor(resolved, parsed.since) : null;
786
+ const expiredFrozen = !parsed.rule && parsed.expired !== null && resolved !== null && resolved - now <= 0;
787
+ const bandKind = resolved === null || parsed.noVisual || expiredFrozen ? null : pickBand(now, resolved, parsed.hasTime);
788
+ let hero = bakedHero(parsed, now);
789
+ if (bandKind === "clock" && resolved !== null) {
790
+ const clock = formatCount(Math.abs(resolved - now), {
791
+ units: "clock",
792
+ round: parsed.round,
793
+ fields: parsed.fields
794
+ });
795
+ hero = resolved - now < 0 ? `${clock} ago` : clock;
796
+ }
797
+ const seriesAccent = getSeriesColors(palette)[0];
798
+ const defaultAccent = resolveColor("red", palette) ?? seriesAccent;
799
+ const manualColor = parsed.color && resolveColor(parsed.color, palette) || parsed.color || null;
800
+ const accent = manualColor ?? defaultAccent;
801
+ const muted = mix(palette.text, themeBaseBg(palette, isDark), 55);
802
+ const banked = resolveColor("green", palette) ?? muted;
803
+ const faint = mix(palette.text, themeBaseBg(palette, isDark), 72);
804
+ const svg = d3Selection.select(container).append("svg").attr("width", width).attr("preserveAspectRatio", "xMidYMid meet").attr("xmlns", "http://www.w3.org/2000/svg").attr("role", "img").attr("aria-label", `${parsed.title ?? "Countdown"}: ${hero}`).style("font-family", FONT_FAMILY);
805
+ const bgRect = svg.append("rect").attr("width", width).attr("fill", palette.bg);
806
+ const estWidth = (t, fs) => t.length * fs * 0.58;
807
+ const fitFont = (t, base, maxW, min) => {
808
+ const w = estWidth(t, base);
809
+ return w <= maxW ? base : Math.max(min, Math.floor(base * maxW / w));
810
+ };
811
+ const dispLen = (s) => parseInlineMarkdown(s).reduce((n, sp) => n + sp.text.length, 0);
812
+ const padX = Math.max(30, Math.round(width * 0.045));
813
+ const padY = Math.max(26, Math.round(width * 0.03));
814
+ const contentW = width - 2 * padX;
815
+ const leftX = padX;
816
+ const remainingNow = resolved === null ? 0 : Math.max(0, resolved - now);
817
+ const dayCount = Math.ceil(remainingNow / DAY_MS);
818
+ const heroSizeStr = parsed.units === "full" ? `${dayCount > 0 ? `${dayCount}d ` : ""}00:00:00` : parsed.units === "clock" ? formatCount(remainingNow, {
819
+ units: "clock",
820
+ round: parsed.round,
821
+ fields: parsed.fields
822
+ }) : hero;
823
+ const heroMaxW = contentW * 0.44;
824
+ const heroFont = fitFont(heroSizeStr, 96, heroMaxW, 26);
825
+ const heroW = Math.min(heroMaxW, estWidth(heroSizeStr, heroFont));
826
+ const gapMid = Math.max(28, Math.round(width * 0.03));
827
+ const leftW = Math.max(contentW * 0.42, contentW - heroW - gapMid);
828
+ const titleBase = 40;
829
+ let titleFont = 0;
830
+ let titleLines = [];
831
+ if (parsed.title) {
832
+ const longestWord = parsed.title.split(/\s+/).reduce((a, b) => b.length > a.length ? b : a, "");
833
+ titleFont = fitFont(longestWord, titleBase, leftW, 22);
834
+ const cpl = Math.max(6, Math.floor(leftW / (titleFont * 0.58)));
835
+ titleLines = wrapDescriptionLines([parsed.title], cpl).map((l) => l.text);
836
+ }
837
+ const eyebrowText = ordinal !== null ? applyOrdinalTemplate(parsed.sinceLabel ?? `Nth ${label}`, ordinal) : null;
838
+ const eyebrowFont = 16;
839
+ const footerText = resolved !== null ? formatFooter(resolved, parsed.hasTime) : null;
840
+ const footerFont = 17;
841
+ const noteFont = 19;
842
+ const asofFont = 13;
843
+ const noteCharsPerLine = Math.max(8, Math.floor(leftW / (noteFont * 0.5)));
844
+ const noteSource = parsed.note ? parsed.note.split("\n").map((l) => l.replace(/^[-*]\s+/, "\u2022 ")) : [];
845
+ const noteLines = noteSource.length ? wrapDescriptionLines(noteSource, noteCharsPerLine, dispLen) : [];
846
+ const bulletPx = noteFont * 0.95;
847
+ let y = padY;
848
+ const drawText = (text, yTop, fs, fill, weight) => svg.append("text").attr("x", leftX).attr("y", yTop + fs).attr("text-anchor", "start").attr("dominant-baseline", "alphabetic").attr("fill", fill).attr("font-family", FONT_FAMILY).attr("font-size", fs).attr("font-weight", weight).text(text);
849
+ if (parsed.title) {
850
+ titleLines.forEach((tl, i) => {
851
+ const t = drawText(tl, y, titleFont, palette.text, 700);
852
+ if (i === 0) t.attr("data-line-number", parsed.titleLineNumber);
853
+ y += i < titleLines.length - 1 ? Math.round(titleFont * 1.12) : titleFont;
854
+ });
855
+ y += Math.round(titleFont * 0.45);
856
+ const heroLeft = width - padX - heroW;
857
+ const ruleRight = Math.max(leftX + 40, heroLeft - 20);
858
+ svg.append("line").attr("x1", leftX).attr("x2", ruleRight).attr("y1", y).attr("y2", y).attr("stroke", mix(palette.text, palette.bg, 14)).attr("stroke-width", 1.25);
859
+ y += Math.round(titleFont * 0.5);
860
+ }
861
+ if (eyebrowText) {
862
+ drawText(eyebrowText, y, eyebrowFont, banked, 700).attr(
863
+ "data-dgmo-countdown-eyebrow",
864
+ ""
865
+ );
866
+ y += eyebrowFont + 8;
867
+ }
868
+ if (footerText) {
869
+ const fx = parsed.rule ? leftX + 22 : leftX;
870
+ if (parsed.rule)
871
+ recurGlyph(svg, leftX + 8, y + footerFont * 0.52, 6.5, muted);
872
+ svg.append("text").attr("x", fx).attr("y", y + footerFont).attr("text-anchor", "start").attr("dominant-baseline", "alphabetic").attr("fill", muted).attr("font-family", FONT_FAMILY).attr("font-size", footerFont).attr("font-weight", 500).attr("data-dgmo-countdown-footer", "").text(footerText);
873
+ y += footerFont + 8;
874
+ }
875
+ if (noteLines.length) {
876
+ y += 4;
877
+ for (const nl of noteLines) {
878
+ const bx = nl.kind === "plain" ? leftX : leftX + bulletPx;
879
+ if (nl.kind === "bullet-first") {
880
+ svg.append("text").attr("x", leftX).attr("y", y + noteFont).attr("fill", muted).attr("font-family", FONT_FAMILY).attr("font-size", noteFont).text("\u2022");
881
+ }
882
+ const t = svg.append("text").attr("x", bx).attr("y", y + noteFont).attr("fill", palette.text).attr("font-family", FONT_FAMILY).attr("font-size", noteFont).attr("font-weight", 400);
883
+ renderInlineText(
884
+ t,
885
+ nl.text,
886
+ palette,
887
+ noteFont
888
+ );
889
+ y += Math.round(noteFont * 1.35);
890
+ }
891
+ y += 2;
892
+ }
893
+ drawText(`as of ${formatDateShort(now)}`, y, asofFont, faint, 400).attr(
894
+ "data-dgmo-countdown-asof",
895
+ ""
896
+ );
897
+ y += asofFont;
898
+ const leftBottom = y;
899
+ const detailFont = 18;
900
+ const remainingSub = resolved !== null ? resolved - now : 0;
901
+ const subText = resolved === null || remainingSub <= 0 ? null : parsed.units === "words" ? formatWordsDetail(remainingSub) : parsed.units === "human" && bandKind !== "clock" ? parsed.hasTime ? formatCount(remainingSub, {
902
+ units: "clock",
903
+ round: parsed.round,
904
+ fields: parsed.fields
905
+ }) : formatHuman(DAY_START(now), DAY_START(resolved)).sub || null : null;
906
+ const heroCapTop = padY + 0.28 * titleFont;
907
+ const heroBaseline = heroCapTop + 0.72 * heroFont;
908
+ const heroBlockBottom = heroBaseline + (subText ? heroFont * 0.28 + detailFont : 0);
909
+ const contentBottom = Math.max(leftBottom, heroBlockBottom);
910
+ const hasBand = bandKind !== null;
911
+ const topSection = contentBottom;
912
+ const bandTop = topSection + 26;
913
+ const BAND_H = hasBand && resolved !== null ? Math.round(bandHeightFor(bandKind, now, resolved, width - 2 * padX)) : 0;
914
+ const bannerH = hasBand ? bandTop + BAND_H + padY : Math.max(
915
+ contentBottom + padY,
916
+ heroFont * 1.25 + 2 * padY,
917
+ Math.round(width * 0.28)
918
+ );
919
+ svg.attr("height", bannerH).attr("viewBox", `0 0 ${width} ${bannerH}`);
920
+ bgRect.attr("height", bannerH);
921
+ if (hasBand && resolved !== null) {
922
+ drawBand(
923
+ svg,
924
+ bandKind,
925
+ { left: leftX, top: bandTop, contentW: width - 2 * padX, height: BAND_H },
926
+ now,
927
+ resolved,
928
+ bandColors(palette, accent, muted, faint)
929
+ );
930
+ }
931
+ const value = svg.append("text").attr("class", "countdown-value").attr("x", width - padX).attr("y", heroBaseline).attr("text-anchor", "end").attr("dominant-baseline", "alphabetic").attr("fill", accent).attr("font-family", FONT_FAMILY).attr("font-size", heroFont).attr("font-weight", 800).attr("data-dgmo-countdown-units", parsed.units).attr("data-dgmo-countdown-round", parsed.round).attr("data-dgmo-countdown-fields", parsed.fields.join(",")).attr("data-dgmo-countdown-expired", parsed.expired).attr("aria-label", `${parsed.title ?? "Countdown"}: ${hero}`).text(hero);
932
+ if (parsed.rule && resolved !== null) {
933
+ value.attr("data-dgmo-countdown", new Date(resolved).toISOString());
934
+ } else if (parsed.target) {
935
+ value.attr("data-dgmo-countdown", parsed.target);
936
+ }
937
+ if (parsed.title) value.attr("data-dgmo-countdown-title", parsed.title);
938
+ if (parsed.onDay) value.attr("data-dgmo-countdown-onday", parsed.onDay);
939
+ if (parsed.hasTime) value.attr("data-dgmo-countdown-hastime", "1");
940
+ if (parsed.since !== null) {
941
+ value.attr("data-dgmo-countdown-since", parsed.since);
942
+ value.attr(
943
+ "data-dgmo-countdown-since-label",
944
+ parsed.sinceLabel ?? `Nth ${parsed.title ?? ""}`
945
+ );
946
+ }
947
+ stampRecur(value, parsed);
948
+ if (subText) {
949
+ svg.append("text").attr("x", width - padX).attr("y", heroBaseline + heroFont * 0.28 + detailFont).attr("text-anchor", "end").attr("dominant-baseline", "alphabetic").attr("fill", muted).attr("font-family", FONT_FAMILY).attr("font-size", detailFont).attr("font-weight", 500).attr("data-dgmo-countdown-detail", "").text(subText);
950
+ }
951
+ }
952
+ function renderCountdownForExport(container, parsed, palette, isDark, exportDims) {
953
+ renderCountdown(container, parsed, palette, isDark, exportDims);
954
+ }
955
+
956
+ export {
957
+ renderCountdown,
958
+ renderCountdownForExport
959
+ };
960
+ //# sourceMappingURL=chunk-GROQGHCT.js.map