@diagrammo/dgmo 0.49.0 → 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 (192) hide show
  1. package/.cursorrules +6 -2
  2. package/.github/copilot-instructions.md +6 -2
  3. package/.windsurfrules +6 -2
  4. package/SKILL.md +6 -2
  5. package/dist/advanced.d.ts +419 -12
  6. package/dist/advanced.js +557 -195
  7. package/dist/auto.js +129 -119
  8. package/dist/auto.mjs +11543 -4815
  9. package/dist/block.js +145 -48
  10. package/dist/{charts-d3-EW3YQTEA.js → charts-d3-DKUD7MQE.js} +5 -5
  11. package/dist/{chunk-5FGDJIJX.js → chunk-2C56LEML.js} +3 -3
  12. package/dist/{chunk-35BBZDFE.js → chunk-2JJ2KNPI.js} +4 -4
  13. package/dist/{chunk-ZTLWVRNS.js → chunk-2QYTMIRR.js} +2 -2
  14. package/dist/{chunk-VC3TR4NL.js → chunk-3G6TMNVF.js} +3 -3
  15. package/dist/{chunk-ZDUQGL3N.js → chunk-3LKM6FMW.js} +2 -2
  16. package/dist/{chunk-4BD7EVPK.js → chunk-3P2DKJCG.js} +2 -2
  17. package/dist/{chunk-6CLKNXVP.js → chunk-3TDRHT4J.js} +457 -78
  18. package/dist/chunk-3XPUDB7B.js +420 -0
  19. package/dist/{chunk-DDTJ5N7Q.js → chunk-3ZPC476N.js} +6 -6
  20. package/dist/{chunk-BPIJLRYE.js → chunk-4BMJQFNK.js} +3 -3
  21. package/dist/{chunk-N4J5KGWG.js → chunk-4S723I74.js} +8 -8
  22. package/dist/{chunk-4YNP6O47.js → chunk-5JSWBPZZ.js} +3 -3
  23. package/dist/{chunk-KUBBJ2CD.js → chunk-5Z736BSU.js} +6 -6
  24. package/dist/{chunk-MJCG5K2O.js → chunk-6BFZKBGD.js} +2 -2
  25. package/dist/{chunk-XCC2RENT.js → chunk-6IAA2QQ2.js} +2 -2
  26. package/dist/{chunk-FUCAB3KQ.js → chunk-6M5PJFQG.js} +3 -3
  27. package/dist/{chunk-T7IKPCMI.js → chunk-6X4AKWLF.js} +3 -3
  28. package/dist/{chunk-JFPY3UJ7.js → chunk-6ZT4U37Q.js} +8 -8
  29. package/dist/{chunk-CLR4A2N2.js → chunk-7G2ER4CY.js} +4 -4
  30. package/dist/chunk-7PQYTZMA.js +681 -0
  31. package/dist/{chunk-LG4TWW4U.js → chunk-7RB5Q6MB.js} +8 -8
  32. package/dist/{chunk-7OVSJI2V.js → chunk-A3WQVFBS.js} +3 -3
  33. package/dist/{chunk-X2CH42BN.js → chunk-ASS5YYIZ.js} +7 -7
  34. package/dist/{chunk-3NFJWFNP.js → chunk-BDXC7MDK.js} +1045 -124
  35. package/dist/chunk-BTUTZMPT.js +482 -0
  36. package/dist/{chunk-UVCXZEGU.js → chunk-CVV36CWI.js} +2 -2
  37. package/dist/{chunk-TC3YWBFO.js → chunk-DMJJ3CEQ.js} +29 -8
  38. package/dist/{chunk-NVT6C2VE.js → chunk-EJTKV7CY.js} +4 -4
  39. package/dist/{chunk-4NQ3IKUM.js → chunk-ER5SCQWQ.js} +5 -5
  40. package/dist/{chunk-7VLUGEMJ.js → chunk-F5UDBSJY.js} +4 -4
  41. package/dist/{chunk-IHLSHCPZ.js → chunk-FAL7NOK3.js} +5 -5
  42. package/dist/{chunk-YRVLP7UU.js → chunk-FB2WHOEQ.js} +4 -4
  43. package/dist/chunk-FL4IOQ37.js +379 -0
  44. package/dist/{chunk-6VE3VLWM.js → chunk-GBE54KY6.js} +6 -5
  45. package/dist/{chunk-ZXL6MB4R.js → chunk-GL5UZ6NY.js} +3 -3
  46. package/dist/{chunk-3BIAFYD2.js → chunk-GPWHQ5FJ.js} +2 -2
  47. package/dist/chunk-GROQGHCT.js +960 -0
  48. package/dist/{chunk-GB3YZTAM.js → chunk-H73FP42Q.js} +5 -5
  49. package/dist/{chunk-O5MQPK7E.js → chunk-I4IFRCUB.js} +3 -3
  50. package/dist/{chunk-IUK7AGD4.js → chunk-I7F2A35O.js} +2 -2
  51. package/dist/{chunk-YTN572Q2.js → chunk-IA3FJYWR.js} +2 -2
  52. package/dist/{chunk-RI4NIMFP.js → chunk-JFYIP7XU.js} +75 -35
  53. package/dist/{chunk-UWDO3O52.js → chunk-JZNMXEIV.js} +2 -2
  54. package/dist/chunk-KJXIHOVL.js +940 -0
  55. package/dist/{chunk-26RVGM44.js → chunk-L2ZTFHAY.js} +2 -2
  56. package/dist/{chunk-PU3AUQPA.js → chunk-M5RXSRO2.js} +2 -2
  57. package/dist/{chunk-XKTN7CZF.js → chunk-NFFIKVNO.js} +4 -4
  58. package/dist/{chunk-SVDWQGX2.js → chunk-NISQC5KW.js} +139 -78
  59. package/dist/{chunk-4HVNZ7WF.js → chunk-O4VUFXIH.js} +3 -3
  60. package/dist/{chunk-F743CM2N.js → chunk-O76UD6VJ.js} +3 -3
  61. package/dist/{chunk-TLKMTQYL.js → chunk-OHQEMBLI.js} +3 -3
  62. package/dist/{chunk-BGJV5ATD.js → chunk-ONA5KPV3.js} +2 -2
  63. package/dist/{chunk-ZNQX6QWH.js → chunk-OTAL43EH.js} +6 -2
  64. package/dist/{chunk-FMKTYMP4.js → chunk-OTP5KVLO.js} +3 -3
  65. package/dist/{chunk-5ZZLLBFK.js → chunk-PGEGPSCZ.js} +2 -2
  66. package/dist/{chunk-XJ7J6WOO.js → chunk-PJUGRJHJ.js} +4 -4
  67. package/dist/{chunk-6SA7FJE4.js → chunk-PLZI6KPM.js} +10 -10
  68. package/dist/{chunk-AJ2PEY7J.js → chunk-PMN3Q7RJ.js} +2 -2
  69. package/dist/chunk-Q4V4XQWV.js +158 -0
  70. package/dist/{chunk-5XCM7UUW.js → chunk-QDFNCATJ.js} +99 -35
  71. package/dist/{chunk-CEHZOPGM.js → chunk-QFQ35BTO.js} +2 -2
  72. package/dist/{chunk-4UDKKGHH.js → chunk-QUJGFNFN.js} +2 -2
  73. package/dist/{chunk-IBC35BTK.js → chunk-R56LASIN.js} +2 -2
  74. package/dist/{chunk-SJEGO2QL.js → chunk-RV26LTUU.js} +4 -4
  75. package/dist/chunk-RV6A2B5S.js +354 -0
  76. package/dist/{chunk-65RTDUZH.js → chunk-S5GRONXL.js} +3 -3
  77. package/dist/{chunk-K6HNAY5V.js → chunk-SCHXJTZL.js} +2 -2
  78. package/dist/{chunk-ALRHIR6I.js → chunk-SGFZZAUO.js} +4 -4
  79. package/dist/{chunk-KV6Y2HE6.js → chunk-SU2VBK4L.js} +4 -4
  80. package/dist/{chunk-D5AVQCDN.js → chunk-T4BRO3Z6.js} +3 -3
  81. package/dist/{chunk-IFK3GIUW.js → chunk-TSA237IM.js} +2 -2
  82. package/dist/{chunk-SQDFK5ZQ.js → chunk-TWCLK2GA.js} +3 -3
  83. package/dist/{chunk-DKEPS5LH.js → chunk-U2HGPLZS.js} +36 -2
  84. package/dist/{chunk-EYN7VFKL.js → chunk-URSQLCTR.js} +3 -3
  85. package/dist/{chunk-BCT5G2VN.js → chunk-UUS2GIJZ.js} +5 -5
  86. package/dist/{chunk-LVHPTBO3.js → chunk-UXOSVCLJ.js} +4 -4
  87. package/dist/{chunk-HBVD67XG.js → chunk-WCUHAQKB.js} +2 -2
  88. package/dist/{chunk-YYX3SU6H.js → chunk-WWN566I7.js} +257 -101
  89. package/dist/{chunk-YM2BSPYW.js → chunk-X2NMFTG3.js} +2 -2
  90. package/dist/{chunk-ZREZOIGS.js → chunk-XCLHOZAM.js} +6 -6
  91. package/dist/{chunk-KQAEKMIX.js → chunk-XDXNDSKO.js} +2 -2
  92. package/dist/{chunk-RTERS6S5.js → chunk-XMVQ5F4M.js} +4 -4
  93. package/dist/{chunk-4FIV4K4Z.js → chunk-YA7D2N2O.js} +7 -7
  94. package/dist/{chunk-B57V3DWN.js → chunk-YB3FW24O.js} +3 -3
  95. package/dist/chunk-YNRDWYZP.js +295 -0
  96. package/dist/{chunk-2WMBWZY2.js → chunk-YZLMKW4T.js} +3 -3
  97. package/dist/{chunk-SGHSY3LU.js → chunk-Z6XJQ6KO.js} +81 -6
  98. package/dist/cli.cjs +153 -144
  99. package/dist/clock.d.ts +10 -0
  100. package/dist/clock.js +235 -0
  101. package/dist/countdown.d.ts +12 -0
  102. package/dist/countdown.js +450 -0
  103. package/dist/dgmo-router-QOMFCOOV.js +84 -0
  104. package/dist/{dimensions-WSIJXT5Q.js → dimensions-P5FSX2QN.js} +5 -5
  105. package/dist/editor.js +39 -1
  106. package/dist/element.js +131 -121
  107. package/dist/element.mjs +11543 -4815
  108. package/dist/{flowchart-parser-IVZN7CQN.js → flowchart-parser-OE4WHLTF.js} +4 -4
  109. package/dist/{flowchart-renderer-GMI2U3DD.js → flowchart-renderer-GPCSMTOR.js} +6 -6
  110. package/dist/highlight.d.ts +17 -1
  111. package/dist/highlight.js +156 -5
  112. package/dist/index.js +50 -45
  113. package/dist/{layout-HQMBPJVS.js → layout-46366KBT.js} +2 -2
  114. package/dist/{layout-D42XE4RE.js → layout-5BG6DFCU.js} +3 -3
  115. package/dist/{layout-K2ZN3Q42.js → layout-T3OZU5QW.js} +4 -4
  116. package/dist/{layout-S3EK4IYO.js → layout-TJIWF7EM.js} +4 -4
  117. package/dist/{layout-GZ2CWONU.js → layout-VYELEAW7.js} +4 -4
  118. package/dist/{layout-4Z5JM7PT.js → layout-WZHNDT2O.js} +4 -4
  119. package/dist/{parser-OBQG655V.js → parser-45DENHFZ.js} +4 -4
  120. package/dist/{parser-MCJWF5G3.js → parser-4AI5ZN5F.js} +3 -3
  121. package/dist/{parser-SMBJO3XN.js → parser-4P36TUVD.js} +4 -4
  122. package/dist/{parser-ZYC3XGNS.js → parser-5AURY4A6.js} +4 -4
  123. package/dist/{parser-WISPH7LW.js → parser-A2BEFMGK.js} +4 -4
  124. package/dist/parser-B5FVS7O6.js +11 -0
  125. package/dist/{parser-KPMN5KKE.js → parser-C2HF2C2E.js} +4 -4
  126. package/dist/parser-CSFUN3CT.js +14 -0
  127. package/dist/{parser-TITK4YW6.js → parser-D3QT6GWN.js} +5 -5
  128. package/dist/{parser-ZKF5K2H2.js → parser-D5637H5H.js} +4 -4
  129. package/dist/{parser-IKZFTLOJ.js → parser-DFFEDKHH.js} +3 -3
  130. package/dist/parser-DOKMZXVZ.js +13 -0
  131. package/dist/parser-FMPCVFRK.js +15 -0
  132. package/dist/{parser-UBGPTIZD.js → parser-HYRTF3DO.js} +3 -3
  133. package/dist/{parser-TNYX5S7E.js → parser-I2UIJKVQ.js} +4 -4
  134. package/dist/{parser-K647FRI4.js → parser-IBWNAPY4.js} +3 -3
  135. package/dist/{parser-JD7OQ2E6.js → parser-KUQWRPIT.js} +4 -4
  136. package/dist/{parser-HVJFTOXL.js → parser-LWKKBNSA.js} +3 -3
  137. package/dist/{parser-4ROBKVUR.js → parser-O4QFCUW7.js} +5 -5
  138. package/dist/{parser-BL7Z72EY.js → parser-PGMQDD4G.js} +4 -4
  139. package/dist/{parser-QJYS7KQQ.js → parser-Q4QKCIWQ.js} +4 -4
  140. package/dist/{parser-UGA23PYK.js → parser-QTOB4KFL.js} +4 -4
  141. package/dist/{parser-DERPY5KC.js → parser-QYYM4QVW.js} +4 -4
  142. package/dist/{parser-GFSOPDB7.js → parser-RZMQP7MM.js} +4 -4
  143. package/dist/parser-RZPVAQVX.js +11 -0
  144. package/dist/parser-SOUJOEYI.js +13 -0
  145. package/dist/{parser-MBJSBTL5.js → parser-UQE5OWZI.js} +5 -5
  146. package/dist/{parser-MRBPXXIV.js → parser-WAV5JRPT.js} +4 -4
  147. package/dist/{parser-4BKIFG2C.js → parser-YLKYBRIT.js} +5 -5
  148. package/dist/{parser-D6ONJQFR.js → parser-YS7TOS2K.js} +3 -3
  149. package/dist/{parser-CLMFZWCC.js → parser-ZSOWUBML.js} +5 -5
  150. package/dist/{parser-XWUDFJ7P.js → parser-ZTBATMLX.js} +4 -4
  151. package/dist/{renderer-LWGJFT3D.js → renderer-35HSIDMZ.js} +5 -5
  152. package/dist/{renderer-BB5PREMY.js → renderer-4ITCHBT7.js} +4 -4
  153. package/dist/{renderer-YHXPN3GF.js → renderer-67NPCBIS.js} +7 -7
  154. package/dist/{renderer-TPIBXNOS.js → renderer-6GHYK7DX.js} +6 -6
  155. package/dist/{renderer-VICQ4WNY.js → renderer-6RNGHC5Z.js} +5 -5
  156. package/dist/renderer-72LGR2YF.js +14 -0
  157. package/dist/{renderer-W5RMOURB.js → renderer-7SWMIFMM.js} +6 -6
  158. package/dist/{renderer-6L3NBEY5.js → renderer-BBCEFILK.js} +6 -6
  159. package/dist/{renderer-VFUVRNLK.js → renderer-BSW7SRIZ.js} +4 -4
  160. package/dist/{renderer-CGW7QPNA.js → renderer-BY533UWU.js} +7 -7
  161. package/dist/{renderer-V3JEMWMM.js → renderer-BZSBPTZJ.js} +6 -6
  162. package/dist/{renderer-DKESNMU5.js → renderer-CXUC4KAD.js} +6 -6
  163. package/dist/{renderer-XEKIRPI6.js → renderer-FZUKFUNZ.js} +5 -5
  164. package/dist/renderer-G2NLGNKF.js +17 -0
  165. package/dist/{renderer-THD6V5TL.js → renderer-GO3FE3RA.js} +9 -7
  166. package/dist/{renderer-ROV756WT.js → renderer-HPGR6USK.js} +5 -5
  167. package/dist/renderer-ICJN2SA2.js +24 -0
  168. package/dist/{renderer-4IUPINAE.js → renderer-INEXO7B6.js} +7 -7
  169. package/dist/{renderer-SQ3JUAI7.js → renderer-KDYCFRBX.js} +6 -6
  170. package/dist/renderer-KY4KQBTF.js +19 -0
  171. package/dist/{renderer-MJDDU27W.js → renderer-LBN65V45.js} +10 -10
  172. package/dist/{renderer-UZF3JROD.js → renderer-MGBWOCXG.js} +8 -8
  173. package/dist/{renderer-MFJ7HY2H.js → renderer-O4JKUGKO.js} +5 -5
  174. package/dist/{renderer-QL5KO6SK.js → renderer-OOGFODWP.js} +7 -7
  175. package/dist/{renderer-A5VFZQQK.js → renderer-Q6ZKPLS6.js} +6 -6
  176. package/dist/{renderer-TYXRHMRI.js → renderer-SZQ326M5.js} +9 -9
  177. package/dist/{renderer-6T3KK4S3.js → renderer-TKG6LS4U.js} +7 -7
  178. package/dist/{renderer-QNHUXCRL.js → renderer-TQMZGDAX.js} +9 -9
  179. package/dist/{renderer-radial-MHO2VDXN.js → renderer-radial-JELMHQ24.js} +6 -6
  180. package/dist/{state-parser-RX3GXOIB.js → state-parser-3REXRK3R.js} +4 -4
  181. package/dist/{state-renderer-AJUKGNWU.js → state-renderer-XYLNRWXR.js} +6 -6
  182. package/docs/ai-integration.md +6 -2
  183. package/docs/language-reference.md +253 -22
  184. package/gallery/fixtures/body.dgmo +17 -0
  185. package/gallery/fixtures/bracket.dgmo +30 -0
  186. package/gallery/fixtures/clock.dgmo +8 -0
  187. package/gallery/fixtures/countdown.dgmo +3 -0
  188. package/gallery/fixtures/goal.dgmo +4 -0
  189. package/package.json +12 -4
  190. package/dist/dgmo-router-ODKPEJ3P.js +0 -79
  191. package/dist/parser-667RGSUW.js +0 -13
  192. package/dist/parser-J3P2D6IP.js +0 -13
@@ -0,0 +1,681 @@
1
+ import {
2
+ FONT_FAMILY
3
+ } from "./chunk-6KFWC4CO.js";
4
+ import {
5
+ mix,
6
+ themeBaseBg
7
+ } from "./chunk-P6T66CCZ.js";
8
+ import {
9
+ resolveColor
10
+ } from "./chunk-TLVIHFRO.js";
11
+
12
+ // src/clock/renderer.ts
13
+ import * as d3Selection from "d3-selection";
14
+
15
+ // src/clock/resolve.ts
16
+ var CLOCK_RAMP = [
17
+ [0, "#3d478f"],
18
+ [4, "#4a4d8c"],
19
+ [6, "#c98a6b"],
20
+ [8, "#d9a441"],
21
+ [11, "#e0b23c"],
22
+ [13, "#4f96c4"],
23
+ [16, "#cc7a33"],
24
+ [19, "#8a5aa0"],
25
+ [24, "#3d478f"]
26
+ ];
27
+ function hexLerp(a, b, t) {
28
+ const pa = [1, 3, 5].map((i) => parseInt(a.slice(i, i + 2), 16));
29
+ const pb = [1, 3, 5].map((i) => parseInt(b.slice(i, i + 2), 16));
30
+ const c = pa.map(
31
+ (v, i) => Math.round(v + (pb[i] - v) * t).toString(16).padStart(2, "0")
32
+ );
33
+ return `#${c.join("")}`;
34
+ }
35
+ function rampColor(h) {
36
+ const hh = (h % 24 + 24) % 24;
37
+ for (let i = 0; i < CLOCK_RAMP.length - 1; i++) {
38
+ const [h0, c0] = CLOCK_RAMP[i];
39
+ const [h1, c1] = CLOCK_RAMP[i + 1];
40
+ if (hh >= h0 && hh <= h1) return hexLerp(c0, c1, (hh - h0) / (h1 - h0));
41
+ }
42
+ return CLOCK_RAMP[0][1];
43
+ }
44
+ var SOON_MIN = 60;
45
+ var RAD = Math.PI / 180;
46
+ var DAY_MS = 864e5;
47
+ var J1970 = 2440588;
48
+ var J2000 = 2451545;
49
+ function zoneParts(zone, nowMs) {
50
+ const d = new Date(nowMs);
51
+ try {
52
+ const o = {};
53
+ new Intl.DateTimeFormat("en-US", {
54
+ timeZone: zone,
55
+ hour12: false,
56
+ hour: "2-digit",
57
+ minute: "2-digit",
58
+ second: "2-digit",
59
+ weekday: "short"
60
+ }).formatToParts(d).forEach((x) => {
61
+ o[x.type] = x.value;
62
+ });
63
+ const off = new Intl.DateTimeFormat("en-US", {
64
+ timeZone: zone,
65
+ timeZoneName: "shortOffset"
66
+ }).formatToParts(d).find((x) => x.type === "timeZoneName");
67
+ return {
68
+ h: parseInt(o["hour"], 10) % 24,
69
+ m: parseInt(o["minute"], 10),
70
+ s: parseInt(o["second"], 10),
71
+ weekday: o["weekday"],
72
+ offsetLabel: off ? off.value.replace("GMT", "UTC") : ""
73
+ };
74
+ } catch {
75
+ return {
76
+ h: d.getUTCHours(),
77
+ m: d.getUTCMinutes(),
78
+ s: d.getUTCSeconds(),
79
+ weekday: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][d.getUTCDay()],
80
+ offsetLabel: "UTC"
81
+ };
82
+ }
83
+ }
84
+ function pad2(n) {
85
+ return n < 10 ? "0" + n : String(n);
86
+ }
87
+ function formatTime(h, m, s, hours12) {
88
+ const sec = pad2(s);
89
+ if (hours12) {
90
+ const ap = h < 12 ? "am" : "pm";
91
+ let hr = h % 12;
92
+ if (hr === 0) hr = 12;
93
+ return { main: `${hr}:${pad2(m)}`, sec, ap };
94
+ }
95
+ return { main: `${pad2(h)}:${pad2(m)}`, sec, ap: "" };
96
+ }
97
+ function fmtDelta(ms) {
98
+ const m = Math.max(0, Math.round(ms / 6e4));
99
+ if (m < 90) return `${m}m`;
100
+ return `${Math.floor(m / 60)}h ${m % 60}m`;
101
+ }
102
+ function workStatus(parts, work) {
103
+ if (!work) return null;
104
+ const min = parts.h * 60 + parts.m;
105
+ if (!work.days[parts.weekday]) return { cls: "off", text: "Weekend" };
106
+ if (min < work.startMin) {
107
+ const d = work.startMin - min;
108
+ return {
109
+ cls: d <= SOON_MIN ? "soon" : "off",
110
+ text: `starts in ${fmtDelta(d * 6e4)}`
111
+ };
112
+ }
113
+ if (min < work.endMin) {
114
+ return { cls: "ok", text: `${fmtDelta((work.endMin - min) * 6e4)} left` };
115
+ }
116
+ return {
117
+ cls: "off",
118
+ text: `ended ${fmtDelta((min - work.endMin) * 6e4)} ago`
119
+ };
120
+ }
121
+ function toJulian(ms) {
122
+ return ms / DAY_MS - 0.5 + J1970;
123
+ }
124
+ function fromJulian(j) {
125
+ return (j + 0.5 - J1970) * DAY_MS;
126
+ }
127
+ function sunTimes(nowMs, lat, lon) {
128
+ const lw = -lon * RAD;
129
+ const phi = lat * RAD;
130
+ const J = toJulian(nowMs);
131
+ const n = Math.round(J - J2000 - 9e-4 - lw / (2 * Math.PI));
132
+ const Jn = J2000 + 9e-4 + lw / (2 * Math.PI) + n;
133
+ const M = (357.5291 + 0.98560028 * (Jn - J2000)) * RAD;
134
+ const C = (1.9148 * Math.sin(M) + 0.02 * Math.sin(2 * M) + 3e-4 * Math.sin(3 * M)) * RAD;
135
+ const L = M + C + Math.PI + 102.9372 * RAD;
136
+ const Jt = Jn + 53e-4 * Math.sin(M) - 69e-4 * Math.sin(2 * L);
137
+ const dec = Math.asin(Math.sin(L) * Math.sin(23.44 * RAD));
138
+ const cw = (Math.sin(-0.833 * RAD) - Math.sin(phi) * Math.sin(dec)) / (Math.cos(phi) * Math.cos(dec));
139
+ if (cw > 1) return { polar: "night" };
140
+ if (cw < -1) return { polar: "day" };
141
+ const w = Math.acos(cw);
142
+ const Jset = J2000 + 9e-4 + (w + lw) / (2 * Math.PI) + n + 53e-4 * Math.sin(M) - 69e-4 * Math.sin(2 * L);
143
+ return {
144
+ sunriseMs: fromJulian(Jt - (Jset - Jt)),
145
+ sunsetMs: fromJulian(Jset)
146
+ };
147
+ }
148
+ function sunLine(nowMs, lat, lon) {
149
+ const t = sunTimes(nowMs, lat, lon);
150
+ if (t.polar) {
151
+ return {
152
+ up: t.polar === "day",
153
+ text: t.polar === "day" ? "midnight sun" : "polar night"
154
+ };
155
+ }
156
+ if (nowMs < t.sunriseMs) {
157
+ return { up: false, text: `sunrise in ${fmtDelta(t.sunriseMs - nowMs)}` };
158
+ }
159
+ if (nowMs < t.sunsetMs) {
160
+ return { up: true, text: `sunset in ${fmtDelta(t.sunsetMs - nowMs)}` };
161
+ }
162
+ const tm = sunTimes(nowMs + DAY_MS, lat, lon);
163
+ if (tm.polar) return { up: false, text: "sunrise in \u2014" };
164
+ return { up: false, text: `sunrise in ${fmtDelta(tm.sunriseMs - nowMs)}` };
165
+ }
166
+ function handAngles(h, m, s) {
167
+ return {
168
+ hour: (h % 12 + m / 60) * 30,
169
+ minute: (m + s / 60) * 6,
170
+ second: s * 6
171
+ };
172
+ }
173
+
174
+ // src/clock/renderer.ts
175
+ var PLACE_ACCENTS = [
176
+ "blue",
177
+ "green",
178
+ "orange",
179
+ "purple",
180
+ "teal",
181
+ "red",
182
+ "cyan"
183
+ ];
184
+ function resolveColorBy(mode, entry, index, ctx) {
185
+ if (entry.color)
186
+ return { solid: entry.color, laneTint: mix(entry.color, ctx.cardFill, 14) };
187
+ switch (mode) {
188
+ case "none":
189
+ return null;
190
+ case "place": {
191
+ const name = PLACE_ACCENTS[index % PLACE_ACCENTS.length];
192
+ const c = resolveColor(name, ctx.palette) ?? ctx.sw.day;
193
+ return { solid: c, laneTint: mix(c, ctx.cardFill, 14) };
194
+ }
195
+ case "daylight":
196
+ return ctx.up ? { solid: ctx.sw.day, laneTint: ctx.sw.dayTint } : { solid: ctx.sw.night, laneTint: ctx.sw.nightTint };
197
+ case "work": {
198
+ if (!ctx.status) return null;
199
+ const cls = ctx.status.cls;
200
+ const solid = cls === "ok" ? ctx.sw.ok : cls === "soon" ? ctx.sw.soon : ctx.sw.off;
201
+ const laneTint = cls === "ok" ? ctx.sw.okSoft : cls === "soon" ? ctx.sw.soonSoft : ctx.sw.offSoft;
202
+ return { solid, laneTint };
203
+ }
204
+ case "time":
205
+ return {
206
+ solid: rampColor(ctx.localHour),
207
+ laneTint: mix(rampColor(ctx.localHour), ctx.cardFill, 14)
208
+ };
209
+ }
210
+ }
211
+ var clipSeq = 0;
212
+ function estWidth(t, fs) {
213
+ return t.length * fs * 0.6;
214
+ }
215
+ function fitFont(t, base, maxW, min) {
216
+ const w = estWidth(t, base);
217
+ return w <= maxW ? base : Math.max(min, Math.floor(base * maxW / w));
218
+ }
219
+ function ellipsize(t, fs, maxW) {
220
+ if (maxW <= 0) return "";
221
+ if (estWidth(t, fs) <= maxW) return t;
222
+ let s = t;
223
+ while (s.length > 0 && estWidth(`${s}\u2026`, fs) > maxW) s = s.slice(0, -1);
224
+ return `${s}\u2026`;
225
+ }
226
+ function wrapText(t, fs, maxW, maxLines) {
227
+ const words = t.split(/\s+/).filter(Boolean);
228
+ const lines = [];
229
+ let cur = "";
230
+ for (const w of words) {
231
+ const trial = cur ? `${cur} ${w}` : w;
232
+ if (estWidth(trial, fs) <= maxW) {
233
+ cur = trial;
234
+ } else if (!cur) {
235
+ cur = w;
236
+ } else if (lines.length + 1 < maxLines) {
237
+ lines.push(cur);
238
+ cur = w;
239
+ } else {
240
+ cur = trial;
241
+ }
242
+ }
243
+ if (cur) lines.push(cur);
244
+ return lines.map((l) => ellipsize(l, fs, maxW));
245
+ }
246
+ function drawSunMoon(parent, cx, cy, up, sw, scale = 1) {
247
+ const icon = parent.append("g").attr("data-dgmo-clock-sun-icon", "").attr(
248
+ "transform",
249
+ scale === 1 ? `translate(${cx},${cy})` : `translate(${cx},${cy}) scale(${scale})`
250
+ );
251
+ const sunG = icon.append("g").attr("data-clock-glyph", "sun").attr("display", up ? "inline" : "none");
252
+ sunG.append("circle").attr("r", 2.5).attr("fill", sw.sunIcon);
253
+ for (let k = 0; k < 8; k++) {
254
+ const a = k * Math.PI / 4;
255
+ sunG.append("line").attr("x1", 3.2 * Math.cos(a)).attr("y1", 3.2 * Math.sin(a)).attr("x2", 4.6 * Math.cos(a)).attr("y2", 4.6 * Math.sin(a)).attr("stroke", sw.sunIcon).attr("stroke-width", 1).attr("stroke-linecap", "round");
256
+ }
257
+ icon.append("g").attr("data-clock-glyph", "moon").attr("display", up ? "none" : "inline").append("path").attr(
258
+ "d",
259
+ "M1.85,-3.32 A3.8,3.8 0 1,0 1.85,3.32 A3.4,3.4 0 0,1 1.85,-3.32 Z"
260
+ ).attr("fill", sw.moonIcon);
261
+ }
262
+ function hourLabel(min, hours12) {
263
+ const h = Math.floor(min / 60);
264
+ const m = min % 60;
265
+ const mm = m ? `:${String(m).padStart(2, "0")}` : "";
266
+ if (!hours12) return `${h}${mm}`;
267
+ const ap = h < 12 ? "am" : "pm";
268
+ const hr = h % 12 === 0 ? 12 : h % 12;
269
+ return `${hr}${mm}${ap}`;
270
+ }
271
+ var WEEKDAY_ABBR = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
272
+ function daysLabel(days) {
273
+ const on = WEEKDAY_ABBR.filter((d) => days[d]);
274
+ if (on.length === 5 && days["Mon"] && days["Fri"] && !days["Sat"] && !days["Sun"])
275
+ return "Mon\u2013Fri";
276
+ return on.join(", ");
277
+ }
278
+ function buildSwatches(palette, muted) {
279
+ const bg = palette.bg;
280
+ const day = resolveColor("orange", palette) ?? "#d98a1f";
281
+ const night = resolveColor("blue", palette) ?? "#4864b0";
282
+ const ok = resolveColor("green", palette) ?? "#3f9e59";
283
+ const soon = resolveColor("orange", palette) ?? "#c9761a";
284
+ return {
285
+ day,
286
+ night,
287
+ dayTint: mix(day, bg, 14),
288
+ nightTint: mix(night, bg, 14),
289
+ ok,
290
+ soon,
291
+ off: muted,
292
+ okSoft: mix(ok, bg, 14),
293
+ soonSoft: mix(soon, bg, 14),
294
+ offSoft: mix(muted, bg, 16),
295
+ // Sundown indicator: a yellow sun by day, a blue moon by night.
296
+ sunIcon: resolveColor("yellow", palette) ?? "#f4b400",
297
+ moonIcon: night
298
+ };
299
+ }
300
+ function renderClock(container, parsed, palette, isDark, exportDims) {
301
+ d3Selection.select(container).selectAll(":not([data-d3-tooltip])").remove();
302
+ const avail = exportDims?.width ?? container.clientWidth;
303
+ const heightHint = exportDims?.height ?? container.clientHeight;
304
+ if (avail <= 0) return;
305
+ const width = exportDims?.width ?? Math.min(720, Math.max(460, avail));
306
+ const now = Date.now();
307
+ const baseBg = themeBaseBg(palette, isDark);
308
+ const muted = mix(palette.text, baseBg, 55);
309
+ const faint = mix(palette.text, baseBg, 72);
310
+ const line2 = mix(palette.text, palette.bg, 76);
311
+ const cardFill = mix(palette.text, palette.bg, 8);
312
+ const sw = buildSwatches(palette, muted);
313
+ const padX = Math.max(20, Math.round(width * 0.04));
314
+ const padY = 20;
315
+ const rightX = width - padX;
316
+ const rowH = 84;
317
+ 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 ?? "Clock"} \u2014 world clocks`).style("font-family", FONT_FAMILY);
318
+ const bgRect = svg.append("rect").attr("width", width).attr("fill", palette.bg);
319
+ const cardM = 8;
320
+ const card = svg.append("rect").attr("x", cardM).attr("y", cardM).attr("width", width - 2 * cardM).attr("rx", 14).attr("fill", cardFill).attr("stroke", mix(palette.text, palette.bg, 40)).attr("stroke-width", 1);
321
+ clipSeq += 1;
322
+ const clipId = `dgmo-clock-clip-${clipSeq}`;
323
+ const clipRect = svg.append("clipPath").attr("id", clipId).append("rect").attr("x", cardM).attr("y", cardM).attr("width", width - 2 * cardM).attr("rx", 14);
324
+ const anyLane = parsed.colorBy !== "none" || parsed.entries.some((e) => e.color);
325
+ const hasTitle = Boolean(parsed.title && !parsed.noTitle);
326
+ let y = padY;
327
+ if (parsed.title && !parsed.noTitle) {
328
+ const titleFont = 20;
329
+ const meta = parsed.work ? `${hourLabel(parsed.work.startMin, parsed.hours12)}\u2013${hourLabel(parsed.work.endMin, parsed.hours12)} \xB7 ${daysLabel(parsed.work.days)}` : null;
330
+ const metaW = meta ? estWidth(meta, 12) + 16 : 0;
331
+ svg.append("text").attr("x", padX).attr("y", y + titleFont).attr("fill", palette.text).attr("font-family", FONT_FAMILY).attr("font-size", titleFont).attr("font-weight", 650).attr("data-line-number", parsed.titleLineNumber).text(ellipsize(parsed.title, titleFont, rightX - padX - metaW));
332
+ if (meta) {
333
+ svg.append("text").attr("x", rightX).attr("y", y + titleFont - 3).attr("text-anchor", "end").attr("fill", faint).attr("font-family", FONT_FAMILY).attr("font-size", 12).attr("font-weight", 500).text(meta);
334
+ }
335
+ y += titleFont + 12;
336
+ svg.append("line").attr("x1", cardM).attr("x2", width - cardM).attr("y1", y).attr("y2", y).attr("stroke", mix(palette.text, palette.bg, 22)).attr("stroke-width", 1);
337
+ y += 1;
338
+ }
339
+ const rowsTop = !hasTitle && anyLane ? cardM : y;
340
+ const body = svg.append("g").attr("clip-path", `url(#${clipId})`);
341
+ const col = {
342
+ text: palette.text,
343
+ muted,
344
+ faint,
345
+ line2,
346
+ tick: mix(palette.text, palette.bg, 35),
347
+ cardFill,
348
+ sw,
349
+ palette
350
+ };
351
+ let bannerH;
352
+ if (parsed.columns) {
353
+ bannerH = drawColumns(body, parsed, now, rowsTop, { width, cardM }, col);
354
+ } else {
355
+ let leftColW = rowH - 20;
356
+ let mainW = 0;
357
+ if (parsed.face === "digital") {
358
+ let secW = 0;
359
+ for (const e of parsed.entries) {
360
+ const p = zoneParts(e.zone, now);
361
+ const t = formatTime(p.h, p.m, p.s, parsed.hours12);
362
+ mainW = Math.max(mainW, estWidth(t.main, 48));
363
+ secW = Math.max(secW, estWidth(`:${t.sec}`, 16), estWidth(t.ap, 16));
364
+ }
365
+ leftColW = Math.max(92, mainW + 5 + secW);
366
+ }
367
+ parsed.entries.forEach((entry, i) => {
368
+ drawRow(
369
+ body,
370
+ entry,
371
+ i,
372
+ parsed,
373
+ now,
374
+ rowsTop + i * rowH,
375
+ rowH,
376
+ { padX, rightX, width, leftColW, mainW },
377
+ col
378
+ );
379
+ });
380
+ const rowsBottom = rowsTop + parsed.entries.length * rowH;
381
+ const bottomMargin = anyLane ? cardM : padY;
382
+ bannerH = Math.max(rowsBottom + bottomMargin, heightHint > 0 ? 0 : 120);
383
+ }
384
+ clipRect.attr("height", bannerH - 2 * cardM);
385
+ svg.attr("height", bannerH).attr("viewBox", `0 0 ${width} ${bannerH}`);
386
+ bgRect.attr("height", bannerH);
387
+ card.attr("height", bannerH - 2 * cardM);
388
+ }
389
+ function drawRow(svg, entry, index, parsed, now, rowTop, rowH, geom, col) {
390
+ const { padX } = geom;
391
+ const { text, muted, line2, tick, sw, cardFill } = col;
392
+ const center = rowTop + rowH / 2;
393
+ const parts = zoneParts(entry.zone, now);
394
+ const hasCoords = entry.lat !== null && entry.lon !== null;
395
+ const sun = parsed.sun && hasCoords ? sunLine(now, entry.lat, entry.lon) : null;
396
+ const up = sun ? sun.up : parts.h >= 6 && parts.h < 18;
397
+ const stColor = up ? sw.day : sw.night;
398
+ const stTint = up ? sw.dayTint : sw.nightTint;
399
+ const ts = formatTime(parts.h, parts.m, parts.s, parsed.hours12);
400
+ const work = parsed.work ? {
401
+ startMin: parsed.work.startMin,
402
+ endMin: parsed.work.endMin,
403
+ days: parsed.work.days
404
+ } : null;
405
+ const status = workStatus(parts, work);
406
+ const auto = resolveColorBy(parsed.colorBy, entry, index, {
407
+ up,
408
+ status,
409
+ localHour: parts.h,
410
+ sw,
411
+ palette: col.palette,
412
+ cardFill
413
+ });
414
+ const rightBlockW = 178;
415
+ const rightColLeft = geom.rightX - rightBlockW;
416
+ const g = svg.append("g").attr("data-line-number", entry.lineNumber);
417
+ if (auto) {
418
+ g.append("rect").attr("x", 9).attr("y", rowTop).attr("width", geom.width - 18).attr("height", rowH).attr("fill", auto.laneTint);
419
+ }
420
+ g.attr("data-dgmo-clock", "").attr("data-dgmo-clock-zone", entry.zone).attr("data-dgmo-clock-face", parsed.face).attr("data-dgmo-clock-hours12", parsed.hours12 ? "1" : "0").attr("data-dgmo-clock-sun", sun ? "1" : "0").attr("data-dgmo-clock-c-day", sw.day).attr("data-dgmo-clock-c-night", sw.night).attr("data-dgmo-clock-c-day-soft", sw.dayTint).attr("data-dgmo-clock-c-night-soft", sw.nightTint).attr("data-dgmo-clock-c-ok", sw.ok).attr("data-dgmo-clock-c-soon", sw.soon).attr("data-dgmo-clock-c-off", sw.off).attr("data-dgmo-clock-c-ok-soft", sw.okSoft).attr("data-dgmo-clock-c-soon-soft", sw.soonSoft).attr("data-dgmo-clock-c-off-soft", sw.offSoft);
421
+ if (entry.lat !== null) g.attr("data-dgmo-clock-lat", entry.lat);
422
+ if (entry.lon !== null) g.attr("data-dgmo-clock-lon", entry.lon);
423
+ if (parsed.work) {
424
+ g.attr("data-dgmo-clock-work-start", parsed.work.startMin).attr("data-dgmo-clock-work-end", parsed.work.endMin).attr(
425
+ "data-dgmo-clock-work-days",
426
+ WEEKDAY_ABBR.filter((d) => parsed.work.days[d]).join(",")
427
+ );
428
+ }
429
+ const contentLeft = padX + 4;
430
+ const timeColor = auto?.solid ?? text;
431
+ const faceFill = auto ? mix(auto.solid, cardFill, 20) : stTint;
432
+ const ringColor = auto?.solid ?? line2;
433
+ const accentColor = auto?.solid ?? stColor;
434
+ if (auto) {
435
+ g.attr("data-dgmo-clock-auto-solid", auto.solid).attr(
436
+ "data-dgmo-clock-auto-face",
437
+ faceFill
438
+ );
439
+ }
440
+ if (parsed.face === "analog") {
441
+ const size = rowH - 20;
442
+ const fx = contentLeft;
443
+ const fy = center - size / 2;
444
+ const fg = g.append("g").attr("transform", `translate(${fx},${fy}) scale(${size / 100})`);
445
+ fg.append("circle").attr("data-dgmo-clock-facebg", "").attr("cx", 50).attr("cy", 50).attr("r", 47).attr("fill", faceFill);
446
+ fg.append("circle").attr("data-dgmo-clock-facering", "").attr("cx", 50).attr("cy", 50).attr("r", 47).attr("fill", "none").attr("stroke", ringColor).attr("stroke-width", auto ? 1.6 : 1.4);
447
+ for (let k = 0; k < 12; k++) {
448
+ const a = k * 30 * Math.PI / 180;
449
+ fg.append("line").attr("x1", 50 + 39 * Math.sin(a)).attr("y1", 50 - 39 * Math.cos(a)).attr("x2", 50 + 46 * Math.sin(a)).attr("y2", 50 - 46 * Math.cos(a)).attr("stroke", tick).attr("stroke-width", 1.8);
450
+ }
451
+ const ang = handAngles(parts.h, parts.m, parts.s);
452
+ fg.append("line").attr("data-dgmo-clock-hand", "h").attr("x1", 50).attr("y1", 50).attr("x2", 50).attr("y2", 28).attr("stroke", text).attr("stroke-width", 4).attr("stroke-linecap", "round").attr("transform", `rotate(${ang.hour} 50 50)`);
453
+ fg.append("line").attr("data-dgmo-clock-hand", "m").attr("x1", 50).attr("y1", 50).attr("x2", 50).attr("y2", 17).attr("stroke", text).attr("stroke-width", 2.6).attr("stroke-linecap", "round").attr("transform", `rotate(${ang.minute} 50 50)`);
454
+ fg.append("line").attr("data-dgmo-clock-hand", "s").attr("x1", 50).attr("y1", 55).attr("x2", 50).attr("y2", 14).attr("stroke", accentColor).attr("stroke-width", 1.3).attr("stroke-linecap", "round").attr("transform", `rotate(${ang.second} 50 50)`);
455
+ fg.append("circle").attr("data-dgmo-clock-center", "").attr("cx", 50).attr("cy", 50).attr("r", 2.6).attr("fill", accentColor);
456
+ } else {
457
+ const mainFont = 48;
458
+ const baseY = center + 16;
459
+ const capTop = baseY - mainFont * 0.7;
460
+ g.append("text").attr("data-dgmo-clock-digital", "").attr("data-dgmo-clock-digital-part", "main").attr("x", contentLeft).attr("y", baseY).attr("fill", timeColor).attr("font-family", FONT_FAMILY).attr("font-size", mainFont).attr("font-weight", 600).style("font-variant-numeric", "tabular-nums").text(ts.main);
461
+ const sf = 20;
462
+ const mainW = [...ts.main].reduce(
463
+ (w, c) => w + mainFont * (c === ":" ? 0.28 : 0.6),
464
+ 0
465
+ );
466
+ const stackX = contentLeft + mainW + 5;
467
+ g.append("text").attr("data-dgmo-clock-digital-part", "sec").attr("x", stackX).attr("y", capTop + sf * 0.72).attr("fill", muted).attr("font-family", FONT_FAMILY).attr("font-size", sf).attr("font-weight", 600).style("font-variant-numeric", "tabular-nums").text(`:${ts.sec}`);
468
+ if (ts.ap)
469
+ g.append("text").attr("data-dgmo-clock-digital-part", "ap").attr("x", stackX).attr("y", baseY).attr("fill", muted).attr("font-family", FONT_FAMILY).attr("font-size", sf).attr("font-weight", 600).text(ts.ap);
470
+ }
471
+ const midLeft = contentLeft + geom.leftColW + 26;
472
+ const midMaxW = Math.max(40, rightColLeft - 12 - midLeft);
473
+ const availH = rowH - 12;
474
+ const ladder = [48, 40, 34, 28, 24, 20, 17];
475
+ let aliasFont = 17;
476
+ let aliasLines = [];
477
+ for (const f of ladder) {
478
+ const maxLines = Math.max(1, Math.floor(availH / (f + 4)));
479
+ const ls = wrapText(entry.label, f, midMaxW, maxLines);
480
+ if (!ls.some((l) => l.endsWith("\u2026"))) {
481
+ aliasFont = f;
482
+ aliasLines = ls;
483
+ break;
484
+ }
485
+ }
486
+ if (aliasLines.length === 0) {
487
+ const maxLines = Math.max(1, Math.floor(availH / 21));
488
+ aliasLines = wrapText(entry.label, 17, midMaxW, maxLines);
489
+ }
490
+ const aliasLh = aliasFont + 4;
491
+ const firstBase = aliasLines.length === 1 ? center + 16 : center - aliasLines.length * aliasLh / 2 + aliasFont * 0.72;
492
+ const aliasFill = auto?.solid ?? mix(muted, text, Math.round((aliasFont - 17) / 31 * 55));
493
+ aliasLines.forEach((ln, i) => {
494
+ g.append("text").attr("x", midLeft).attr("y", firstBase + i * aliasLh).attr("fill", aliasFill).attr("font-family", FONT_FAMILY).attr("font-size", aliasFont).attr("font-weight", 650).text(ln);
495
+ });
496
+ const iconX = rightColLeft + 6;
497
+ const textX = rightColLeft + 20;
498
+ const textMax = geom.rightX - textX;
499
+ const lines = [];
500
+ if (entry.label !== entry.place) lines.push({ kind: "place" });
501
+ if (status) lines.push({ kind: "avail" });
502
+ if (sun) lines.push({ kind: "sun" });
503
+ const lh = 23;
504
+ const top = center + 10 - (lines.length - 1) * lh / 2;
505
+ lines.forEach((ln, i) => {
506
+ const yy = top + i * lh;
507
+ if (ln.kind === "place") {
508
+ g.append("path").attr("transform", `translate(${iconX},${yy - 5}) scale(1.25)`).attr("d", "M0,4 L-2.3,-0.6 A2.6,2.6 0 1 1 2.3,-0.6 Z").attr("fill", muted);
509
+ g.append("text").attr("x", textX).attr("y", yy).attr("fill", muted).attr("font-family", FONT_FAMILY).attr("font-size", 14).attr("font-weight", 500).text(ellipsize(entry.place, 14, textMax));
510
+ } else if (ln.kind === "avail" && status) {
511
+ const stCol = status.cls === "ok" ? sw.ok : status.cls === "soon" ? sw.soon : sw.off;
512
+ const dot = g.append("circle").attr("data-dgmo-clock-status-dot", "").attr("cx", iconX).attr("cy", yy - 5).attr("r", 5);
513
+ if (status.cls === "off")
514
+ dot.attr("fill", "none").attr("stroke", stCol).attr("stroke-width", 1.6);
515
+ else dot.attr("fill", stCol).attr("stroke", "none");
516
+ g.append("text").attr("data-dgmo-clock-status", "").attr("x", textX).attr("y", yy).attr("fill", stCol).attr("font-family", FONT_FAMILY).attr("font-size", 14).attr("font-weight", 600).text(ellipsize(status.text, 14, textMax));
517
+ } else if (ln.kind === "sun" && sun) {
518
+ drawSunMoon(g, iconX, yy - 5, up, sw, 1.25);
519
+ g.append("text").attr("data-dgmo-clock-sun-line", "").attr("x", textX).attr("y", yy).attr("fill", muted).attr("font-family", FONT_FAMILY).attr("font-size", 13.5).text(ellipsize(sun.text, 13.5, textMax));
520
+ }
521
+ });
522
+ }
523
+ function bakeAnchors(g, entry, parsed, sun, sw) {
524
+ g.attr("data-dgmo-clock", "").attr("data-dgmo-clock-zone", entry.zone).attr("data-dgmo-clock-face", parsed.face).attr("data-dgmo-clock-hours12", parsed.hours12 ? "1" : "0").attr("data-dgmo-clock-sun", sun ? "1" : "0").attr("data-dgmo-clock-c-day", sw.day).attr("data-dgmo-clock-c-night", sw.night).attr("data-dgmo-clock-c-day-soft", sw.dayTint).attr("data-dgmo-clock-c-night-soft", sw.nightTint).attr("data-dgmo-clock-c-ok", sw.ok).attr("data-dgmo-clock-c-soon", sw.soon).attr("data-dgmo-clock-c-off", sw.off).attr("data-dgmo-clock-c-ok-soft", sw.okSoft).attr("data-dgmo-clock-c-soon-soft", sw.soonSoft).attr("data-dgmo-clock-c-off-soft", sw.offSoft);
525
+ if (entry.lat !== null) g.attr("data-dgmo-clock-lat", entry.lat);
526
+ if (entry.lon !== null) g.attr("data-dgmo-clock-lon", entry.lon);
527
+ if (parsed.work) {
528
+ g.attr("data-dgmo-clock-work-start", parsed.work.startMin).attr("data-dgmo-clock-work-end", parsed.work.endMin).attr(
529
+ "data-dgmo-clock-work-days",
530
+ WEEKDAY_ABBR.filter((d) => parsed.work.days[d]).join(",")
531
+ );
532
+ }
533
+ }
534
+ function drawColumns(body, parsed, now, top, geom, col) {
535
+ const { width, cardM } = geom;
536
+ const { text, muted, line2, tick, cardFill, sw } = col;
537
+ const n = Math.max(1, parsed.entries.length);
538
+ const colW = (width - 2 * cardM) / n;
539
+ const tints = [];
540
+ let maxBottom = top;
541
+ parsed.entries.forEach((entry, i) => {
542
+ const x0 = cardM + i * colW;
543
+ const cx = x0 + colW / 2;
544
+ const parts = zoneParts(entry.zone, now);
545
+ const hasCoords = entry.lat !== null && entry.lon !== null;
546
+ const sun = parsed.sun && hasCoords ? sunLine(now, entry.lat, entry.lon) : null;
547
+ const up = sun ? sun.up : parts.h >= 6 && parts.h < 18;
548
+ const ts = formatTime(parts.h, parts.m, parts.s, parsed.hours12);
549
+ const work = parsed.work ? {
550
+ startMin: parsed.work.startMin,
551
+ endMin: parsed.work.endMin,
552
+ days: parsed.work.days
553
+ } : null;
554
+ const status = workStatus(parts, work);
555
+ const stColor = up ? sw.day : sw.night;
556
+ const stTint = up ? sw.dayTint : sw.nightTint;
557
+ const auto = resolveColorBy(parsed.colorBy, entry, i, {
558
+ up,
559
+ status,
560
+ localHour: parts.h,
561
+ sw,
562
+ palette: col.palette,
563
+ cardFill
564
+ });
565
+ const timeColor = auto?.solid ?? text;
566
+ const faceFill = auto ? mix(auto.solid, cardFill, 20) : stTint;
567
+ const ringColor = auto?.solid ?? line2;
568
+ const accentColor = auto?.solid ?? stColor;
569
+ if (auto)
570
+ tints.push(
571
+ body.append("rect").attr("x", x0).attr("y", top).attr("width", colW).attr("fill", auto.laneTint)
572
+ );
573
+ const g = body.append("g").attr("data-line-number", entry.lineNumber);
574
+ bakeAnchors(g, entry, parsed, sun, sw);
575
+ if (auto) {
576
+ g.attr("data-dgmo-clock-auto-solid", auto.solid).attr(
577
+ "data-dgmo-clock-auto-face",
578
+ faceFill
579
+ );
580
+ }
581
+ let cy = top + (parsed.face === "analog" ? 22 : 36);
582
+ const innerW = colW - 16;
583
+ if (parsed.face === "analog") {
584
+ const size = Math.min(innerW, 96);
585
+ const fg = g.append("g").attr(
586
+ "transform",
587
+ `translate(${cx - size / 2},${cy}) scale(${size / 100})`
588
+ );
589
+ fg.append("circle").attr("data-dgmo-clock-facebg", "").attr("cx", 50).attr("cy", 50).attr("r", 47).attr("fill", faceFill);
590
+ fg.append("circle").attr("data-dgmo-clock-facering", "").attr("cx", 50).attr("cy", 50).attr("r", 47).attr("fill", "none").attr("stroke", ringColor).attr("stroke-width", auto ? 1.6 : 1.4);
591
+ for (let k = 0; k < 12; k++) {
592
+ const a = k * 30 * Math.PI / 180;
593
+ fg.append("line").attr("x1", 50 + 39 * Math.sin(a)).attr("y1", 50 - 39 * Math.cos(a)).attr("x2", 50 + 46 * Math.sin(a)).attr("y2", 50 - 46 * Math.cos(a)).attr("stroke", tick).attr("stroke-width", 1.8);
594
+ }
595
+ const ang = handAngles(parts.h, parts.m, parts.s);
596
+ fg.append("line").attr("data-dgmo-clock-hand", "h").attr("x1", 50).attr("y1", 50).attr("x2", 50).attr("y2", 28).attr("stroke", text).attr("stroke-width", 4).attr("stroke-linecap", "round").attr("transform", `rotate(${ang.hour} 50 50)`);
597
+ fg.append("line").attr("data-dgmo-clock-hand", "m").attr("x1", 50).attr("y1", 50).attr("x2", 50).attr("y2", 17).attr("stroke", text).attr("stroke-width", 2.6).attr("stroke-linecap", "round").attr("transform", `rotate(${ang.minute} 50 50)`);
598
+ fg.append("line").attr("data-dgmo-clock-hand", "s").attr("x1", 50).attr("y1", 55).attr("x2", 50).attr("y2", 14).attr("stroke", accentColor).attr("stroke-width", 1.3).attr("stroke-linecap", "round").attr("transform", `rotate(${ang.second} 50 50)`);
599
+ fg.append("circle").attr("data-dgmo-clock-center", "").attr("cx", 50).attr("cy", 50).attr("r", 2.6).attr("fill", accentColor);
600
+ cy += size + 6;
601
+ } else {
602
+ const sf = 13;
603
+ const tf = fitFont(ts.main, 44, innerW - 30, 20);
604
+ const mainW = [...ts.main].reduce(
605
+ (w, c) => w + tf * (c === ":" ? 0.28 : 0.6),
606
+ 0
607
+ );
608
+ const stackW = Math.max(estWidth(`:${ts.sec}`, sf), estWidth(ts.ap, sf));
609
+ const gLeft = cx - (mainW + 7 + stackW) / 2;
610
+ const baseY = cy + tf * 0.34;
611
+ g.append("text").attr("data-dgmo-clock-digital", "").attr("data-dgmo-clock-digital-part", "main").attr("x", gLeft).attr("y", baseY).attr("fill", timeColor).attr("font-family", FONT_FAMILY).attr("font-size", tf).attr("font-weight", 600).style("font-variant-numeric", "tabular-nums").text(ts.main);
612
+ const stackX = gLeft + mainW + 7;
613
+ g.append("text").attr("data-dgmo-clock-digital-part", "sec").attr("x", stackX).attr("y", baseY - tf * 0.32).attr("fill", muted).attr("font-family", FONT_FAMILY).attr("font-size", sf).attr("font-weight", 500).text(`:${ts.sec}`);
614
+ if (ts.ap)
615
+ g.append("text").attr("data-dgmo-clock-digital-part", "ap").attr("x", stackX).attr("y", baseY).attr("fill", muted).attr("font-family", FONT_FAMILY).attr("font-size", sf).attr("font-weight", 500).text(ts.ap);
616
+ cy += tf + 8;
617
+ }
618
+ const amax = colW - 14;
619
+ let af = 14;
620
+ let alines = [];
621
+ for (const f of [26, 22, 19, 16, 14]) {
622
+ const ml = Math.max(1, Math.floor(70 / (f + 3)));
623
+ const ls = wrapText(entry.label, f, amax, ml);
624
+ if (!ls.some((l) => l.endsWith("\u2026"))) {
625
+ af = f;
626
+ alines = ls;
627
+ break;
628
+ }
629
+ }
630
+ if (!alines.length) alines = wrapText(entry.label, 14, amax, 3);
631
+ const alh = af + 3;
632
+ const aFill = auto?.solid ?? mix(muted, text, Math.round((af - 14) / 12 * 55));
633
+ alines.forEach(
634
+ (ln, j) => g.append("text").attr("x", cx).attr("y", cy + af * 0.72 + j * alh).attr("text-anchor", "middle").attr("fill", aFill).attr("font-family", FONT_FAMILY).attr("font-size", af).attr("font-weight", 650).text(ln)
635
+ );
636
+ cy += alines.length * alh + 12;
637
+ const kinds = [];
638
+ if (entry.label !== entry.place) kinds.push("place");
639
+ if (status) kinds.push("avail");
640
+ if (sun) kinds.push("sun");
641
+ const iconX = x0 + 16;
642
+ const textX = x0 + 28;
643
+ const tmax = colW - 40;
644
+ kinds.forEach((kind, j) => {
645
+ const yy = cy + j * 20;
646
+ if (kind === "place") {
647
+ g.append("path").attr("transform", `translate(${iconX},${yy - 4})`).attr("d", "M0,4 L-2.3,-0.6 A2.6,2.6 0 1 1 2.3,-0.6 Z").attr("fill", muted);
648
+ g.append("text").attr("x", textX).attr("y", yy).attr("fill", muted).attr("font-family", FONT_FAMILY).attr("font-size", 12).text(ellipsize(entry.place, 12, tmax));
649
+ } else if (kind === "avail" && status) {
650
+ const stCol = status.cls === "ok" ? sw.ok : status.cls === "soon" ? sw.soon : sw.off;
651
+ const dot = g.append("circle").attr("data-dgmo-clock-status-dot", "").attr("cx", iconX).attr("cy", yy - 4).attr("r", 4);
652
+ if (status.cls === "off")
653
+ dot.attr("fill", "none").attr("stroke", stCol).attr("stroke-width", 1.4);
654
+ else dot.attr("fill", stCol).attr("stroke", "none");
655
+ g.append("text").attr("data-dgmo-clock-status", "").attr("x", textX).attr("y", yy).attr("fill", stCol).attr("font-family", FONT_FAMILY).attr("font-size", 12).attr("font-weight", 600).text(ellipsize(status.text, 12, tmax));
656
+ } else if (kind === "sun" && sun) {
657
+ drawSunMoon(g, iconX, yy - 4, up, sw, 1);
658
+ g.append("text").attr("data-dgmo-clock-sun-line", "").attr("x", textX).attr("y", yy).attr("fill", muted).attr("font-family", FONT_FAMILY).attr("font-size", 11.5).text(ellipsize(sun.text, 11.5, tmax));
659
+ }
660
+ });
661
+ const bottom = kinds.length ? cy + (kinds.length - 1) * 20 + 8 : cy;
662
+ if (bottom > maxBottom) maxBottom = bottom;
663
+ });
664
+ const colBodyH = maxBottom - top + 14;
665
+ tints.forEach((r) => r.attr("height", colBodyH));
666
+ return top + colBodyH + cardM;
667
+ }
668
+ function renderClockForExport(container, parsed, palette, isDark, exportDims) {
669
+ renderClock(container, parsed, palette, isDark, exportDims);
670
+ }
671
+
672
+ export {
673
+ zoneParts,
674
+ formatTime,
675
+ workStatus,
676
+ sunLine,
677
+ handAngles,
678
+ renderClock,
679
+ renderClockForExport
680
+ };
681
+ //# sourceMappingURL=chunk-7PQYTZMA.js.map