@readdy/anim 0.0.21

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 (310) hide show
  1. package/animations/button/3d-flip/index.js +60 -0
  2. package/animations/button/3d-flip/react.tsx +29 -0
  3. package/animations/button/3d-flip/style.css +17 -0
  4. package/animations/button/blur-fade-in/index.js +21 -0
  5. package/animations/button/blur-fade-in/react.tsx +26 -0
  6. package/animations/button/blur-fade-in/style.css +27 -0
  7. package/animations/button/border-beam/index.js +172 -0
  8. package/animations/button/border-beam/react.tsx +55 -0
  9. package/animations/button/border-beam/style.css +59 -0
  10. package/animations/button/bounce-elastic/index.js +21 -0
  11. package/animations/button/bounce-elastic/react.tsx +26 -0
  12. package/animations/button/bounce-elastic/style.css +31 -0
  13. package/animations/button/bubble-button/index.js +317 -0
  14. package/animations/button/bubble-button/react.tsx +19 -0
  15. package/animations/button/bubble-button/style.css +245 -0
  16. package/animations/button/confetti-button/index.js +66 -0
  17. package/animations/button/confetti-button/react.tsx +30 -0
  18. package/animations/button/confetti-button/style.css +48 -0
  19. package/animations/button/glow-cta/index.js +69 -0
  20. package/animations/button/glow-cta/react.tsx +45 -0
  21. package/animations/button/glow-cta/style.css +78 -0
  22. package/animations/button/magnetic-hover/index.js +61 -0
  23. package/animations/button/magnetic-hover/react.tsx +29 -0
  24. package/animations/button/magnetic-hover/style.css +18 -0
  25. package/animations/button/pulse/index.js +21 -0
  26. package/animations/button/pulse/react.tsx +26 -0
  27. package/animations/button/pulse/style.css +24 -0
  28. package/animations/button/rainbow-button/index.js +21 -0
  29. package/animations/button/rainbow-button/react.tsx +26 -0
  30. package/animations/button/rainbow-button/style.css +54 -0
  31. package/animations/button/shimmer-border/index.js +28 -0
  32. package/animations/button/shimmer-border/react.tsx +41 -0
  33. package/animations/button/shimmer-border/style.css +53 -0
  34. package/animations/button/sketch-button/index.js +16 -0
  35. package/animations/button/sketch-button/react.tsx +19 -0
  36. package/animations/button/sketch-button/style.css +25 -0
  37. package/animations/card/blur-rise/index.js +21 -0
  38. package/animations/card/blur-rise/react.tsx +26 -0
  39. package/animations/card/blur-rise/style.css +27 -0
  40. package/animations/card/bounce-in-bottom/index.js +21 -0
  41. package/animations/card/bounce-in-bottom/react.tsx +26 -0
  42. package/animations/card/bounce-in-bottom/style.css +31 -0
  43. package/animations/card/card-fan-spread/index.js +146 -0
  44. package/animations/card/card-fan-spread/react.tsx +35 -0
  45. package/animations/card/card-fan-spread/style.css +90 -0
  46. package/animations/card/card-flip/index.js +203 -0
  47. package/animations/card/card-flip/react.tsx +35 -0
  48. package/animations/card/card-flip/style.css +71 -0
  49. package/animations/card/float-idle/index.js +21 -0
  50. package/animations/card/float-idle/react.tsx +26 -0
  51. package/animations/card/float-idle/style.css +21 -0
  52. package/animations/card/image-magnifier/index.js +333 -0
  53. package/animations/card/image-magnifier/react.tsx +31 -0
  54. package/animations/card/image-magnifier/style.css +42 -0
  55. package/animations/card/image-zoom-rotate/index.js +48 -0
  56. package/animations/card/image-zoom-rotate/react.tsx +31 -0
  57. package/animations/card/image-zoom-rotate/style.css +20 -0
  58. package/animations/card/pop-in-stack/index.js +25 -0
  59. package/animations/card/pop-in-stack/react.tsx +33 -0
  60. package/animations/card/pop-in-stack/style.css +25 -0
  61. package/animations/card/reveal-from-top/index.js +21 -0
  62. package/animations/card/reveal-from-top/react.tsx +26 -0
  63. package/animations/card/reveal-from-top/style.css +28 -0
  64. package/animations/card/rgb-split-glitch/index.js +28 -0
  65. package/animations/card/rgb-split-glitch/react.tsx +41 -0
  66. package/animations/card/rgb-split-glitch/style.css +33 -0
  67. package/animations/card/tilted-card/index.js +64 -0
  68. package/animations/card/tilted-card/react.tsx +33 -0
  69. package/animations/card/tilted-card/style.css +27 -0
  70. package/animations/header/anime-splittext/index.js +108 -0
  71. package/animations/header/anime-splittext/react.tsx +30 -0
  72. package/animations/header/anime-splittext/style.css +71 -0
  73. package/animations/header/bounce-in-down/index.js +40 -0
  74. package/animations/header/bounce-in-down/react.tsx +29 -0
  75. package/animations/header/bounce-in-down/style.css +40 -0
  76. package/animations/header/fly-in-chars/index.js +46 -0
  77. package/animations/header/fly-in-chars/react.tsx +30 -0
  78. package/animations/header/fly-in-chars/style.css +29 -0
  79. package/animations/header/gradient-text/index.js +21 -0
  80. package/animations/header/gradient-text/react.tsx +26 -0
  81. package/animations/header/gradient-text/style.css +28 -0
  82. package/animations/header/letter-bounce/index.js +33 -0
  83. package/animations/header/letter-bounce/react.tsx +34 -0
  84. package/animations/header/letter-bounce/style.css +25 -0
  85. package/animations/header/roll-in/index.js +40 -0
  86. package/animations/header/roll-in/react.tsx +29 -0
  87. package/animations/header/roll-in/style.css +31 -0
  88. package/animations/header/shimmer-text/index.js +16 -0
  89. package/animations/header/shimmer-text/react.tsx +28 -0
  90. package/animations/header/shimmer-text/style.css +29 -0
  91. package/animations/header/shuffle/index.js +118 -0
  92. package/animations/header/shuffle/react.tsx +50 -0
  93. package/animations/header/shuffle/style.css +25 -0
  94. package/animations/header/split-text/index.js +72 -0
  95. package/animations/header/split-text/react.tsx +38 -0
  96. package/animations/header/split-text/style.css +31 -0
  97. package/animations/header/text-type/index.js +267 -0
  98. package/animations/header/text-type/react.tsx +63 -0
  99. package/animations/header/text-type/style.css +37 -0
  100. package/animations/header/word-curtain-reveal/index.js +97 -0
  101. package/animations/header/word-curtain-reveal/react.tsx +30 -0
  102. package/animations/header/word-curtain-reveal/style.css +39 -0
  103. package/dist/button/3d-flip/react.js +21 -0
  104. package/dist/button/3d-flip.js +61 -0
  105. package/dist/button/blur-fade-in/react.js +28 -0
  106. package/dist/button/blur-fade-in.js +17 -0
  107. package/dist/button/border-beam/react.js +22 -0
  108. package/dist/button/border-beam.js +168 -0
  109. package/dist/button/bounce-elastic/react.js +28 -0
  110. package/dist/button/bounce-elastic.js +17 -0
  111. package/dist/button/bubble-button/react.js +20 -0
  112. package/dist/button/bubble-button.js +318 -0
  113. package/dist/button/confetti-button/react.js +21 -0
  114. package/dist/button/confetti-button.js +67 -0
  115. package/dist/button/glow-cta/react.js +23 -0
  116. package/dist/button/glow-cta.js +65 -0
  117. package/dist/button/magnetic-hover/react.js +21 -0
  118. package/dist/button/magnetic-hover.js +62 -0
  119. package/dist/button/pulse/react.js +28 -0
  120. package/dist/button/pulse.js +17 -0
  121. package/dist/button/rainbow-button/react.js +28 -0
  122. package/dist/button/rainbow-button.js +17 -0
  123. package/dist/button/shimmer-border/react.js +22 -0
  124. package/dist/button/shimmer-border.js +24 -0
  125. package/dist/button/sketch-button/react.js +20 -0
  126. package/dist/button/sketch-button.js +17 -0
  127. package/dist/card/blur-rise/react.js +28 -0
  128. package/dist/card/blur-rise.js +17 -0
  129. package/dist/card/bounce-in-bottom/react.js +28 -0
  130. package/dist/card/bounce-in-bottom.js +17 -0
  131. package/dist/card/card-fan-spread/react.js +20 -0
  132. package/dist/card/card-fan-spread.js +147 -0
  133. package/dist/card/float-idle/react.js +28 -0
  134. package/dist/card/float-idle.js +17 -0
  135. package/dist/card/image-magnifier/react.js +22 -0
  136. package/dist/card/image-magnifier.js +334 -0
  137. package/dist/card/image-zoom-rotate/react.js +21 -0
  138. package/dist/card/image-zoom-rotate.js +49 -0
  139. package/dist/card/pop-in-stack/react.js +20 -0
  140. package/dist/card/pop-in-stack.js +26 -0
  141. package/dist/card/reveal-from-top/react.js +28 -0
  142. package/dist/card/reveal-from-top.js +17 -0
  143. package/dist/card/rgb-split-glitch/react.js +22 -0
  144. package/dist/card/rgb-split-glitch.js +24 -0
  145. package/dist/card/tilted-card/react.js +21 -0
  146. package/dist/card/tilted-card.js +65 -0
  147. package/dist/chunks/constants-EnH6-Pz4.js +66 -0
  148. package/dist/chunks/constants-ZTHic1pf.js +66 -0
  149. package/dist/chunks/pointer-follow-B3RFnn_q.js +93 -0
  150. package/dist/chunks/pointer-follow-BETANySn.js +93 -0
  151. package/dist/chunks/reduced-motion-BpQYuEzK.js +17 -0
  152. package/dist/chunks/reduced-motion-HX79Ac8G.js +17 -0
  153. package/dist/chunks/resolve-card-media-Cj3V_oms.js +43 -0
  154. package/dist/chunks/resolve-card-media-DBIU-duL.js +43 -0
  155. package/dist/chunks/text-split-D02jltVh.js +191 -0
  156. package/dist/chunks/text-split-frOR4UpH.js +191 -0
  157. package/dist/full.css +1 -0
  158. package/dist/full.js +3192 -0
  159. package/dist/header/anime-splittext/react.js +22 -0
  160. package/dist/header/anime-splittext.js +109 -0
  161. package/dist/header/bounce-in-down/react.js +32 -0
  162. package/dist/header/bounce-in-down.js +36 -0
  163. package/dist/header/fly-in-chars/react.js +23 -0
  164. package/dist/header/fly-in-chars.js +47 -0
  165. package/dist/header/gradient-text/react.js +28 -0
  166. package/dist/header/gradient-text.js +17 -0
  167. package/dist/header/letter-bounce/react.js +23 -0
  168. package/dist/header/letter-bounce.js +34 -0
  169. package/dist/header/roll-in/react.js +32 -0
  170. package/dist/header/roll-in.js +36 -0
  171. package/dist/header/shimmer-text/react.js +27 -0
  172. package/dist/header/shimmer-text.js +17 -0
  173. package/dist/header/shuffle/react.js +30 -0
  174. package/dist/header/shuffle.js +119 -0
  175. package/dist/header/split-text/react.js +26 -0
  176. package/dist/header/split-text.js +73 -0
  177. package/dist/header/text-type/react.js +43 -0
  178. package/dist/header/text-type.js +268 -0
  179. package/dist/header/word-curtain-reveal/react.js +22 -0
  180. package/dist/header/word-curtain-reveal.js +98 -0
  181. package/dist/meta.json +6 -0
  182. package/dist/metadata.json +1051 -0
  183. package/dist/react.css +1 -0
  184. package/dist/types/animations/button/3d-flip/index.d.ts +3 -0
  185. package/dist/types/animations/button/3d-flip/react.d.ts +8 -0
  186. package/dist/types/animations/button/blur-fade-in/index.d.ts +3 -0
  187. package/dist/types/animations/button/blur-fade-in/react.d.ts +13 -0
  188. package/dist/types/animations/button/border-beam/index.d.ts +3 -0
  189. package/dist/types/animations/button/border-beam/react.d.ts +25 -0
  190. package/dist/types/animations/button/bounce-elastic/index.d.ts +3 -0
  191. package/dist/types/animations/button/bounce-elastic/react.d.ts +13 -0
  192. package/dist/types/animations/button/bubble-button/index.d.ts +3 -0
  193. package/dist/types/animations/button/bubble-button/react.d.ts +4 -0
  194. package/dist/types/animations/button/confetti-button/index.d.ts +3 -0
  195. package/dist/types/animations/button/confetti-button/react.d.ts +8 -0
  196. package/dist/types/animations/button/glow-cta/index.d.ts +3 -0
  197. package/dist/types/animations/button/glow-cta/react.d.ts +20 -0
  198. package/dist/types/animations/button/magnetic-hover/index.d.ts +3 -0
  199. package/dist/types/animations/button/magnetic-hover/react.d.ts +8 -0
  200. package/dist/types/animations/button/pulse/index.d.ts +3 -0
  201. package/dist/types/animations/button/pulse/react.d.ts +13 -0
  202. package/dist/types/animations/button/rainbow-button/index.d.ts +3 -0
  203. package/dist/types/animations/button/rainbow-button/react.d.ts +13 -0
  204. package/dist/types/animations/button/shimmer-border/index.d.ts +3 -0
  205. package/dist/types/animations/button/shimmer-border/react.d.ts +18 -0
  206. package/dist/types/animations/button/sketch-button/index.d.ts +3 -0
  207. package/dist/types/animations/button/sketch-button/react.d.ts +4 -0
  208. package/dist/types/animations/card/blur-rise/index.d.ts +3 -0
  209. package/dist/types/animations/card/blur-rise/react.d.ts +13 -0
  210. package/dist/types/animations/card/bounce-in-bottom/index.d.ts +3 -0
  211. package/dist/types/animations/card/bounce-in-bottom/react.d.ts +13 -0
  212. package/dist/types/animations/card/card-fan-spread/index.d.ts +3 -0
  213. package/dist/types/animations/card/card-fan-spread/react.d.ts +11 -0
  214. package/dist/types/animations/card/card-flip/index.d.ts +3 -0
  215. package/dist/types/animations/card/card-flip/react.d.ts +11 -0
  216. package/dist/types/animations/card/float-idle/index.d.ts +3 -0
  217. package/dist/types/animations/card/float-idle/react.d.ts +13 -0
  218. package/dist/types/animations/card/image-magnifier/index.d.ts +3 -0
  219. package/dist/types/animations/card/image-magnifier/react.d.ts +9 -0
  220. package/dist/types/animations/card/image-zoom-rotate/index.d.ts +3 -0
  221. package/dist/types/animations/card/image-zoom-rotate/react.d.ts +9 -0
  222. package/dist/types/animations/card/pop-in-stack/index.d.ts +3 -0
  223. package/dist/types/animations/card/pop-in-stack/react.d.ts +10 -0
  224. package/dist/types/animations/card/reveal-from-top/index.d.ts +3 -0
  225. package/dist/types/animations/card/reveal-from-top/react.d.ts +13 -0
  226. package/dist/types/animations/card/rgb-split-glitch/index.d.ts +3 -0
  227. package/dist/types/animations/card/rgb-split-glitch/react.d.ts +18 -0
  228. package/dist/types/animations/card/tilted-card/index.d.ts +3 -0
  229. package/dist/types/animations/card/tilted-card/react.d.ts +10 -0
  230. package/dist/types/animations/header/anime-splittext/index.d.ts +3 -0
  231. package/dist/types/animations/header/anime-splittext/react.d.ts +8 -0
  232. package/dist/types/animations/header/bounce-in-down/index.d.ts +3 -0
  233. package/dist/types/animations/header/bounce-in-down/react.d.ts +13 -0
  234. package/dist/types/animations/header/fly-in-chars/index.d.ts +3 -0
  235. package/dist/types/animations/header/fly-in-chars/react.d.ts +8 -0
  236. package/dist/types/animations/header/gradient-text/index.d.ts +3 -0
  237. package/dist/types/animations/header/gradient-text/react.d.ts +13 -0
  238. package/dist/types/animations/header/letter-bounce/index.d.ts +3 -0
  239. package/dist/types/animations/header/letter-bounce/react.d.ts +10 -0
  240. package/dist/types/animations/header/roll-in/index.d.ts +3 -0
  241. package/dist/types/animations/header/roll-in/react.d.ts +13 -0
  242. package/dist/types/animations/header/shimmer-text/index.d.ts +3 -0
  243. package/dist/types/animations/header/shimmer-text/react.d.ts +4 -0
  244. package/dist/types/animations/header/shuffle/index.d.ts +3 -0
  245. package/dist/types/animations/header/shuffle/react.d.ts +14 -0
  246. package/dist/types/animations/header/split-text/index.d.ts +3 -0
  247. package/dist/types/animations/header/split-text/react.d.ts +10 -0
  248. package/dist/types/animations/header/text-type/index.d.ts +3 -0
  249. package/dist/types/animations/header/text-type/react.d.ts +13 -0
  250. package/dist/types/animations/header/word-curtain-reveal/index.d.ts +3 -0
  251. package/dist/types/animations/header/word-curtain-reveal/react.d.ts +8 -0
  252. package/dist/types/react-barrel.d.ts +34 -0
  253. package/dist/types/scripts/bundle-all.d.ts +173 -0
  254. package/dist/types/scripts/check-metadata.d.ts +1 -0
  255. package/dist/types/scripts/copy-metadata.d.ts +1 -0
  256. package/dist/types/scripts/generate-animation-id-map.d.ts +1 -0
  257. package/dist/types/scripts/generate-dist-meta.d.ts +1 -0
  258. package/dist/types/scripts/generate-preview-manifest.d.ts +1 -0
  259. package/dist/types/scripts/update-metadata.d.ts +1 -0
  260. package/dist/types/shared/constants.d.ts +34 -0
  261. package/dist/types/shared/meta.d.ts +18 -0
  262. package/dist/types/shared/pointer-follow.d.ts +8 -0
  263. package/dist/types/shared/reduced-motion.d.ts +11 -0
  264. package/dist/types/shared/resolve-card-media.d.ts +1 -0
  265. package/dist/types/shared/text-split.d.ts +19 -0
  266. package/dist/types/stories/3d-flip.stories.d.ts +7 -0
  267. package/dist/types/stories/_helpers.d.ts +24 -0
  268. package/dist/types/stories/anime-splittext.stories.d.ts +8 -0
  269. package/dist/types/stories/blur-fade-in.stories.d.ts +8 -0
  270. package/dist/types/stories/blur-rise.stories.d.ts +8 -0
  271. package/dist/types/stories/blur-to-sharp-rise-header.stories.d.ts +8 -0
  272. package/dist/types/stories/border-beam.stories.d.ts +8 -0
  273. package/dist/types/stories/bounce-elastic.stories.d.ts +8 -0
  274. package/dist/types/stories/bounce-in-bottom.stories.d.ts +8 -0
  275. package/dist/types/stories/bounce-in-down.stories.d.ts +9 -0
  276. package/dist/types/stories/bubble-button.stories.d.ts +8 -0
  277. package/dist/types/stories/card-fan-spread.stories.d.ts +7 -0
  278. package/dist/types/stories/card-flip.stories.d.ts +7 -0
  279. package/dist/types/stories/confetti-button.stories.d.ts +7 -0
  280. package/dist/types/stories/float-idle.stories.d.ts +8 -0
  281. package/dist/types/stories/fly-in-chars.stories.d.ts +8 -0
  282. package/dist/types/stories/glow-cta.stories.d.ts +9 -0
  283. package/dist/types/stories/gradient-text.stories.d.ts +9 -0
  284. package/dist/types/stories/image-magnifier.stories.d.ts +10 -0
  285. package/dist/types/stories/image-zoom-rotate.stories.d.ts +7 -0
  286. package/dist/types/stories/letter-bounce.stories.d.ts +8 -0
  287. package/dist/types/stories/magic-ui-border-beam-card.stories.d.ts +8 -0
  288. package/dist/types/stories/magnetic-hover.stories.d.ts +7 -0
  289. package/dist/types/stories/pop-in-stack.stories.d.ts +7 -0
  290. package/dist/types/stories/pulse.stories.d.ts +8 -0
  291. package/dist/types/stories/rainbow-button.stories.d.ts +8 -0
  292. package/dist/types/stories/reveal-from-top.stories.d.ts +8 -0
  293. package/dist/types/stories/rgb-split-glitch.stories.d.ts +8 -0
  294. package/dist/types/stories/roll-in.stories.d.ts +9 -0
  295. package/dist/types/stories/shimmer-border.stories.d.ts +9 -0
  296. package/dist/types/stories/shimmer-text.stories.d.ts +8 -0
  297. package/dist/types/stories/shuffle.stories.d.ts +8 -0
  298. package/dist/types/stories/sketch-button.stories.d.ts +7 -0
  299. package/dist/types/stories/split-text.stories.d.ts +8 -0
  300. package/dist/types/stories/text-type.stories.d.ts +8 -0
  301. package/dist/types/stories/tilted-card.stories.d.ts +7 -0
  302. package/dist/types/stories/word-curtain-reveal.stories.d.ts +8 -0
  303. package/package.json +166 -0
  304. package/react-barrel.js +44 -0
  305. package/shared/constants.js +64 -0
  306. package/shared/meta.js +21 -0
  307. package/shared/pointer-follow.js +91 -0
  308. package/shared/reduced-motion.js +15 -0
  309. package/shared/resolve-card-media.js +41 -0
  310. package/shared/text-split.js +188 -0
package/dist/full.js ADDED
@@ -0,0 +1,3192 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
+ typeof define === 'function' && define.amd ? define(factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ReaddyAnim = factory());
5
+ })(this, (function () { 'use strict';
6
+
7
+ /**
8
+ * @readdy/anim/shared/constants.js
9
+ *
10
+ * 共享常量 —— 动效 ID 前缀、class 前缀、ID 构建器
11
+ * 解决 issues #2:动效 ID 前缀不一致
12
+ */
13
+
14
+ /** 动效 ID 前缀,统一格式 */
15
+ const ANIM_ID_PREFIX = 'readdy-anim-';
16
+
17
+ /** CSS class 前缀 */
18
+ const ANIM_CLASS_PREFIX = 'readdy-anim-';
19
+
20
+ /**
21
+ * 构建动效 CSS class
22
+ * @param {string} name - class 后缀,如 'text-type'
23
+ * @returns {string} 完整 class,如 'readdy-anim-text-type'
24
+ */
25
+ function buildAnimClass(name) {
26
+ return ANIM_CLASS_PREFIX + name
27
+ }
28
+
29
+ /**
30
+ * 构建动效相关 DOM id
31
+ * 目前与 class 前缀保持一致,便于 SVG filter / portal 节点等共享同一命名空间。
32
+ *
33
+ * @param {string} name - id 后缀,如 'bubble-goo'
34
+ * @returns {string} 完整 id,如 'readdy-anim-bubble-goo'
35
+ */
36
+ function buildAnimDomId(name) {
37
+ return ANIM_CLASS_PREFIX + name
38
+ }
39
+
40
+ /**
41
+ * 构建动效规范 ID
42
+ * 统一接受动效 slug,例如:
43
+ * - buildAnimId('letter-bounce') => 'readdy-anim-letter-bounce'
44
+ * - buildAnimId('bubble-button') => 'readdy-anim-bubble-button'
45
+ *
46
+ * @param {string} name - 动效 slug
47
+ * @returns {string} 规范 ID
48
+ */
49
+ function buildAnimId(name) {
50
+ const slug = String(name).trim();
51
+
52
+ if (!slug) {
53
+ throw new Error('buildAnimId(name) requires a non-empty animation slug')
54
+ }
55
+
56
+ if (slug.includes('/')) {
57
+ throw new Error(`buildAnimId(name) only accepts animation slugs, received path-like value: ${slug}`)
58
+ }
59
+
60
+ const normalizedSlug = slug
61
+ .replace(/[^a-zA-Z0-9]+/g, '-')
62
+ .replace(/^-+|-+$/g, '')
63
+ .toLowerCase();
64
+
65
+ if (!normalizedSlug) {
66
+ throw new Error(`buildAnimId(name) could not derive a valid animation slug from: ${slug}`)
67
+ }
68
+
69
+ return ANIM_ID_PREFIX + normalizedSlug
70
+ }
71
+
72
+ /**
73
+ * @readdy/anim/shared/text-split.js
74
+ *
75
+ * 文本拆字工具 —— 将元素内的文字拆分为带 stagger delay 的 span,
76
+ * 用于 text-split 类动效(letter-bounce、split-text、fly-in-chars 等)。
77
+ *
78
+ * init(el) 调用此工具,destroy(el) 恢复 el.dataset.originalText。
79
+ *
80
+ * 规则:
81
+ * - 只拆 textNode,保留元素节点(<em>、<strong>、<span class="icon"> 等)不动
82
+ * - 空白字符不拆,保留为原样
83
+ * - 超过 maxChars 字符时自动降级为按词拆分(splitTextIntoWords)
84
+ * - 拆字前保存原始 innerHTML 到 el.dataset.originalText(只在内部保存一次)
85
+ */
86
+
87
+
88
+ // ─────────────────────────────────────────────────────────
89
+ // 公开 API
90
+ // ─────────────────────────────────────────────────────────
91
+
92
+ /**
93
+ * 将元素内的文本拆分为逐字 span,每个 span 带有 animation-delay。
94
+ *
95
+ * @param el 目标元素
96
+ * @param options 配置项
97
+ * @param options.stagger 每个字符的延迟增量(ms),默认 60
98
+ * @param options.charClass span 的 class 名,默认 'readdy-anim-char'
99
+ * @param options.maxChars 超长文本降级阈值,默认 200
100
+ */
101
+ function splitTextIntoChars(el, options = {}) {
102
+ const {
103
+ stagger = 60,
104
+ charClass = buildAnimClass('char'),
105
+ maxChars = 200,
106
+ } = options;
107
+
108
+ // 保存原始内容,供 destroy 恢复(只在内部保存,各动效 init 不重复保存)
109
+ if (!el.dataset.originalText) {
110
+ el.dataset.originalText = el.innerHTML;
111
+ }
112
+
113
+ const textLength = el.textContent.trim().length;
114
+
115
+ // 超长文本降级为按词拆分
116
+ if (textLength > maxChars) {
117
+ splitTextIntoWords(el, { stagger: stagger * 2, wordClass: charClass });
118
+ return
119
+ }
120
+
121
+ let charIndex = 0;
122
+ walkAndSplit(el, charClass, stagger, () => charIndex++);
123
+ }
124
+
125
+ /**
126
+ * 将元素内的文本按词拆分,每个词包在一个 span 中。
127
+ *
128
+ * @param el 目标元素
129
+ * @param options 配置项
130
+ * @param options.stagger 每个词的延迟增量(ms),默认 120
131
+ * @param options.wordClass span 的 class 名,默认 'readdy-anim-word'
132
+ */
133
+ function splitTextIntoWords(el, options = {}) {
134
+ const {
135
+ stagger = 120,
136
+ wordClass = buildAnimClass('word'),
137
+ } = options;
138
+
139
+ // 保存原始内容,供 destroy 恢复
140
+ if (!el.dataset.originalText) {
141
+ el.dataset.originalText = el.innerHTML;
142
+ }
143
+
144
+ let wordIndex = 0;
145
+ walkAndSplitByWord(el, wordClass, stagger, () => wordIndex++);
146
+ }
147
+
148
+ // ─────────────────────────────────────────────────────────
149
+ // 内部实现
150
+ // ─────────────────────────────────────────────────────────
151
+
152
+ /**
153
+ * 不应该拆分的子元素标签 —— 这些标签内的文本保持原样
154
+ */
155
+ const PRESERVE_TAGS = new Set([
156
+ 'SVG', 'IMG', 'VIDEO', 'IFRAME', 'CANVAS', 'SCRIPT', 'STYLE',
157
+ ]);
158
+
159
+ /**
160
+ * 判断是否为空白字符(不拆)
161
+ */
162
+ function isWhitespace(char) {
163
+ return char === ' ' || char === '\n' || char === '\t' || char === ' '
164
+ }
165
+
166
+ /**
167
+ * 递归遍历 DOM 树,将所有 textNode 拆成逐字 span。
168
+ *
169
+ * @param node 当前遍历的节点
170
+ * @param charClass span 的 class 名
171
+ * @param stagger 每个字符的延迟增量(ms)
172
+ * @param nextIndex 返回当前字符索引的函数(每次 +1)
173
+ */
174
+ function walkAndSplit(node, charClass, stagger, nextIndex) {
175
+ // 要遍历的子节点列表(先快照,因为遍历过程中会修改 DOM)
176
+ const children = Array.from(node.childNodes);
177
+
178
+ for (const child of children) {
179
+ if (child.nodeType === Node.ELEMENT_NODE) {
180
+ // 元素节点:保留标签,递归进入
181
+ if (PRESERVE_TAGS.has(child.tagName.toUpperCase())) {
182
+ continue // svg/img 等不拆
183
+ }
184
+ walkAndSplit(child, charClass, stagger, nextIndex);
185
+
186
+ } else if (child.nodeType === Node.TEXT_NODE) {
187
+ // 文本节点:拆字
188
+ const text = child.textContent;
189
+ if (!text) continue
190
+
191
+ const fragment = document.createDocumentFragment();
192
+
193
+ for (let i = 0; i < text.length; i++) {
194
+ const char = text[i];
195
+
196
+ if (isWhitespace(char)) {
197
+ // 空白字符保留为文本节点,不拆
198
+ fragment.appendChild(document.createTextNode(char));
199
+ } else {
200
+ // 非空白字符 → 包在 span 里
201
+ const span = document.createElement('span');
202
+ span.className = charClass;
203
+ span.style.animationDelay = `${nextIndex() * stagger}ms`;
204
+ span.textContent = char;
205
+ fragment.appendChild(span);
206
+ }
207
+ }
208
+
209
+ // 替换原始文本节点
210
+ child.parentNode.replaceChild(fragment, child);
211
+ }
212
+ }
213
+ }
214
+
215
+ /**
216
+ * 递归遍历 DOM 树,将所有 textNode 按词拆分。
217
+ *
218
+ * @param node 当前遍历的节点
219
+ * @param wordClass span 的 class 名
220
+ * @param stagger 每个词的延迟增量(ms)
221
+ * @param nextIndex 返回当前词索引的函数(每次 +1)
222
+ */
223
+ function walkAndSplitByWord(node, wordClass, stagger, nextIndex) {
224
+ const children = Array.from(node.childNodes);
225
+
226
+ for (const child of children) {
227
+ if (child.nodeType === Node.ELEMENT_NODE) {
228
+ if (PRESERVE_TAGS.has(child.tagName.toUpperCase())) {
229
+ continue
230
+ }
231
+ walkAndSplitByWord(child, wordClass, stagger, nextIndex);
232
+
233
+ } else if (child.nodeType === Node.TEXT_NODE) {
234
+ const text = child.textContent;
235
+ if (!text) continue
236
+
237
+ // 按空白分词,保留原始空白
238
+ const words = text.split(/(\s+)/);
239
+ const fragment = document.createDocumentFragment();
240
+
241
+ for (const part of words) {
242
+ if (/^\s*$/.test(part)) {
243
+ // 纯空白,保留为文本节点
244
+ fragment.appendChild(document.createTextNode(part));
245
+ } else {
246
+ // 非空白词 → 包在 span 里
247
+ const span = document.createElement('span');
248
+ span.className = wordClass;
249
+ span.style.animationDelay = `${nextIndex() * stagger}ms`;
250
+ span.textContent = part;
251
+ fragment.appendChild(span);
252
+ }
253
+ }
254
+
255
+ child.parentNode.replaceChild(fragment, child);
256
+ }
257
+ }
258
+ }
259
+
260
+ const ANIMATION_ID$x = buildAnimId('letter-bounce');
261
+
262
+ const CSS_CLASS$x = buildAnimClass('letter-bounce');
263
+ const CHAR_CLASS$6 = buildAnimClass('letter-bounce-char');
264
+
265
+ function init$x(el, options = {}) {
266
+ if (!el.classList.contains(CSS_CLASS$x)) {
267
+ el.classList.add(CSS_CLASS$x);
268
+ }
269
+
270
+ el.style.setProperty('--readdy-anim-letter-bounce-duration', `${options.duration ?? 850}ms`);
271
+ el.style.setProperty('--readdy-anim-letter-bounce-amplitude', `${options.amplitude ?? 6}px`);
272
+
273
+ splitTextIntoChars(el, {
274
+ stagger: options.stagger ?? 60,
275
+ charClass: CHAR_CLASS$6,
276
+ maxChars: options.maxChars ?? 160,
277
+ });
278
+ }
279
+
280
+ function destroy$x(el) {
281
+ el.classList.remove(CSS_CLASS$x);
282
+ el.style.removeProperty('--readdy-anim-letter-bounce-duration');
283
+ el.style.removeProperty('--readdy-anim-letter-bounce-amplitude');
284
+ if (el.dataset.originalText) {
285
+ el.innerHTML = el.dataset.originalText;
286
+ delete el.dataset.originalText;
287
+ }
288
+ }
289
+
290
+ var letterBounce = /*#__PURE__*/Object.freeze({
291
+ __proto__: null,
292
+ ANIMATION_ID: ANIMATION_ID$x,
293
+ destroy: destroy$x,
294
+ init: init$x
295
+ });
296
+
297
+ const ANIMATION_ID$w = buildAnimId('shimmer-text');
298
+
299
+ const CSS_CLASS$w = buildAnimClass('shimmer-text');
300
+
301
+ function init$w(el) {
302
+ if (!el.classList.contains(CSS_CLASS$w)) {
303
+ el.classList.add(CSS_CLASS$w);
304
+ }
305
+ }
306
+
307
+ function destroy$w(el) {
308
+ el.classList.remove(CSS_CLASS$w);
309
+ }
310
+
311
+ var shimmerText = /*#__PURE__*/Object.freeze({
312
+ __proto__: null,
313
+ ANIMATION_ID: ANIMATION_ID$w,
314
+ destroy: destroy$w,
315
+ init: init$w
316
+ });
317
+
318
+ /**
319
+ * @readdy/anim/shared/reduced-motion.js
320
+ *
321
+ * 无障碍工具 —— 检测 prefers-reduced-motion
322
+ * 所有 React 组件和 init 函数统一使用此函数
323
+ */
324
+
325
+ /**
326
+ * 检测用户是否偏好减少动画
327
+ * @returns {boolean} true 表示用户偏好减少动画
328
+ */
329
+ function prefersReducedMotion() {
330
+ return typeof window !== 'undefined' &&
331
+ window.matchMedia('(prefers-reduced-motion: reduce)').matches
332
+ }
333
+
334
+ const ANIMATION_ID$v = buildAnimId('text-type');
335
+
336
+ const CSS_CLASS$v = buildAnimClass('text-type');
337
+ const CONTENT_CLASS = buildAnimClass('text-type-content');
338
+ const CURSOR_CLASS = buildAnimClass('text-type-cursor');
339
+ const RICH_CLASS = buildAnimClass('text-type-rich');
340
+ const stateMap$9 = new WeakMap();
341
+
342
+ function parsePhrases(el, options) {
343
+ if (Array.isArray(options.texts) && options.texts.length > 0) {
344
+ return {
345
+ phrases: options.texts.map(String),
346
+ source: 'options',
347
+ }
348
+ }
349
+
350
+ const raw = el.dataset.textTypeValues?.trim();
351
+ if (raw) {
352
+ try {
353
+ const parsed = JSON.parse(raw);
354
+ if (Array.isArray(parsed) && parsed.length > 0) {
355
+ return {
356
+ phrases: parsed.map(String),
357
+ source: 'data',
358
+ }
359
+ }
360
+ } catch {}
361
+
362
+ return {
363
+ phrases: raw
364
+ .split('|')
365
+ .map((item) => item.trim())
366
+ .filter(Boolean),
367
+ source: 'data',
368
+ }
369
+ }
370
+
371
+ return {
372
+ phrases: [el.textContent ?? ''],
373
+ source: 'dom',
374
+ }
375
+ }
376
+
377
+ function clearState$1(state) {
378
+ for (const timeoutId of state.timeouts) {
379
+ window.clearTimeout(timeoutId);
380
+ }
381
+ state.timeouts.clear();
382
+ }
383
+
384
+ function schedule(state, fn, delay) {
385
+ const timeoutId = window.setTimeout(() => {
386
+ state.timeouts.delete(timeoutId);
387
+ fn();
388
+ }, delay);
389
+ state.timeouts.add(timeoutId);
390
+ return timeoutId
391
+ }
392
+
393
+ function hasRichTextStructure(el) {
394
+ return Array.from(el.childNodes).some((node) => node.nodeType === Node.ELEMENT_NODE)
395
+ }
396
+
397
+ function normalizeComparableText(text) {
398
+ return String(text).replace(/\s+/g, '')
399
+ }
400
+
401
+ function shouldUseRichMode(el, phrases) {
402
+ if (!hasRichTextStructure(el)) {
403
+ return false
404
+ }
405
+
406
+ if (phrases.length !== 1) {
407
+ return false
408
+ }
409
+
410
+ return normalizeComparableText(phrases[0]) === normalizeComparableText(el.textContent ?? '')
411
+ }
412
+
413
+ function collectRichSegments(el) {
414
+ const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
415
+ const segments = [];
416
+ let node = walker.nextNode();
417
+
418
+ while (node) {
419
+ segments.push({
420
+ node,
421
+ text: node.textContent ?? '',
422
+ });
423
+ node = walker.nextNode();
424
+ }
425
+
426
+ return segments
427
+ }
428
+
429
+ function setupRichContent(el) {
430
+ const segments = collectRichSegments(el);
431
+ const cursor = document.createElement('span');
432
+ cursor.className = CURSOR_CLASS;
433
+ cursor.setAttribute('aria-hidden', 'true');
434
+ el.appendChild(cursor);
435
+
436
+ return {
437
+ cursor,
438
+ segments,
439
+ }
440
+ }
441
+
442
+ function renderRich(state, visibleCount) {
443
+ let remaining = visibleCount;
444
+
445
+ for (const segment of state.segments) {
446
+ const nextLength = Math.max(0, Math.min(segment.text.length, remaining));
447
+ segment.node.textContent = segment.text.slice(0, nextLength);
448
+ remaining -= segment.text.length;
449
+ }
450
+ }
451
+
452
+ function render(state, text) {
453
+ if (state.mode === 'rich') {
454
+ renderRich(state, text.length);
455
+ return
456
+ }
457
+
458
+ state.content.textContent = text;
459
+ }
460
+
461
+ function typePhrase(state, phraseIndex) {
462
+ const phrase = state.phrases[phraseIndex];
463
+ const typingSpeed = state.typingSpeed;
464
+ const deletingSpeed = state.deletingSpeed;
465
+ const nextIndex = (phraseIndex + 1) % state.phrases.length;
466
+
467
+ let cursor = 0;
468
+
469
+ const typeNext = () => {
470
+ cursor += 1;
471
+ render(state, phrase.slice(0, cursor));
472
+
473
+ if (cursor < phrase.length) {
474
+ schedule(state, typeNext, typingSpeed);
475
+ return
476
+ }
477
+
478
+ if (state.phrases.length === 1) {
479
+ return
480
+ }
481
+
482
+ schedule(state, () => deletePhrase(phrase, nextIndex), state.pauseDuration);
483
+ };
484
+
485
+ const deletePhrase = (currentPhrase, targetIndex) => {
486
+ let remaining = currentPhrase.length;
487
+
488
+ const deleteNext = () => {
489
+ remaining -= 1;
490
+ render(state, currentPhrase.slice(0, remaining));
491
+
492
+ if (remaining > 0) {
493
+ schedule(state, deleteNext, deletingSpeed);
494
+ return
495
+ }
496
+
497
+ schedule(state, () => typePhrase(state, targetIndex), typingSpeed);
498
+ };
499
+
500
+ schedule(state, deleteNext, deletingSpeed);
501
+ };
502
+
503
+ schedule(state, typeNext, typingSpeed);
504
+ }
505
+
506
+ function init$v(el, options = {}) {
507
+ destroy$v(el);
508
+
509
+ if (!el.dataset.originalText) {
510
+ el.dataset.originalText = el.innerHTML;
511
+ }
512
+
513
+ const { phrases, source } = parsePhrases(el, options);
514
+ const richMode = shouldUseRichMode(el, phrases);
515
+ const finalPhrase = phrases[phrases.length - 1] ?? '';
516
+
517
+ el.classList.add(CSS_CLASS$v);
518
+ el.classList.toggle(RICH_CLASS, richMode);
519
+ el.style.setProperty('--readdy-anim-text-type-gap', options.gap ?? '0.08em');
520
+ el.style.setProperty('--readdy-anim-text-type-caret-width', options.caretWidth ?? '0.08em');
521
+ el.style.setProperty('--readdy-anim-text-type-caret-blink-duration', `${options.caretBlinkDuration ?? 900}ms`);
522
+ if (richMode) {
523
+ const richContent = setupRichContent(el);
524
+ const state = {
525
+ mode: 'rich',
526
+ ...richContent,
527
+ phrases,
528
+ typingSpeed: options.typingSpeed ?? 75,
529
+ deletingSpeed: options.deletingSpeed ?? 45,
530
+ pauseDuration: options.pauseDuration ?? 1500,
531
+ timeouts: new Set(),
532
+ };
533
+
534
+ stateMap$9.set(el, state);
535
+
536
+ if (prefersReducedMotion()) {
537
+ render(state, finalPhrase);
538
+ return
539
+ }
540
+
541
+ render(state, '');
542
+ typePhrase(state, 0);
543
+ return
544
+ }
545
+
546
+ el.innerHTML = `<span class="${CONTENT_CLASS}"></span><span class="${CURSOR_CLASS}" aria-hidden="true"></span>`;
547
+
548
+ const state = {
549
+ mode: 'plain',
550
+ content: el.querySelector(`.${CONTENT_CLASS}`),
551
+ cursor: el.querySelector(`.${CURSOR_CLASS}`),
552
+ phrases,
553
+ typingSpeed: options.typingSpeed ?? 75,
554
+ deletingSpeed: options.deletingSpeed ?? 45,
555
+ pauseDuration: options.pauseDuration ?? 1500,
556
+ timeouts: new Set(),
557
+ };
558
+
559
+ stateMap$9.set(el, state);
560
+
561
+ if (prefersReducedMotion()) {
562
+ render(state, finalPhrase);
563
+ return
564
+ }
565
+
566
+ render(state, '');
567
+ typePhrase(state, 0);
568
+ }
569
+
570
+ function destroy$v(el) {
571
+ const state = stateMap$9.get(el);
572
+ if (state) {
573
+ clearState$1(state);
574
+ stateMap$9.delete(el);
575
+ }
576
+
577
+ el.classList.remove(CSS_CLASS$v);
578
+ el.classList.remove(RICH_CLASS);
579
+ el.style.removeProperty('--readdy-anim-text-type-gap');
580
+ el.style.removeProperty('--readdy-anim-text-type-caret-width');
581
+ el.style.removeProperty('--readdy-anim-text-type-caret-blink-duration');
582
+
583
+ if (state?.mode === 'rich') {
584
+ for (const segment of state.segments) {
585
+ segment.node.textContent = segment.text;
586
+ }
587
+ state.cursor?.remove();
588
+ delete el.dataset.originalText;
589
+ return
590
+ }
591
+
592
+ if (el.dataset.originalText) {
593
+ el.innerHTML = el.dataset.originalText;
594
+ delete el.dataset.originalText;
595
+ }
596
+ }
597
+
598
+ var textType = /*#__PURE__*/Object.freeze({
599
+ __proto__: null,
600
+ ANIMATION_ID: ANIMATION_ID$v,
601
+ destroy: destroy$v,
602
+ init: init$v
603
+ });
604
+
605
+ const ANIMATION_ID$u = buildAnimId('gradient-text');
606
+
607
+ const CSS_CLASS$u = buildAnimClass('gradient-text');
608
+
609
+ function init$u(el, options = {}) {
610
+ if (!el.classList.contains(CSS_CLASS$u)) {
611
+ el.classList.add(CSS_CLASS$u);
612
+ }
613
+ }
614
+
615
+ function destroy$u(el) {
616
+ el.classList.remove(CSS_CLASS$u);
617
+ }
618
+
619
+ var gradientText = /*#__PURE__*/Object.freeze({
620
+ __proto__: null,
621
+ ANIMATION_ID: ANIMATION_ID$u,
622
+ destroy: destroy$u,
623
+ init: init$u
624
+ });
625
+
626
+ const ANIMATION_ID$t = buildAnimId('fly-in-chars');
627
+
628
+ const CSS_CLASS$t = buildAnimClass('fly-in-chars');
629
+ const CHAR_CLASS$5 = buildAnimClass('fly-in-char');
630
+
631
+ function randomBetween(min, max) {
632
+ return Math.round(min + Math.random() * (max - min))
633
+ }
634
+
635
+ function init$t(el, options = {}) {
636
+ if (el.classList.contains(CSS_CLASS$t)) {
637
+ return
638
+ }
639
+
640
+ el.classList.add(CSS_CLASS$t);
641
+
642
+ if (prefersReducedMotion()) {
643
+ return
644
+ }
645
+
646
+ splitTextIntoChars(el, {
647
+ stagger: options.stagger ?? 36,
648
+ charClass: CHAR_CLASS$5,
649
+ maxChars: options.maxChars ?? 160,
650
+ });
651
+
652
+ const chars = el.querySelectorAll(`.${CHAR_CLASS$5}`);
653
+ for (const char of chars) {
654
+ char.style.setProperty('--readdy-anim-fly-in-x', `${randomBetween(-120, 120)}px`);
655
+ char.style.setProperty('--readdy-anim-fly-in-y', `${randomBetween(-80, 80)}px`);
656
+ char.style.setProperty('--readdy-anim-fly-in-rotate', `${randomBetween(-25, 25)}deg`);
657
+ }
658
+ }
659
+
660
+ function destroy$t(el) {
661
+ el.classList.remove(CSS_CLASS$t);
662
+ if (el.dataset.originalText) {
663
+ el.innerHTML = el.dataset.originalText;
664
+ delete el.dataset.originalText;
665
+ }
666
+ }
667
+
668
+ var flyInChars = /*#__PURE__*/Object.freeze({
669
+ __proto__: null,
670
+ ANIMATION_ID: ANIMATION_ID$t,
671
+ destroy: destroy$t,
672
+ init: init$t
673
+ });
674
+
675
+ const ANIMATION_ID$s = buildAnimId('blur-rise');
676
+
677
+ const CSS_CLASS$s = buildAnimClass('blur-rise');
678
+
679
+ function init$s(el, options = {}) {
680
+ if (!el.classList.contains(CSS_CLASS$s)) {
681
+ el.classList.add(CSS_CLASS$s);
682
+ }
683
+ }
684
+
685
+ function destroy$s(el) {
686
+ el.classList.remove(CSS_CLASS$s);
687
+ }
688
+
689
+ var blurRise = /*#__PURE__*/Object.freeze({
690
+ __proto__: null,
691
+ ANIMATION_ID: ANIMATION_ID$s,
692
+ destroy: destroy$s,
693
+ init: init$s
694
+ });
695
+
696
+ const ANIMATION_ID$r = buildAnimId('split-text');
697
+
698
+ const CSS_CLASS$r = buildAnimClass('split-text');
699
+ const VISIBLE_CLASS = 'is-visible';
700
+ const CHAR_CLASS$4 = buildAnimClass('split-text-char');
701
+ const observerMap = new WeakMap();
702
+
703
+ function reveal(el) {
704
+ if (!el.classList.contains(VISIBLE_CLASS)) {
705
+ el.classList.add(VISIBLE_CLASS);
706
+ }
707
+ }
708
+
709
+ function init$r(el, options = {}) {
710
+ if (el.classList.contains(CSS_CLASS$r)) {
711
+ return
712
+ }
713
+
714
+ el.classList.add(CSS_CLASS$r);
715
+
716
+ splitTextIntoChars(el, {
717
+ stagger: options.stagger ?? 50,
718
+ charClass: CHAR_CLASS$4,
719
+ maxChars: options.maxChars ?? 180,
720
+ });
721
+
722
+ if (prefersReducedMotion()) {
723
+ reveal(el);
724
+ return
725
+ }
726
+
727
+ if (typeof IntersectionObserver === 'undefined') {
728
+ reveal(el);
729
+ return
730
+ }
731
+
732
+ const observer = new IntersectionObserver(
733
+ (entries) => {
734
+ if (entries.some((entry) => entry.isIntersecting)) {
735
+ reveal(el);
736
+ observer.disconnect();
737
+ observerMap.delete(el);
738
+ }
739
+ },
740
+ {
741
+ threshold: options.threshold ?? 0.1,
742
+ rootMargin: options.rootMargin ?? '-100px 0px',
743
+ }
744
+ );
745
+
746
+ observer.observe(el);
747
+ observerMap.set(el, observer);
748
+ }
749
+
750
+ function destroy$r(el) {
751
+ const observer = observerMap.get(el);
752
+ if (observer) {
753
+ observer.disconnect();
754
+ observerMap.delete(el);
755
+ }
756
+
757
+ el.classList.remove(CSS_CLASS$r, VISIBLE_CLASS);
758
+ if (el.dataset.originalText) {
759
+ el.innerHTML = el.dataset.originalText;
760
+ delete el.dataset.originalText;
761
+ }
762
+ }
763
+
764
+ var splitText = /*#__PURE__*/Object.freeze({
765
+ __proto__: null,
766
+ ANIMATION_ID: ANIMATION_ID$r,
767
+ destroy: destroy$r,
768
+ init: init$r
769
+ });
770
+
771
+ const ANIMATION_ID$q = buildAnimId('shuffle');
772
+
773
+ const CSS_CLASS$q = buildAnimClass('shuffle');
774
+ const CHAR_CLASS$3 = buildAnimClass('shuffle-char');
775
+ const GLYPHS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%&*+-?';
776
+ const stateMap$8 = new WeakMap();
777
+
778
+ function randomGlyph() {
779
+ return GLYPHS[Math.floor(Math.random() * GLYPHS.length)]
780
+ }
781
+
782
+ function clearState(state) {
783
+ for (const intervalId of state.intervals) {
784
+ window.clearInterval(intervalId);
785
+ }
786
+ for (const timeoutId of state.timeouts) {
787
+ window.clearTimeout(timeoutId);
788
+ }
789
+ state.intervals = [];
790
+ state.timeouts = [];
791
+ }
792
+
793
+ function runShuffle(el, options = {}) {
794
+ const state = stateMap$8.get(el);
795
+ if (!state) return
796
+
797
+ clearState(state);
798
+
799
+ const chars = [...el.querySelectorAll(`.${CHAR_CLASS$3}`)];
800
+ chars.forEach((char, index) => {
801
+ const finalChar = char.dataset.finalChar ?? char.textContent ?? '';
802
+ const startDelay = index * (options.stagger ?? 35);
803
+ const frames = options.shuffleFrames ?? 7;
804
+ const frameDelay = options.frameDelay ?? 40;
805
+
806
+ char.textContent = randomGlyph();
807
+ char.classList.remove('is-settled');
808
+
809
+ const timeoutId = window.setTimeout(() => {
810
+ let frame = 0;
811
+ const intervalId = window.setInterval(() => {
812
+ frame += 1;
813
+ char.textContent = frame >= frames ? finalChar : randomGlyph();
814
+ char.classList.toggle('is-settled', frame >= frames);
815
+
816
+ if (frame >= frames) {
817
+ window.clearInterval(intervalId);
818
+ }
819
+ }, frameDelay);
820
+
821
+ state.intervals.push(intervalId);
822
+ }, startDelay);
823
+
824
+ state.timeouts.push(timeoutId);
825
+ });
826
+ }
827
+
828
+ function init$q(el, options = {}) {
829
+ if (el.classList.contains(CSS_CLASS$q)) {
830
+ return
831
+ }
832
+
833
+ el.classList.add(CSS_CLASS$q);
834
+
835
+ el.style.setProperty('--readdy-anim-shuffle-opacity', `${options.idleOpacity ?? 0.45}`);
836
+ el.style.setProperty('--readdy-anim-shuffle-translate-y', options.idleOffset ?? '0.08em');
837
+ el.style.setProperty('--readdy-anim-shuffle-scale', `${options.idleScale ?? 0.98}`);
838
+ el.style.setProperty('--readdy-anim-shuffle-settle-duration', `${options.settleDuration ?? 180}ms`);
839
+
840
+ splitTextIntoChars(el, {
841
+ stagger: options.stagger ?? 35,
842
+ charClass: CHAR_CLASS$3,
843
+ maxChars: options.maxChars ?? 120,
844
+ });
845
+
846
+ const chars = el.querySelectorAll(`.${CHAR_CLASS$3}`);
847
+ chars.forEach((char) => {
848
+ char.dataset.finalChar = char.textContent ?? '';
849
+ });
850
+
851
+ if (prefersReducedMotion()) {
852
+ return
853
+ }
854
+
855
+ const state = {
856
+ intervals: [],
857
+ timeouts: [],
858
+ onMouseEnter: () => runShuffle(el, options),
859
+ };
860
+
861
+ stateMap$8.set(el, state);
862
+ el.addEventListener('mouseenter', state.onMouseEnter);
863
+ runShuffle(el, options);
864
+ }
865
+
866
+ function destroy$q(el) {
867
+ const state = stateMap$8.get(el);
868
+ if (state) {
869
+ clearState(state);
870
+ el.removeEventListener('mouseenter', state.onMouseEnter);
871
+ stateMap$8.delete(el);
872
+ }
873
+
874
+ el.classList.remove(CSS_CLASS$q);
875
+ el.style.removeProperty('--readdy-anim-shuffle-opacity');
876
+ el.style.removeProperty('--readdy-anim-shuffle-translate-y');
877
+ el.style.removeProperty('--readdy-anim-shuffle-scale');
878
+ el.style.removeProperty('--readdy-anim-shuffle-settle-duration');
879
+ if (el.dataset.originalText) {
880
+ el.innerHTML = el.dataset.originalText;
881
+ delete el.dataset.originalText;
882
+ }
883
+ }
884
+
885
+ var shuffle = /*#__PURE__*/Object.freeze({
886
+ __proto__: null,
887
+ ANIMATION_ID: ANIMATION_ID$q,
888
+ destroy: destroy$q,
889
+ init: init$q
890
+ });
891
+
892
+ const ANIMATION_ID$p = buildAnimId('roll-in');
893
+
894
+ const CSS_CLASS$p = buildAnimClass('roll-in');
895
+ const CHAR_CLASS$2 = buildAnimClass('roll-in-char');
896
+
897
+ function init$p(el, options = {}) {
898
+ if (el.classList.contains(CSS_CLASS$p)) {
899
+ return
900
+ }
901
+
902
+ el.classList.add(CSS_CLASS$p);
903
+
904
+ if (prefersReducedMotion()) {
905
+ return
906
+ }
907
+
908
+ splitTextIntoChars(el, {
909
+ stagger: options.stagger ?? 45,
910
+ charClass: CHAR_CLASS$2,
911
+ maxChars: options.maxChars ?? 160,
912
+ });
913
+ }
914
+
915
+ function destroy$p(el) {
916
+ el.classList.remove(CSS_CLASS$p);
917
+ if (el.dataset.originalText) {
918
+ el.innerHTML = el.dataset.originalText;
919
+ delete el.dataset.originalText;
920
+ }
921
+ }
922
+
923
+ var rollIn = /*#__PURE__*/Object.freeze({
924
+ __proto__: null,
925
+ ANIMATION_ID: ANIMATION_ID$p,
926
+ destroy: destroy$p,
927
+ init: init$p
928
+ });
929
+
930
+ const ANIMATION_ID$o = buildAnimId('anime-splittext');
931
+
932
+ const CSS_CLASS$o = buildAnimClass('anime-splittext');
933
+ const WORD_CLASS$1 = buildAnimClass('anime-word');
934
+ const WORD_INNER_CLASS = buildAnimClass('anime-word-inner');
935
+ const CHAR_CLASS$1 = buildAnimClass('anime-char');
936
+
937
+ function splitAnimatedUnits$1(text) {
938
+ if (/\s/.test(text)) {
939
+ return text.split(/(\s+)/).filter(Boolean)
940
+ }
941
+
942
+ return Array.from(text)
943
+ }
944
+
945
+ function buildWordFragment(word, wordIndex, stagger, duration) {
946
+ const outer = document.createElement('span');
947
+ outer.className = WORD_CLASS$1;
948
+ outer.style.setProperty('--readdy-anim-word-offset', wordIndex % 2 === 0 ? '110%' : '-110%');
949
+
950
+ const inner = document.createElement('span');
951
+ inner.className = WORD_INNER_CLASS;
952
+ inner.style.setProperty('--readdy-anim-word-delay', `${wordIndex * stagger}ms`);
953
+ inner.style.setProperty('--readdy-anim-word-loop-delay', `${duration + 20 + wordIndex * stagger}ms`)
954
+
955
+ ;[...word].forEach((char, charIndex) => {
956
+ const charSpan = document.createElement('span');
957
+ charSpan.className = CHAR_CLASS$1;
958
+ charSpan.textContent = char;
959
+ charSpan.style.setProperty(
960
+ '--readdy-anim-char-delay',
961
+ `${Math.round(duration * 0.6) + wordIndex * stagger + charIndex * 36}ms`
962
+ );
963
+ inner.appendChild(charSpan);
964
+ });
965
+
966
+ outer.appendChild(inner);
967
+ return outer
968
+ }
969
+
970
+ function wrapWordsInTextNode$1(textNode, getWordIndex, stagger, duration) {
971
+ const text = textNode.textContent ?? '';
972
+ if (!text.trim()) {
973
+ return
974
+ }
975
+
976
+ const parts = splitAnimatedUnits$1(text);
977
+ const fragment = document.createDocumentFragment();
978
+
979
+ for (const part of parts) {
980
+ if (!part) continue
981
+
982
+ if (/^\s+$/.test(part)) {
983
+ fragment.appendChild(document.createTextNode(part));
984
+ continue
985
+ }
986
+
987
+ fragment.appendChild(buildWordFragment(part, getWordIndex(), stagger, duration));
988
+ }
989
+
990
+ textNode.parentNode?.replaceChild(fragment, textNode);
991
+ }
992
+
993
+ function splitWords$1(el, options = {}) {
994
+ if (!el.dataset.originalText) {
995
+ el.dataset.originalText = el.innerHTML;
996
+ }
997
+
998
+ const stagger = options.stagger ?? 120;
999
+ const duration = options.duration ?? 700;
1000
+
1001
+ let wordIndex = 0;
1002
+ const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
1003
+ const textNodes = [];
1004
+ let node = walker.nextNode();
1005
+
1006
+ while (node) {
1007
+ textNodes.push(node);
1008
+ node = walker.nextNode();
1009
+ }
1010
+
1011
+ for (const textNode of textNodes) {
1012
+ wrapWordsInTextNode$1(textNode, () => wordIndex++, stagger, duration);
1013
+ }
1014
+ }
1015
+
1016
+ function init$o(el, options = {}) {
1017
+ destroy$o(el);
1018
+
1019
+ if (!el.classList.contains(CSS_CLASS$o)) {
1020
+ el.classList.add(CSS_CLASS$o);
1021
+ }
1022
+
1023
+ el.style.setProperty('--readdy-anim-anime-word-duration', `${options.duration ?? 700}ms`);
1024
+ splitWords$1(el, options);
1025
+ }
1026
+
1027
+ function destroy$o(el) {
1028
+ el.classList.remove(CSS_CLASS$o);
1029
+ el.style.removeProperty('--readdy-anim-anime-word-duration');
1030
+ if (el.dataset.originalText) {
1031
+ el.innerHTML = el.dataset.originalText;
1032
+ delete el.dataset.originalText;
1033
+ }
1034
+ }
1035
+
1036
+ var animeSplittext = /*#__PURE__*/Object.freeze({
1037
+ __proto__: null,
1038
+ ANIMATION_ID: ANIMATION_ID$o,
1039
+ destroy: destroy$o,
1040
+ init: init$o
1041
+ });
1042
+
1043
+ const ANIMATION_ID$n = buildAnimId('word-curtain-reveal');
1044
+
1045
+ const CSS_CLASS$n = buildAnimClass('word-curtain-reveal');
1046
+ const WORD_CLASS = buildAnimClass('word-curtain-word');
1047
+ const INNER_CLASS$1 = buildAnimClass('word-curtain-inner');
1048
+
1049
+ function splitAnimatedUnits(text) {
1050
+ if (/\s/.test(text)) {
1051
+ return text.split(/(\s+)/).filter(Boolean)
1052
+ }
1053
+
1054
+ return Array.from(text)
1055
+ }
1056
+
1057
+ function wrapWordsInTextNode(textNode, stagger, getWordIndex) {
1058
+ const text = textNode.textContent ?? '';
1059
+ if (!text.trim()) {
1060
+ return
1061
+ }
1062
+
1063
+ const parts = splitAnimatedUnits(text);
1064
+ const fragment = document.createDocumentFragment();
1065
+
1066
+ for (const part of parts) {
1067
+ if (!part) continue
1068
+
1069
+ if (/^\s+$/.test(part)) {
1070
+ fragment.appendChild(document.createTextNode(part));
1071
+ continue
1072
+ }
1073
+
1074
+ const outer = document.createElement('span');
1075
+ outer.className = WORD_CLASS;
1076
+
1077
+ const inner = document.createElement('span');
1078
+ inner.className = INNER_CLASS$1;
1079
+ inner.textContent = part;
1080
+ inner.style.animationDelay = `${getWordIndex() * stagger}ms`;
1081
+
1082
+ outer.appendChild(inner);
1083
+ fragment.appendChild(outer);
1084
+ }
1085
+
1086
+ textNode.parentNode?.replaceChild(fragment, textNode);
1087
+ }
1088
+
1089
+ function splitWords(el, stagger) {
1090
+ if (!el.dataset.originalText) {
1091
+ el.dataset.originalText = el.innerHTML;
1092
+ }
1093
+
1094
+ let wordIndex = 0;
1095
+ const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
1096
+ const textNodes = [];
1097
+ let node = walker.nextNode();
1098
+
1099
+ while (node) {
1100
+ textNodes.push(node);
1101
+ node = walker.nextNode();
1102
+ }
1103
+
1104
+ for (const textNode of textNodes) {
1105
+ wrapWordsInTextNode(textNode, stagger, () => wordIndex++);
1106
+ }
1107
+ }
1108
+
1109
+ function init$n(el, options = {}) {
1110
+ destroy$n(el);
1111
+
1112
+ if (!el.classList.contains(CSS_CLASS$n)) {
1113
+ el.classList.add(CSS_CLASS$n);
1114
+ }
1115
+
1116
+ el.style.setProperty(
1117
+ '--readdy-anim-word-curtain-duration',
1118
+ `${options.duration ?? 550}ms`
1119
+ );
1120
+
1121
+ if (prefersReducedMotion()) {
1122
+ return
1123
+ }
1124
+
1125
+ splitWords(el, options.stagger ?? 35);
1126
+ }
1127
+
1128
+ function destroy$n(el) {
1129
+ el.classList.remove(CSS_CLASS$n);
1130
+ el.style.removeProperty('--readdy-anim-word-curtain-duration');
1131
+ if (el.dataset.originalText) {
1132
+ el.innerHTML = el.dataset.originalText;
1133
+ delete el.dataset.originalText;
1134
+ }
1135
+ }
1136
+
1137
+ var wordCurtainReveal = /*#__PURE__*/Object.freeze({
1138
+ __proto__: null,
1139
+ ANIMATION_ID: ANIMATION_ID$n,
1140
+ destroy: destroy$n,
1141
+ init: init$n
1142
+ });
1143
+
1144
+ const ANIMATION_ID$m = buildAnimId('bounce-in-down');
1145
+
1146
+ const CSS_CLASS$m = buildAnimClass('bounce-in-down');
1147
+ const CHAR_CLASS = buildAnimClass('bounce-in-down-char');
1148
+
1149
+ function init$m(el, options = {}) {
1150
+ if (el.classList.contains(CSS_CLASS$m)) {
1151
+ return
1152
+ }
1153
+
1154
+ el.classList.add(CSS_CLASS$m);
1155
+
1156
+ if (prefersReducedMotion()) {
1157
+ return
1158
+ }
1159
+
1160
+ splitTextIntoChars(el, {
1161
+ stagger: options.stagger ?? 40,
1162
+ charClass: CHAR_CLASS,
1163
+ maxChars: options.maxChars ?? 160,
1164
+ });
1165
+ }
1166
+
1167
+ function destroy$m(el) {
1168
+ el.classList.remove(CSS_CLASS$m);
1169
+ if (el.dataset.originalText) {
1170
+ el.innerHTML = el.dataset.originalText;
1171
+ delete el.dataset.originalText;
1172
+ }
1173
+ }
1174
+
1175
+ var bounceInDown = /*#__PURE__*/Object.freeze({
1176
+ __proto__: null,
1177
+ ANIMATION_ID: ANIMATION_ID$m,
1178
+ destroy: destroy$m,
1179
+ init: init$m
1180
+ });
1181
+
1182
+ function getPointerMetrics(target, event) {
1183
+ const rect =
1184
+ target && typeof target.getBoundingClientRect === 'function'
1185
+ ? target.getBoundingClientRect()
1186
+ : target;
1187
+ const centerX = rect.left + rect.width / 2;
1188
+ const centerY = rect.top + rect.height / 2;
1189
+ const deltaX = event.clientX - centerX;
1190
+ const deltaY = event.clientY - centerY;
1191
+
1192
+ return {
1193
+ rect,
1194
+ deltaX,
1195
+ deltaY,
1196
+ relativeX: rect.width ? deltaX / rect.width : 0,
1197
+ relativeY: rect.height ? deltaY / rect.height : 0,
1198
+ }
1199
+ }
1200
+
1201
+ function attachPointerFollow(el, handlers) {
1202
+ const { onMove, onLeave, onEnter } = handlers;
1203
+ const requestFrame =
1204
+ window.requestAnimationFrame?.bind(window) ?? ((callback) => window.setTimeout(callback, 16));
1205
+ const cancelFrame =
1206
+ window.cancelAnimationFrame?.bind(window) ?? ((frameId) => window.clearTimeout(frameId));
1207
+
1208
+ let frameId = null;
1209
+ let lastEvent = null;
1210
+ let activeRect = null;
1211
+
1212
+ const context = {
1213
+ get rect() {
1214
+ return activeRect
1215
+ },
1216
+ refreshRect() {
1217
+ activeRect = el.getBoundingClientRect();
1218
+ return activeRect
1219
+ },
1220
+ getMetrics(event) {
1221
+ return getPointerMetrics(activeRect ?? context.refreshRect(), event)
1222
+ },
1223
+ };
1224
+
1225
+ const flushMove = () => {
1226
+ frameId = null;
1227
+ if (!lastEvent) {
1228
+ return
1229
+ }
1230
+ if (!activeRect) {
1231
+ context.refreshRect();
1232
+ }
1233
+ onMove(lastEvent, context);
1234
+ };
1235
+
1236
+ const handleEnter = (event) => {
1237
+ context.refreshRect();
1238
+ onEnter?.(event, context);
1239
+ };
1240
+
1241
+ const handleMove = (event) => {
1242
+ lastEvent = event;
1243
+ if (frameId !== null) {
1244
+ return
1245
+ }
1246
+ frameId = requestFrame(flushMove);
1247
+ };
1248
+
1249
+ const handleLeave = (event) => {
1250
+ if (frameId !== null) {
1251
+ cancelFrame(frameId);
1252
+ frameId = null;
1253
+ }
1254
+ lastEvent = null;
1255
+ activeRect = null;
1256
+ onLeave?.(event, context);
1257
+ };
1258
+
1259
+ el.addEventListener('pointerenter', handleEnter);
1260
+ el.addEventListener('pointermove', handleMove);
1261
+ el.addEventListener('pointerleave', handleLeave);
1262
+
1263
+ return () => {
1264
+ if (frameId !== null) {
1265
+ cancelFrame(frameId);
1266
+ frameId = null;
1267
+ }
1268
+ el.removeEventListener('pointerenter', handleEnter);
1269
+ el.removeEventListener('pointermove', handleMove);
1270
+ el.removeEventListener('pointerleave', handleLeave);
1271
+ }
1272
+ }
1273
+
1274
+ const ANIMATION_ID$l = buildAnimId('magnetic-hover');
1275
+
1276
+ const CSS_CLASS$l = buildAnimClass('magnetic-hover');
1277
+ const stateMap$7 = new WeakMap();
1278
+
1279
+ function resetTransform(el) {
1280
+ el.style.setProperty('--readdy-anim-magnetic-x', '0px');
1281
+ el.style.setProperty('--readdy-anim-magnetic-y', '0px');
1282
+ el.style.setProperty('--readdy-anim-magnetic-scale', '1');
1283
+ }
1284
+
1285
+ function init$l(el, options = {}) {
1286
+ destroy$l(el);
1287
+
1288
+ el.classList.add(CSS_CLASS$l);
1289
+ resetTransform(el);
1290
+
1291
+ if (prefersReducedMotion()) {
1292
+ return
1293
+ }
1294
+
1295
+ const padding = options.padding ?? 150;
1296
+ const strength = options.strength ?? 3;
1297
+
1298
+ const onMove = (event, context) => {
1299
+ const { rect, deltaX, deltaY } = getPointerMetrics(context.rect, event);
1300
+
1301
+ if (Math.abs(deltaX) > rect.width / 2 + padding || Math.abs(deltaY) > rect.height / 2 + padding) {
1302
+ return
1303
+ }
1304
+
1305
+ el.style.setProperty('--readdy-anim-magnetic-x', `${deltaX / strength}px`);
1306
+ el.style.setProperty('--readdy-anim-magnetic-y', `${deltaY / strength}px`);
1307
+ el.style.setProperty('--readdy-anim-magnetic-scale', '1.05');
1308
+ };
1309
+
1310
+ const onLeave = () => {
1311
+ resetTransform(el);
1312
+ };
1313
+
1314
+ const cleanup = attachPointerFollow(el, { onMove, onLeave });
1315
+ stateMap$7.set(el, { cleanup });
1316
+ }
1317
+
1318
+ function destroy$l(el) {
1319
+ const state = stateMap$7.get(el);
1320
+ if (state) {
1321
+ state.cleanup();
1322
+ stateMap$7.delete(el);
1323
+ }
1324
+
1325
+ el.classList.remove(CSS_CLASS$l);
1326
+ el.style.removeProperty('--readdy-anim-magnetic-x');
1327
+ el.style.removeProperty('--readdy-anim-magnetic-y');
1328
+ el.style.removeProperty('--readdy-anim-magnetic-scale');
1329
+ }
1330
+
1331
+ var magneticHover = /*#__PURE__*/Object.freeze({
1332
+ __proto__: null,
1333
+ ANIMATION_ID: ANIMATION_ID$l,
1334
+ destroy: destroy$l,
1335
+ init: init$l
1336
+ });
1337
+
1338
+ const ANIMATION_ID$k = buildAnimId('border-beam');
1339
+
1340
+ const CSS_CLASS$k = buildAnimClass('border-beam');
1341
+ const LAYER_CLASS$1 = `${CSS_CLASS$k}__layer`;
1342
+ const BEAM_CLASS = `${CSS_CLASS$k}__beam`;
1343
+ const BEAM_WARM_CLASS = `${BEAM_CLASS}--warm`;
1344
+ const BEAM_COOL_CLASS = `${BEAM_CLASS}--cool`;
1345
+ const ANIMATION_KEY = '__readdyBorderBeamAnimation';
1346
+ const STATE_KEY = '__readdyBorderBeamState';
1347
+ const DEFAULT_SIZE = 72;
1348
+
1349
+ function ensureLayer(el) {
1350
+ const existing = Array.from(el.children).find((child) => child.classList?.contains(LAYER_CLASS$1));
1351
+ if (existing) {
1352
+ const warmBeam = existing.querySelector(`.${BEAM_WARM_CLASS}`);
1353
+ const coolBeam = existing.querySelector(`.${BEAM_COOL_CLASS}`);
1354
+ if (warmBeam && coolBeam) {
1355
+ return { layer: existing, beams: [warmBeam, coolBeam] }
1356
+ }
1357
+ existing.remove();
1358
+ }
1359
+
1360
+ const layer = document.createElement('span');
1361
+ layer.className = LAYER_CLASS$1;
1362
+ layer.setAttribute('aria-hidden', 'true');
1363
+
1364
+ const warmBeam = document.createElement('span');
1365
+ warmBeam.className = `${BEAM_CLASS} ${BEAM_WARM_CLASS}`;
1366
+ layer.appendChild(warmBeam);
1367
+
1368
+ const coolBeam = document.createElement('span');
1369
+ coolBeam.className = `${BEAM_CLASS} ${BEAM_COOL_CLASS}`;
1370
+ layer.appendChild(coolBeam);
1371
+
1372
+ el.appendChild(layer);
1373
+
1374
+ return { layer, beams: [warmBeam, coolBeam] }
1375
+ }
1376
+
1377
+ function cancelAnimation(el) {
1378
+ el[ANIMATION_KEY]?.cancel?.();
1379
+ delete el[ANIMATION_KEY];
1380
+ }
1381
+
1382
+ function getBeamSize(el, options) {
1383
+ if (typeof options.size === 'number') {
1384
+ return options.size
1385
+ }
1386
+
1387
+ const { width, height } = el.getBoundingClientRect();
1388
+ return Math.max(DEFAULT_SIZE, Math.min(Math.round((width + height) * 0.22), 160))
1389
+ }
1390
+
1391
+ function syncLayer(el) {
1392
+ const state = el[STATE_KEY];
1393
+ if (!state) return
1394
+
1395
+ const { beams, options } = state;
1396
+ const radius = getComputedStyle(el).borderRadius || '0px';
1397
+ const size = getBeamSize(el, options);
1398
+
1399
+ el.style.setProperty('--readdy-anim-border-beam-radius', radius);
1400
+ el.style.setProperty('--readdy-anim-border-beam-duration', `${options.duration ?? 3000}ms`);
1401
+ el.style.setProperty('--readdy-anim-border-beam-width', `${options.borderWidth ?? 1.35}px`);
1402
+ el.style.setProperty('--readdy-anim-border-beam-glow-opacity', `${options.glowOpacity ?? 0.28}`);
1403
+ el.style.setProperty('--readdy-anim-border-beam-size', `${size}px`);
1404
+
1405
+ beams.forEach((beam, index) => {
1406
+ beam.style.width = `${size}px`;
1407
+ beam.style.offsetPath = `rect(0 auto auto 0 round ${radius})`;
1408
+ if (index === 0) {
1409
+ beam.style.setProperty('--readdy-anim-border-beam-color-from', options.colorFrom ?? '#ff6b6b');
1410
+ beam.style.setProperty('--readdy-anim-border-beam-color-to', options.colorTo ?? '#ffb86b');
1411
+ } else {
1412
+ beam.style.setProperty('--readdy-anim-border-beam-color-from', options.secondaryColorFrom ?? '#5ea0ff');
1413
+ beam.style.setProperty('--readdy-anim-border-beam-color-to', options.secondaryColorTo ?? '#9ec5ff');
1414
+ }
1415
+ });
1416
+ }
1417
+
1418
+ function runAnimation(el) {
1419
+ const state = el[STATE_KEY];
1420
+ if (!state) return
1421
+
1422
+ const { beams, options } = state;
1423
+ const initialOffset = options.initialOffset ?? 0;
1424
+ const duration = options.duration ?? 3000;
1425
+ const delay = options.delay ?? 0;
1426
+ const reverse = options.reverse ?? false;
1427
+
1428
+ cancelAnimation(el);
1429
+ const animations = beams
1430
+ .map((beam, index) => {
1431
+ if (typeof beam.animate !== 'function') return null
1432
+
1433
+ const beamOffset = initialOffset + index * 50;
1434
+ const from = reverse ? `${100 - beamOffset}%` : `${beamOffset}%`;
1435
+ const to = reverse ? `${-beamOffset}%` : `${100 + beamOffset}%`;
1436
+ beam.style.offsetDistance = from;
1437
+
1438
+ return beam.animate(
1439
+ [
1440
+ { offsetDistance: from },
1441
+ { offsetDistance: to },
1442
+ ],
1443
+ {
1444
+ duration,
1445
+ delay: -delay,
1446
+ easing: 'linear',
1447
+ iterations: Infinity,
1448
+ fill: 'both',
1449
+ }
1450
+ )
1451
+ })
1452
+ .filter(Boolean);
1453
+
1454
+ if (animations.length > 0) {
1455
+ el[ANIMATION_KEY] = {
1456
+ cancel() {
1457
+ animations.forEach((animation) => animation.cancel());
1458
+ },
1459
+ };
1460
+ }
1461
+ }
1462
+
1463
+ function init$k(el, options = {}) {
1464
+ if (!el.classList.contains(CSS_CLASS$k)) {
1465
+ el.classList.add(CSS_CLASS$k);
1466
+ }
1467
+
1468
+ const { layer, beams } = ensureLayer(el);
1469
+ const state = el[STATE_KEY] ?? { layer, beams, options };
1470
+
1471
+ state.layer = layer;
1472
+ state.beams = beams;
1473
+ state.options = options;
1474
+
1475
+ if (!state.resizeObserver && typeof ResizeObserver !== 'undefined') {
1476
+ state.resizeObserver = new ResizeObserver(() => {
1477
+ syncLayer(el);
1478
+ });
1479
+ state.resizeObserver.observe(el);
1480
+ }
1481
+
1482
+ el[STATE_KEY] = state;
1483
+ syncLayer(el);
1484
+ runAnimation(el);
1485
+ }
1486
+
1487
+ function destroy$k(el) {
1488
+ cancelAnimation(el);
1489
+
1490
+ const state = el[STATE_KEY];
1491
+ state?.resizeObserver?.disconnect();
1492
+ state?.layer?.remove();
1493
+ delete el[STATE_KEY];
1494
+
1495
+ el.classList.remove(CSS_CLASS$k);
1496
+ el.style.removeProperty('--readdy-anim-border-beam-radius');
1497
+ el.style.removeProperty('--readdy-anim-border-beam-duration');
1498
+ el.style.removeProperty('--readdy-anim-border-beam-width');
1499
+ el.style.removeProperty('--readdy-anim-border-beam-glow-opacity');
1500
+ el.style.removeProperty('--readdy-anim-border-beam-size');
1501
+ }
1502
+
1503
+ var borderBeam = /*#__PURE__*/Object.freeze({
1504
+ __proto__: null,
1505
+ ANIMATION_ID: ANIMATION_ID$k,
1506
+ destroy: destroy$k,
1507
+ init: init$k
1508
+ });
1509
+
1510
+ const ANIMATION_ID$j = buildAnimId('shimmer-border');
1511
+
1512
+ const CSS_CLASS$j = buildAnimClass('shimmer-border');
1513
+
1514
+ function init$j(el, options = {}) {
1515
+ if (!el.classList.contains(CSS_CLASS$j)) {
1516
+ el.classList.add(CSS_CLASS$j);
1517
+ }
1518
+
1519
+ el.style.setProperty('--readdy-anim-shimmer-border-duration', `${options.duration ?? 800}ms`);
1520
+ el.style.setProperty('--readdy-anim-shimmer-border-width', `${options.borderWidth ?? 1.5}px`);
1521
+ el.style.setProperty('--readdy-anim-shimmer-border-opacity', `${options.opacity ?? 0.88}`);
1522
+ }
1523
+
1524
+ function destroy$j(el) {
1525
+ el.classList.remove(CSS_CLASS$j);
1526
+ el.style.removeProperty('--readdy-anim-shimmer-border-duration');
1527
+ el.style.removeProperty('--readdy-anim-shimmer-border-width');
1528
+ el.style.removeProperty('--readdy-anim-shimmer-border-opacity');
1529
+ }
1530
+
1531
+ var shimmerBorder = /*#__PURE__*/Object.freeze({
1532
+ __proto__: null,
1533
+ ANIMATION_ID: ANIMATION_ID$j,
1534
+ destroy: destroy$j,
1535
+ init: init$j
1536
+ });
1537
+
1538
+ const ANIMATION_ID$i = buildAnimId('rainbow-button');
1539
+
1540
+ const CSS_CLASS$i = buildAnimClass('rainbow-button');
1541
+
1542
+ function init$i(el, options = {}) {
1543
+ if (!el.classList.contains(CSS_CLASS$i)) {
1544
+ el.classList.add(CSS_CLASS$i);
1545
+ }
1546
+ }
1547
+
1548
+ function destroy$i(el) {
1549
+ el.classList.remove(CSS_CLASS$i);
1550
+ }
1551
+
1552
+ var rainbowButton = /*#__PURE__*/Object.freeze({
1553
+ __proto__: null,
1554
+ ANIMATION_ID: ANIMATION_ID$i,
1555
+ destroy: destroy$i,
1556
+ init: init$i
1557
+ });
1558
+
1559
+ const ANIMATION_ID$h = buildAnimId('sketch-button');
1560
+
1561
+ const CSS_CLASS$h = buildAnimClass('sketch-button');
1562
+
1563
+ function init$h(el) {
1564
+ if (!el.classList.contains(CSS_CLASS$h)) {
1565
+ el.classList.add(CSS_CLASS$h);
1566
+ }
1567
+ }
1568
+
1569
+ function destroy$h(el) {
1570
+ el.classList.remove(CSS_CLASS$h);
1571
+ }
1572
+
1573
+ var sketchButton = /*#__PURE__*/Object.freeze({
1574
+ __proto__: null,
1575
+ ANIMATION_ID: ANIMATION_ID$h,
1576
+ destroy: destroy$h,
1577
+ init: init$h
1578
+ });
1579
+
1580
+ const ANIMATION_ID$g = buildAnimId('confetti-button');
1581
+
1582
+ const CSS_CLASS$g = buildAnimClass('confetti-button');
1583
+ const LAYER_CLASS = buildAnimClass('confetti-layer');
1584
+ const PIECE_CLASS = buildAnimClass('confetti-piece');
1585
+ const stateMap$6 = new WeakMap();
1586
+
1587
+ function createBurst(el, options) {
1588
+ const layer = document.createElement('span');
1589
+ layer.className = LAYER_CLASS;
1590
+ el.appendChild(layer);
1591
+
1592
+ const colors = options.colors ?? ['#22d3ee', '#a78bfa', '#f472b6', '#facc15', '#34d399'];
1593
+ const pieces = options.pieces ?? 18;
1594
+
1595
+ for (let index = 0; index < pieces; index += 1) {
1596
+ const piece = document.createElement('span');
1597
+ piece.className = PIECE_CLASS;
1598
+ piece.style.setProperty('--readdy-anim-confetti-x', `${(Math.random() - 0.5) * 180}px`);
1599
+ piece.style.setProperty('--readdy-anim-confetti-y', `${ -40 - Math.random() * 90}px`);
1600
+ piece.style.setProperty('--readdy-anim-confetti-rotate', `${Math.random() * 360}deg`);
1601
+ piece.style.setProperty('--readdy-anim-confetti-delay', `${index * 14}ms`);
1602
+ piece.style.background = colors[index % colors.length];
1603
+ layer.appendChild(piece);
1604
+ }
1605
+
1606
+ return window.setTimeout(() => {
1607
+ layer.remove();
1608
+ }, 1100)
1609
+ }
1610
+
1611
+ function init$g(el, options = {}) {
1612
+ destroy$g(el);
1613
+
1614
+ el.classList.add(CSS_CLASS$g);
1615
+
1616
+ const onClick = () => {
1617
+ if (prefersReducedMotion()) {
1618
+ return
1619
+ }
1620
+ const timeoutId = createBurst(el, options);
1621
+ const state = stateMap$6.get(el);
1622
+ if (state) {
1623
+ state.timeoutIds.push(timeoutId);
1624
+ }
1625
+ };
1626
+
1627
+ el.addEventListener('click', onClick);
1628
+ stateMap$6.set(el, { onClick, timeoutIds: [] });
1629
+ }
1630
+
1631
+ function destroy$g(el) {
1632
+ const state = stateMap$6.get(el);
1633
+ if (state) {
1634
+ el.removeEventListener('click', state.onClick);
1635
+ state.timeoutIds.forEach((timeoutId) => window.clearTimeout(timeoutId));
1636
+ stateMap$6.delete(el);
1637
+ }
1638
+
1639
+ el.classList.remove(CSS_CLASS$g);
1640
+ el.querySelectorAll(`.${LAYER_CLASS}`).forEach((node) => node.remove());
1641
+ }
1642
+
1643
+ var confettiButton = /*#__PURE__*/Object.freeze({
1644
+ __proto__: null,
1645
+ ANIMATION_ID: ANIMATION_ID$g,
1646
+ destroy: destroy$g,
1647
+ init: init$g
1648
+ });
1649
+
1650
+ const ANIMATION_ID$f = buildAnimId('glow-cta');
1651
+
1652
+ const CSS_CLASS$f = buildAnimClass('glow-cta');
1653
+ const ACTIVE_CLASS$1 = buildAnimClass('glow-cta-active');
1654
+ const cleanups = new WeakMap();
1655
+ const GLOW_X_VAR = '--readdy-anim-glow-cta-x';
1656
+ const GLOW_Y_VAR = '--readdy-anim-glow-cta-y';
1657
+
1658
+ function init$f(el, options = {}) {
1659
+ if (cleanups.has(el)) return
1660
+
1661
+ el.classList.add(CSS_CLASS$f);
1662
+ el.style.setProperty(GLOW_X_VAR, '50%');
1663
+ el.style.setProperty(GLOW_Y_VAR, '50%');
1664
+ el.style.setProperty('--readdy-anim-glow-cta-scale', `${options.scale ?? 1.05}`);
1665
+ el.style.setProperty('--readdy-anim-glow-cta-padding', options.arrowPadding ?? 'calc(2rem + 1.2em)');
1666
+ el.style.setProperty('--readdy-anim-glow-cta-idle-opacity', `${options.idleOpacity ?? 0.2}`);
1667
+ el.style.setProperty('--readdy-anim-glow-cta-active-opacity', `${options.activeOpacity ?? 0.6}`);
1668
+ el.style.setProperty('--readdy-anim-glow-cta-inset', `${options.inset ?? -8}px`);
1669
+
1670
+ if (prefersReducedMotion()) {
1671
+ cleanups.set(el, () => {});
1672
+ return
1673
+ }
1674
+
1675
+ const cleanup = attachPointerFollow(el, {
1676
+ onMove(event, context) {
1677
+ const { rect } = context.getMetrics(event);
1678
+ const x = rect.width ? ((event.clientX - rect.left) / rect.width) * 100 : 50;
1679
+ const y = rect.height ? ((event.clientY - rect.top) / rect.height) * 100 : 50;
1680
+
1681
+ el.style.setProperty(GLOW_X_VAR, `${Math.max(0, Math.min(100, x))}%`);
1682
+ el.style.setProperty(GLOW_Y_VAR, `${Math.max(0, Math.min(100, y))}%`);
1683
+ el.classList.add(ACTIVE_CLASS$1);
1684
+ },
1685
+ onLeave() {
1686
+ el.classList.remove(ACTIVE_CLASS$1);
1687
+ el.style.setProperty(GLOW_X_VAR, '50%');
1688
+ el.style.setProperty(GLOW_Y_VAR, '50%');
1689
+ },
1690
+ });
1691
+
1692
+ cleanups.set(el, cleanup);
1693
+ }
1694
+
1695
+ function destroy$f(el) {
1696
+ cleanups.get(el)?.();
1697
+ cleanups.delete(el);
1698
+
1699
+ el.classList.remove(CSS_CLASS$f);
1700
+ el.classList.remove(ACTIVE_CLASS$1);
1701
+ el.style.removeProperty(GLOW_X_VAR);
1702
+ el.style.removeProperty(GLOW_Y_VAR);
1703
+ el.style.removeProperty('--readdy-anim-glow-cta-scale');
1704
+ el.style.removeProperty('--readdy-anim-glow-cta-padding');
1705
+ el.style.removeProperty('--readdy-anim-glow-cta-idle-opacity');
1706
+ el.style.removeProperty('--readdy-anim-glow-cta-active-opacity');
1707
+ el.style.removeProperty('--readdy-anim-glow-cta-inset');
1708
+ }
1709
+
1710
+ var glowCta = /*#__PURE__*/Object.freeze({
1711
+ __proto__: null,
1712
+ ANIMATION_ID: ANIMATION_ID$f,
1713
+ destroy: destroy$f,
1714
+ init: init$f
1715
+ });
1716
+
1717
+ const ANIMATION_ID$e = buildAnimId('bubble-button');
1718
+
1719
+ const CSS_CLASS$e = buildAnimClass('bubble-button');
1720
+ const ACTIVE_CLASS = buildAnimClass('bubble-button-active');
1721
+ const HOVER_CLASS = buildAnimClass('bubble-button-hover');
1722
+ const FALLBACK_CLASS = buildAnimClass('bubble-button-fallback');
1723
+ const CONTAINER_CLASS = buildAnimClass('bubble-button-container');
1724
+ const EFFECT_CONTAINER_CLASS = buildAnimClass('bubble-button-effect-container');
1725
+ const EFFECT_BUTTON_CLASS = buildAnimClass('bubble-button-effect-button');
1726
+ const CIRCLE_CLASS = buildAnimClass('bubble-button-circle');
1727
+ const FILTER_ID = buildAnimDomId('bubble-goo');
1728
+ const FILTER_ROOT_ID = buildAnimDomId('bubble-goo-root');
1729
+
1730
+ const stateMap$5 = new WeakMap();
1731
+ let gooFilterRefCount = 0;
1732
+
1733
+ function ensureGooFilter() {
1734
+ gooFilterRefCount += 1;
1735
+ if (document.getElementById(FILTER_ID)) {
1736
+ return
1737
+ }
1738
+
1739
+ const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
1740
+ svg.id = FILTER_ROOT_ID;
1741
+ svg.setAttribute('aria-hidden', 'true');
1742
+ svg.style.position = 'absolute';
1743
+ svg.style.width = '0';
1744
+ svg.style.height = '0';
1745
+ svg.style.pointerEvents = 'none';
1746
+
1747
+ svg.innerHTML = `
1748
+ <defs>
1749
+ <filter id="${FILTER_ID}">
1750
+ <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
1751
+ <feColorMatrix
1752
+ in="blur"
1753
+ mode="matrix"
1754
+ values="
1755
+ 1 0 0 0 0
1756
+ 0 1 0 0 0
1757
+ 0 0 1 0 0
1758
+ 0 0 0 19 -9
1759
+ "
1760
+ result="goo"
1761
+ />
1762
+ <feComposite in="SourceGraphic" in2="goo" />
1763
+ </filter>
1764
+ </defs>
1765
+ `;
1766
+
1767
+ document.body.appendChild(svg);
1768
+ }
1769
+
1770
+ function releaseGooFilter() {
1771
+ gooFilterRefCount = Math.max(gooFilterRefCount - 1, 0);
1772
+ if (gooFilterRefCount === 0) {
1773
+ document.getElementById(FILTER_ROOT_ID)?.remove();
1774
+ }
1775
+ }
1776
+
1777
+ function createCircle(position, slot) {
1778
+ const circle = document.createElement('span');
1779
+ circle.className = `${CIRCLE_CLASS} ${CIRCLE_CLASS}-${position} ${CIRCLE_CLASS}-${position}-${slot}`;
1780
+ return circle
1781
+ }
1782
+
1783
+ function ensureStructure(el) {
1784
+ let container = el.parentElement;
1785
+
1786
+ if (!container?.classList.contains(CONTAINER_CLASS)) {
1787
+ container = document.createElement('span');
1788
+ container.className = CONTAINER_CLASS;
1789
+ el.parentNode?.insertBefore(container, el);
1790
+ container.appendChild(el);
1791
+ }
1792
+
1793
+ let effectContainer = container.querySelector(`.${EFFECT_CONTAINER_CLASS}`);
1794
+ if (!effectContainer) {
1795
+ effectContainer = document.createElement('span');
1796
+ effectContainer.className = EFFECT_CONTAINER_CLASS;
1797
+ effectContainer.style.filter = `url(#${FILTER_ID})`;
1798
+ effectContainer.style.webkitFilter = `url(#${FILTER_ID})`;
1799
+
1800
+ effectContainer.appendChild(createCircle('top-left', 1));
1801
+ effectContainer.appendChild(createCircle('top-left', 2));
1802
+ effectContainer.appendChild(createCircle('top-left', 3));
1803
+
1804
+ const effectButton = document.createElement('span');
1805
+ effectButton.className = EFFECT_BUTTON_CLASS;
1806
+ effectContainer.appendChild(effectButton);
1807
+
1808
+ effectContainer.appendChild(createCircle('bottom-right', 1));
1809
+ effectContainer.appendChild(createCircle('bottom-right', 2));
1810
+ effectContainer.appendChild(createCircle('bottom-right', 3));
1811
+
1812
+ container.appendChild(effectContainer);
1813
+ }
1814
+
1815
+ return {
1816
+ container,
1817
+ effectContainer,
1818
+ effectButton: effectContainer.querySelector(`.${EFFECT_BUTTON_CLASS}`),
1819
+ circlesTopLeft: Array.from(effectContainer.querySelectorAll(`.${CIRCLE_CLASS}-top-left`)),
1820
+ circlesBottomRight: Array.from(effectContainer.querySelectorAll(`.${CIRCLE_CLASS}-bottom-right`)),
1821
+ }
1822
+ }
1823
+
1824
+ function setAccent(container, el) {
1825
+ const computed = window.getComputedStyle(el);
1826
+ const backgroundColor = computed.backgroundColor;
1827
+ const accent = backgroundColor && backgroundColor !== 'rgba(0, 0, 0, 0)' ? backgroundColor : '#4f6bff';
1828
+ container.style.setProperty('--readdy-anim-bubble-accent', accent);
1829
+ }
1830
+
1831
+ function clearAnimations(state) {
1832
+ state.animations.forEach((animation) => {
1833
+ animation.cancel();
1834
+ });
1835
+ state.animations = [];
1836
+ }
1837
+
1838
+ function trackAnimation(state, animation) {
1839
+ if (!animation) {
1840
+ return
1841
+ }
1842
+
1843
+ state.animations.push(animation);
1844
+ const forget = () => {
1845
+ state.animations = state.animations.filter((item) => item !== animation);
1846
+ };
1847
+ animation.addEventListener('finish', forget, { once: true });
1848
+ animation.addEventListener('cancel', forget, { once: true });
1849
+ }
1850
+
1851
+ function clearInlineState(state) {
1852
+ const nodes = [
1853
+ state.effectButton,
1854
+ ...state.circlesTopLeft,
1855
+ ...state.circlesBottomRight,
1856
+ ].filter(Boolean);
1857
+
1858
+ nodes.forEach((node) => {
1859
+ node.style.opacity = '';
1860
+ node.style.transform = '';
1861
+ });
1862
+ }
1863
+
1864
+ function resetState(state) {
1865
+ clearAnimations(state);
1866
+ state.container.classList.remove(ACTIVE_CLASS);
1867
+ state.container.classList.remove(HOVER_CLASS);
1868
+ clearInlineState(state);
1869
+ }
1870
+
1871
+ function hasWAAPI() {
1872
+ return typeof Element.prototype.animate === 'function'
1873
+ }
1874
+
1875
+ function playBurst(state) {
1876
+ const { container, effectButton, circlesTopLeft, circlesBottomRight } = state;
1877
+
1878
+ container.classList.remove(ACTIVE_CLASS);
1879
+ void container.offsetWidth;
1880
+ container.classList.add(HOVER_CLASS);
1881
+ container.classList.add(ACTIVE_CLASS);
1882
+
1883
+ if (!state.supportsWAAPI) {
1884
+ return
1885
+ }
1886
+
1887
+ clearAnimations(state);
1888
+
1889
+ trackAnimation(
1890
+ state,
1891
+ effectButton?.animate(
1892
+ [
1893
+ { transform: 'translateY(-50%) scaleY(1)', opacity: 1 },
1894
+ { transform: 'translateY(-50%) scaleY(1.1)', opacity: 1, offset: 0.34 },
1895
+ { transform: 'translateY(-50%) scale(1)', opacity: 1 },
1896
+ ],
1897
+ {
1898
+ duration: 1000,
1899
+ easing: 'cubic-bezier(0.22, 1, 0.36, 1)',
1900
+ fill: 'forwards',
1901
+ }
1902
+ )
1903
+ );
1904
+
1905
+ const topFrames = [
1906
+ [
1907
+ { transform: 'translate(0, 0) rotate(-45deg) scale(1)', opacity: 1 },
1908
+ { transform: 'translate(-25px, -25px) rotate(-45deg) scale(1, 2)', opacity: 1, offset: 0.5 },
1909
+ { transform: 'translate(-19px, -27px) rotate(-45deg) scale(0.2)', opacity: 0.95, offset: 0.58 },
1910
+ { transform: 'translate(-24px, -42px) rotate(-45deg) scale(0)', opacity: 0 },
1911
+ ],
1912
+ [
1913
+ { transform: 'translate(0, 0) rotate(-45deg) scale(1)', opacity: 1 },
1914
+ { transform: 'translate(-25px, -25px) rotate(-45deg) scale(1, 2)', opacity: 1, offset: 0.5 },
1915
+ { transform: 'translate(-35px, -32px) rotate(-45deg) scale(1, 0.8)', opacity: 0.95, offset: 0.58 },
1916
+ { transform: 'translate(-45px, -42px) rotate(-45deg) scale(0.4)', opacity: 0 },
1917
+ ],
1918
+ [
1919
+ { transform: 'translate(0, 0) rotate(-45deg) scale(1)', opacity: 1 },
1920
+ { transform: 'translate(-25px, -25px) rotate(-45deg) scale(1, 2)', opacity: 1, offset: 0.5 },
1921
+ { transform: 'translate(-40px, -19px) rotate(-45deg) scale(0.2)', opacity: 0.95, offset: 0.58 },
1922
+ { transform: 'translate(-55px, -14px) rotate(-45deg) scale(0)', opacity: 0 },
1923
+ ],
1924
+ ];
1925
+
1926
+ const bottomFrames = [
1927
+ [
1928
+ { transform: 'translate(0, 0) rotate(45deg) scale(1)', opacity: 1 },
1929
+ { transform: 'translate(30px, 30px) rotate(45deg) scale(1)', opacity: 1, offset: 0.48 },
1930
+ { transform: 'translate(24px, 33px) rotate(45deg) scale(0.2)', opacity: 0.95, offset: 0.56 },
1931
+ { transform: 'translate(29px, 48px) rotate(45deg) scale(0)', opacity: 0 },
1932
+ ],
1933
+ [
1934
+ { transform: 'translate(0, 0) rotate(45deg) scale(1)', opacity: 1 },
1935
+ { transform: 'translate(30px, 30px) rotate(45deg) scale(1)', opacity: 1, offset: 0.48 },
1936
+ { transform: 'translate(37px, 33px) rotate(45deg) scale(0.8)', opacity: 0.95, offset: 0.56 },
1937
+ { transform: 'translate(44px, 40px) rotate(45deg) scale(0.4)', opacity: 0 },
1938
+ ],
1939
+ [
1940
+ { transform: 'translate(0, 0) rotate(45deg) scale(1)', opacity: 1 },
1941
+ { transform: 'translate(30px, 30px) rotate(45deg) scale(1)', opacity: 1, offset: 0.48 },
1942
+ { transform: 'translate(45px, 24px) rotate(45deg) scale(0.2)', opacity: 0.95, offset: 0.56 },
1943
+ { transform: 'translate(60px, 19px) rotate(45deg) scale(0)', opacity: 0 },
1944
+ ],
1945
+ ];
1946
+
1947
+ circlesTopLeft.forEach((circle, index) => {
1948
+ trackAnimation(
1949
+ state,
1950
+ circle.animate(topFrames[index], {
1951
+ duration: 1200,
1952
+ easing: 'cubic-bezier(0.22, 1, 0.36, 1)',
1953
+ fill: 'forwards',
1954
+ })
1955
+ );
1956
+ });
1957
+
1958
+ circlesBottomRight.forEach((circle, index) => {
1959
+ trackAnimation(
1960
+ state,
1961
+ circle.animate(bottomFrames[index], {
1962
+ duration: 1100,
1963
+ easing: 'cubic-bezier(0.22, 1, 0.36, 1)',
1964
+ fill: 'forwards',
1965
+ })
1966
+ );
1967
+ });
1968
+ }
1969
+
1970
+ function init$e(el) {
1971
+ destroy$e(el);
1972
+ el.classList.add(CSS_CLASS$e);
1973
+
1974
+ if (prefersReducedMotion()) {
1975
+ return
1976
+ }
1977
+
1978
+ ensureGooFilter();
1979
+ const structure = ensureStructure(el);
1980
+ setAccent(structure.container, el);
1981
+
1982
+ const state = {
1983
+ ...structure,
1984
+ animations: [],
1985
+ supportsWAAPI: hasWAAPI(),
1986
+ onEnter: () => {},
1987
+ onLeave: () => {},
1988
+ };
1989
+
1990
+ state.onEnter = () => {
1991
+ playBurst(state);
1992
+ };
1993
+
1994
+ state.onLeave = () => {
1995
+ resetState(state);
1996
+ };
1997
+
1998
+ state.container.addEventListener('mouseenter', state.onEnter);
1999
+ state.container.addEventListener('mouseleave', state.onLeave);
2000
+ state.container.classList.toggle(FALLBACK_CLASS, !state.supportsWAAPI);
2001
+ stateMap$5.set(el, state);
2002
+ }
2003
+
2004
+ function destroy$e(el) {
2005
+ const state = stateMap$5.get(el);
2006
+ if (state) {
2007
+ state.container.removeEventListener('mouseenter', state.onEnter);
2008
+ state.container.removeEventListener('mouseleave', state.onLeave);
2009
+ resetState(state);
2010
+ releaseGooFilter();
2011
+ stateMap$5.delete(el);
2012
+ }
2013
+
2014
+ el.classList.remove(CSS_CLASS$e);
2015
+
2016
+ const container = el.parentElement?.classList.contains(CONTAINER_CLASS) ? el.parentElement : null;
2017
+ if (container) {
2018
+ container.classList.remove(ACTIVE_CLASS);
2019
+ container.classList.remove(HOVER_CLASS);
2020
+ container.classList.remove(FALLBACK_CLASS);
2021
+ container.style.removeProperty('--readdy-anim-bubble-accent');
2022
+ if (container.parentNode) {
2023
+ container.parentNode.insertBefore(el, container);
2024
+ } else {
2025
+ container.removeChild(el);
2026
+ }
2027
+ container.remove();
2028
+ }
2029
+ }
2030
+
2031
+ var bubbleButton = /*#__PURE__*/Object.freeze({
2032
+ __proto__: null,
2033
+ ANIMATION_ID: ANIMATION_ID$e,
2034
+ destroy: destroy$e,
2035
+ init: init$e
2036
+ });
2037
+
2038
+ const ANIMATION_ID$d = buildAnimId('bounce-elastic');
2039
+
2040
+ const CSS_CLASS$d = buildAnimClass('bounce-elastic');
2041
+
2042
+ function init$d(el, options = {}) {
2043
+ if (!el.classList.contains(CSS_CLASS$d)) {
2044
+ el.classList.add(CSS_CLASS$d);
2045
+ }
2046
+ }
2047
+
2048
+ function destroy$d(el) {
2049
+ el.classList.remove(CSS_CLASS$d);
2050
+ }
2051
+
2052
+ var bounceElastic = /*#__PURE__*/Object.freeze({
2053
+ __proto__: null,
2054
+ ANIMATION_ID: ANIMATION_ID$d,
2055
+ destroy: destroy$d,
2056
+ init: init$d
2057
+ });
2058
+
2059
+ const ANIMATION_ID$c = buildAnimId('pulse');
2060
+
2061
+ const CSS_CLASS$c = buildAnimClass('pulse');
2062
+
2063
+ function init$c(el, options = {}) {
2064
+ if (!el.classList.contains(CSS_CLASS$c)) {
2065
+ el.classList.add(CSS_CLASS$c);
2066
+ }
2067
+ }
2068
+
2069
+ function destroy$c(el) {
2070
+ el.classList.remove(CSS_CLASS$c);
2071
+ }
2072
+
2073
+ var pulse = /*#__PURE__*/Object.freeze({
2074
+ __proto__: null,
2075
+ ANIMATION_ID: ANIMATION_ID$c,
2076
+ destroy: destroy$c,
2077
+ init: init$c
2078
+ });
2079
+
2080
+ const ANIMATION_ID$b = buildAnimId('blur-fade-in');
2081
+
2082
+ const CSS_CLASS$b = buildAnimClass('blur-fade-in');
2083
+
2084
+ function init$b(el, options = {}) {
2085
+ if (!el.classList.contains(CSS_CLASS$b)) {
2086
+ el.classList.add(CSS_CLASS$b);
2087
+ }
2088
+ }
2089
+
2090
+ function destroy$b(el) {
2091
+ el.classList.remove(CSS_CLASS$b);
2092
+ }
2093
+
2094
+ var blurFadeIn = /*#__PURE__*/Object.freeze({
2095
+ __proto__: null,
2096
+ ANIMATION_ID: ANIMATION_ID$b,
2097
+ destroy: destroy$b,
2098
+ init: init$b
2099
+ });
2100
+
2101
+ const ANIMATION_ID$a = buildAnimId('3d-flip');
2102
+
2103
+ const CSS_CLASS$a = buildAnimClass('3d-flip');
2104
+ const stateMap$4 = new WeakMap();
2105
+
2106
+ function reset$1(el) {
2107
+ el.style.setProperty('--readdy-anim-3d-rotate-x', '0deg');
2108
+ el.style.setProperty('--readdy-anim-3d-rotate-y', '0deg');
2109
+ el.style.setProperty('--readdy-anim-3d-translate-x', '0px');
2110
+ el.style.setProperty('--readdy-anim-3d-translate-y', '0px');
2111
+ }
2112
+
2113
+ function init$a(el, options = {}) {
2114
+ destroy$a(el);
2115
+
2116
+ el.classList.add(CSS_CLASS$a);
2117
+ reset$1(el);
2118
+
2119
+ if (prefersReducedMotion()) {
2120
+ return
2121
+ }
2122
+
2123
+ const tilt = options.maxTilt ?? 12;
2124
+ const travel = options.translate ?? 8;
2125
+
2126
+ const onMove = (event, context) => {
2127
+ const { relativeX, relativeY } = getPointerMetrics(context.rect, event);
2128
+
2129
+ el.style.setProperty('--readdy-anim-3d-rotate-x', `${relativeY * -tilt * 2}deg`);
2130
+ el.style.setProperty('--readdy-anim-3d-rotate-y', `${relativeX * tilt * 2}deg`);
2131
+ el.style.setProperty('--readdy-anim-3d-translate-x', `${relativeX * travel * 2}px`);
2132
+ el.style.setProperty('--readdy-anim-3d-translate-y', `${relativeY * travel * 2}px`);
2133
+ };
2134
+
2135
+ const onLeave = () => {
2136
+ reset$1(el);
2137
+ };
2138
+
2139
+ const cleanup = attachPointerFollow(el, { onMove, onLeave });
2140
+ stateMap$4.set(el, { cleanup });
2141
+ }
2142
+
2143
+ function destroy$a(el) {
2144
+ const state = stateMap$4.get(el);
2145
+ if (state) {
2146
+ state.cleanup();
2147
+ stateMap$4.delete(el);
2148
+ }
2149
+
2150
+ el.classList.remove(CSS_CLASS$a);
2151
+ el.style.removeProperty('--readdy-anim-3d-rotate-x');
2152
+ el.style.removeProperty('--readdy-anim-3d-rotate-y');
2153
+ el.style.removeProperty('--readdy-anim-3d-translate-x');
2154
+ el.style.removeProperty('--readdy-anim-3d-translate-y');
2155
+ }
2156
+
2157
+ var flip3d = /*#__PURE__*/Object.freeze({
2158
+ __proto__: null,
2159
+ ANIMATION_ID: ANIMATION_ID$a,
2160
+ destroy: destroy$a,
2161
+ init: init$a
2162
+ });
2163
+
2164
+ const ANIMATION_ID$9 = buildAnimId('float-idle');
2165
+
2166
+ const CSS_CLASS$9 = buildAnimClass('float-idle');
2167
+
2168
+ function init$9(el, options = {}) {
2169
+ if (!el.classList.contains(CSS_CLASS$9)) {
2170
+ el.classList.add(CSS_CLASS$9);
2171
+ }
2172
+ }
2173
+
2174
+ function destroy$9(el) {
2175
+ el.classList.remove(CSS_CLASS$9);
2176
+ }
2177
+
2178
+ var floatIdle = /*#__PURE__*/Object.freeze({
2179
+ __proto__: null,
2180
+ ANIMATION_ID: ANIMATION_ID$9,
2181
+ destroy: destroy$9,
2182
+ init: init$9
2183
+ });
2184
+
2185
+ const ANIMATION_ID$8 = buildAnimId('tilted-card');
2186
+
2187
+ const CSS_CLASS$8 = buildAnimClass('tilted-card');
2188
+ const stateMap$3 = new WeakMap();
2189
+
2190
+ function reset(el) {
2191
+ el.style.setProperty('--readdy-anim-card-tilt-x', '0deg');
2192
+ el.style.setProperty('--readdy-anim-card-tilt-y', '0deg');
2193
+ el.style.setProperty('--readdy-anim-card-scale', '1');
2194
+ }
2195
+
2196
+ function init$8(el, options = {}) {
2197
+ destroy$8(el);
2198
+
2199
+ el.classList.add(CSS_CLASS$8);
2200
+ reset(el);
2201
+
2202
+ const perspective = options.perspective ?? 900;
2203
+ const duration = options.duration ?? 550;
2204
+ el.style.setProperty('--readdy-anim-card-tilt-perspective', `${perspective}px`);
2205
+ el.style.setProperty('--readdy-anim-card-tilt-duration', `${duration}ms`);
2206
+
2207
+ if (prefersReducedMotion()) {
2208
+ return
2209
+ }
2210
+
2211
+ const maxTilt = options.maxTilt ?? 10;
2212
+ const scale = options.scale ?? 1.02;
2213
+
2214
+ const onMove = (event, context) => {
2215
+ const { relativeX, relativeY } = getPointerMetrics(context.rect, event);
2216
+
2217
+ el.style.setProperty('--readdy-anim-card-tilt-x', `${relativeY * -maxTilt * 2}deg`);
2218
+ el.style.setProperty('--readdy-anim-card-tilt-y', `${relativeX * maxTilt * 2}deg`);
2219
+ el.style.setProperty('--readdy-anim-card-scale', `${scale}`);
2220
+ };
2221
+
2222
+ const onLeave = () => {
2223
+ reset(el);
2224
+ };
2225
+
2226
+ const cleanup = attachPointerFollow(el, { onMove, onLeave });
2227
+ stateMap$3.set(el, { cleanup });
2228
+ }
2229
+
2230
+ function destroy$8(el) {
2231
+ const state = stateMap$3.get(el);
2232
+ if (state) {
2233
+ state.cleanup();
2234
+ stateMap$3.delete(el);
2235
+ }
2236
+
2237
+ el.classList.remove(CSS_CLASS$8);
2238
+ el.style.removeProperty('--readdy-anim-card-tilt-x');
2239
+ el.style.removeProperty('--readdy-anim-card-tilt-y');
2240
+ el.style.removeProperty('--readdy-anim-card-scale');
2241
+ el.style.removeProperty('--readdy-anim-card-tilt-perspective');
2242
+ el.style.removeProperty('--readdy-anim-card-tilt-duration');
2243
+ }
2244
+
2245
+ var tiltedCard = /*#__PURE__*/Object.freeze({
2246
+ __proto__: null,
2247
+ ANIMATION_ID: ANIMATION_ID$8,
2248
+ destroy: destroy$8,
2249
+ init: init$8
2250
+ });
2251
+
2252
+ const ANIMATION_ID$7 = buildAnimId('card-flip');
2253
+
2254
+ const CSS_CLASS$7 = buildAnimClass('card-flip');
2255
+ const SCENE_CLASS = buildAnimClass('card-flip-scene');
2256
+ const INNER_CLASS = buildAnimClass('card-flip-inner');
2257
+ const FACE_CLASS = buildAnimClass('card-flip-face');
2258
+ const FRONT_CLASS = buildAnimClass('card-flip-front');
2259
+ const BACK_CLASS = buildAnimClass('card-flip-back');
2260
+
2261
+ const stateMap$2 = new WeakMap();
2262
+ const FACE_STYLE_PROPS = [
2263
+ 'background',
2264
+ 'backgroundColor',
2265
+ 'backgroundImage',
2266
+ 'backgroundSize',
2267
+ 'backgroundPosition',
2268
+ 'backgroundRepeat',
2269
+ 'backgroundClip',
2270
+ 'border',
2271
+ 'borderTop',
2272
+ 'borderRight',
2273
+ 'borderBottom',
2274
+ 'borderLeft',
2275
+ 'borderRadius',
2276
+ 'boxShadow',
2277
+ 'padding',
2278
+ 'paddingTop',
2279
+ 'paddingRight',
2280
+ 'paddingBottom',
2281
+ 'paddingLeft',
2282
+ 'color',
2283
+ 'backdropFilter',
2284
+ 'WebkitBackdropFilter',
2285
+ ];
2286
+
2287
+ function createEl(tag, className) {
2288
+ const el = document.createElement(tag);
2289
+ if (className) el.className = className;
2290
+ return el
2291
+ }
2292
+
2293
+ function collectRenderableNodes(el) {
2294
+ return Array.from(el.childNodes).filter((node) => {
2295
+ if (node.nodeType !== Node.TEXT_NODE) return true
2296
+ return (node.textContent ?? '').trim().length > 0
2297
+ })
2298
+ }
2299
+
2300
+ function sanitizeBackFaceClone(root) {
2301
+ if (!(root instanceof HTMLElement)) {
2302
+ return
2303
+ }
2304
+
2305
+ const nodes = [root, ...root.querySelectorAll('*')];
2306
+
2307
+ root.removeAttribute('id');
2308
+ root.removeAttribute('tabindex');
2309
+ root.removeAttribute('aria-labelledby');
2310
+ root.removeAttribute('aria-describedby');
2311
+ root.removeAttribute('aria-controls');
2312
+ root.removeAttribute('for');
2313
+
2314
+ nodes.forEach((node) => {
2315
+ if (node instanceof HTMLElement) {
2316
+ node.removeAttribute('id');
2317
+ }
2318
+ });
2319
+
2320
+ nodes.forEach((node) => {
2321
+ if (
2322
+ !(node instanceof HTMLElement) ||
2323
+ !node.matches(
2324
+ 'a, button, input, textarea, select, summary, [tabindex], [contenteditable], label[for]'
2325
+ )
2326
+ ) {
2327
+ return
2328
+ }
2329
+
2330
+ node.setAttribute('aria-hidden', 'true');
2331
+ node.setAttribute('tabindex', '-1');
2332
+ node.removeAttribute('for');
2333
+ node.style.pointerEvents = 'none';
2334
+ if (
2335
+ node instanceof HTMLInputElement ||
2336
+ node instanceof HTMLTextAreaElement ||
2337
+ node instanceof HTMLSelectElement ||
2338
+ node instanceof HTMLButtonElement
2339
+ ) {
2340
+ node.disabled = true;
2341
+ }
2342
+ });
2343
+ }
2344
+
2345
+ function buildBackFace(nodes) {
2346
+ const back = createEl('div', `${FACE_CLASS} ${BACK_CLASS}`);
2347
+ back.setAttribute('aria-hidden', 'true');
2348
+ back.append(
2349
+ ...nodes.map((node) => {
2350
+ const clone = node.cloneNode(true);
2351
+ sanitizeBackFaceClone(clone);
2352
+ return clone
2353
+ })
2354
+ );
2355
+ return back
2356
+ }
2357
+
2358
+ function applyFaceShellStyles(host, face) {
2359
+ const styles = window.getComputedStyle(host);
2360
+ FACE_STYLE_PROPS.forEach((prop) => {
2361
+ const value = styles[prop];
2362
+ if (value) {
2363
+ face.style[prop] = value;
2364
+ }
2365
+ });
2366
+ }
2367
+
2368
+ function init$7(el, options = {}) {
2369
+ destroy$7(el);
2370
+
2371
+ const originalNodes = collectRenderableNodes(el);
2372
+ const rect = el.getBoundingClientRect();
2373
+ const previousMinHeight = el.style.minHeight;
2374
+ const previousHeight = el.style.height;
2375
+ const previousTabIndex = el.getAttribute('tabindex');
2376
+ const previousInlineStyles = {
2377
+ background: el.style.background,
2378
+ backgroundColor: el.style.backgroundColor,
2379
+ backgroundImage: el.style.backgroundImage,
2380
+ border: el.style.border,
2381
+ boxShadow: el.style.boxShadow,
2382
+ padding: el.style.padding,
2383
+ overflow: el.style.overflow,
2384
+ };
2385
+
2386
+ const scene = createEl('div', SCENE_CLASS);
2387
+ const inner = createEl('div', INNER_CLASS);
2388
+ const front = createEl('div', `${FACE_CLASS} ${FRONT_CLASS}`);
2389
+ const back = buildBackFace(originalNodes);
2390
+
2391
+ applyFaceShellStyles(el, front);
2392
+ applyFaceShellStyles(el, back);
2393
+
2394
+ front.append(...originalNodes);
2395
+ inner.append(front, back);
2396
+ scene.appendChild(inner);
2397
+
2398
+ stateMap$2.set(el, {
2399
+ originalNodes,
2400
+ previousMinHeight,
2401
+ previousHeight,
2402
+ previousTabIndex,
2403
+ previousInlineStyles,
2404
+ });
2405
+
2406
+ el.classList.add(CSS_CLASS$7);
2407
+ el.style.setProperty('--readdy-anim-card-flip-duration', `${options.duration ?? 500}ms`);
2408
+ el.style.setProperty('--readdy-anim-card-flip-perspective', `${options.perspective ?? 2000}px`);
2409
+ if (rect.height > 0) {
2410
+ el.style.minHeight = `${rect.height}px`;
2411
+ }
2412
+ el.style.background = 'transparent';
2413
+ el.style.backgroundColor = 'transparent';
2414
+ el.style.backgroundImage = 'none';
2415
+ el.style.border = 'none';
2416
+ el.style.boxShadow = 'none';
2417
+ el.style.padding = '0';
2418
+ el.style.overflow = 'visible';
2419
+ el.tabIndex = el.tabIndex >= 0 ? el.tabIndex : 0;
2420
+ el.replaceChildren(scene);
2421
+ }
2422
+
2423
+ function destroy$7(el) {
2424
+ const state = stateMap$2.get(el);
2425
+ el.classList.remove(CSS_CLASS$7);
2426
+ el.style.removeProperty('--readdy-anim-card-flip-duration');
2427
+ el.style.removeProperty('--readdy-anim-card-flip-perspective');
2428
+
2429
+ if (state) {
2430
+ if (state.previousMinHeight) {
2431
+ el.style.minHeight = state.previousMinHeight;
2432
+ } else {
2433
+ el.style.removeProperty('min-height');
2434
+ }
2435
+ if (state.previousHeight) {
2436
+ el.style.height = state.previousHeight;
2437
+ } else {
2438
+ el.style.removeProperty('height');
2439
+ }
2440
+ if (state.previousTabIndex === null) {
2441
+ el.removeAttribute('tabindex');
2442
+ } else {
2443
+ el.setAttribute('tabindex', state.previousTabIndex);
2444
+ }
2445
+ Object.assign(el.style, state.previousInlineStyles);
2446
+ el.replaceChildren(...state.originalNodes);
2447
+ stateMap$2.delete(el);
2448
+ } else {
2449
+ el.removeAttribute('tabindex');
2450
+ }
2451
+ }
2452
+
2453
+ var cardFlip = /*#__PURE__*/Object.freeze({
2454
+ __proto__: null,
2455
+ ANIMATION_ID: ANIMATION_ID$7,
2456
+ destroy: destroy$7,
2457
+ init: init$7
2458
+ });
2459
+
2460
+ function hasUsableBackgroundImage(node) {
2461
+ const style = window.getComputedStyle(node);
2462
+ return Boolean(style.backgroundImage && style.backgroundImage !== 'none')
2463
+ }
2464
+
2465
+ function resolveCardMediaElement(el, mediaClass) {
2466
+ const byClass = el.querySelector(`.${mediaClass}`);
2467
+ if (byClass instanceof HTMLElement) {
2468
+ return byClass
2469
+ }
2470
+
2471
+ const image = el.querySelector('img');
2472
+ if (image instanceof HTMLImageElement) {
2473
+ let candidate = image.parentElement;
2474
+ while (candidate && candidate !== el) {
2475
+ const style = window.getComputedStyle(candidate);
2476
+ if (
2477
+ style.overflow === 'hidden' ||
2478
+ style.position !== 'static' ||
2479
+ candidate.childElementCount === 1 ||
2480
+ hasUsableBackgroundImage(candidate)
2481
+ ) {
2482
+ return candidate
2483
+ }
2484
+ candidate = candidate.parentElement;
2485
+ }
2486
+ }
2487
+
2488
+ const backgroundCandidate = Array.from(el.querySelectorAll('*')).find((node) => {
2489
+ if (!(node instanceof HTMLElement)) {
2490
+ return false
2491
+ }
2492
+ return hasUsableBackgroundImage(node)
2493
+ });
2494
+
2495
+ if (backgroundCandidate instanceof HTMLElement) {
2496
+ return backgroundCandidate
2497
+ }
2498
+
2499
+ return el.firstElementChild instanceof HTMLElement ? el.firstElementChild : el
2500
+ }
2501
+
2502
+ const ANIMATION_ID$6 = buildAnimId('image-zoom-rotate');
2503
+
2504
+ const CSS_CLASS$6 = buildAnimClass('image-zoom-rotate');
2505
+ const MEDIA_CLASS$1 = buildAnimClass('card-media');
2506
+
2507
+ const autoMediaState = new WeakMap();
2508
+
2509
+ function init$6(el, options = {}) {
2510
+ if (!el.classList.contains(CSS_CLASS$6)) {
2511
+ el.classList.add(CSS_CLASS$6);
2512
+ }
2513
+
2514
+ el.style.setProperty('--readdy-anim-image-zoom-scale', `${options.scale ?? 1.08}`);
2515
+ el.style.setProperty('--readdy-anim-image-zoom-rotate', `${options.rotate ?? 2}deg`);
2516
+ el.style.setProperty('--readdy-anim-image-zoom-duration', `${options.duration ?? 500}ms`);
2517
+
2518
+ const media = resolveCardMediaElement(el, MEDIA_CLASS$1);
2519
+ if (!media) return
2520
+
2521
+ const state = {
2522
+ media,
2523
+ addedMediaClass: false,
2524
+ };
2525
+
2526
+ if (!media.classList.contains(MEDIA_CLASS$1)) {
2527
+ media.classList.add(MEDIA_CLASS$1);
2528
+ state.addedMediaClass = true;
2529
+ }
2530
+
2531
+ autoMediaState.set(el, state);
2532
+ }
2533
+
2534
+ function destroy$6(el) {
2535
+ el.classList.remove(CSS_CLASS$6);
2536
+ el.style.removeProperty('--readdy-anim-image-zoom-scale');
2537
+ el.style.removeProperty('--readdy-anim-image-zoom-rotate');
2538
+ el.style.removeProperty('--readdy-anim-image-zoom-duration');
2539
+
2540
+ const state = autoMediaState.get(el);
2541
+ if (state?.addedMediaClass) {
2542
+ state.media?.classList.remove(MEDIA_CLASS$1);
2543
+ }
2544
+ autoMediaState.delete(el);
2545
+ }
2546
+
2547
+ var imageZoomRotate = /*#__PURE__*/Object.freeze({
2548
+ __proto__: null,
2549
+ ANIMATION_ID: ANIMATION_ID$6,
2550
+ destroy: destroy$6,
2551
+ init: init$6
2552
+ });
2553
+
2554
+ const ANIMATION_ID$5 = buildAnimId('rgb-split-glitch');
2555
+
2556
+ const CSS_CLASS$5 = buildAnimClass('rgb-split-glitch');
2557
+
2558
+ function init$5(el, options = {}) {
2559
+ if (!el.classList.contains(CSS_CLASS$5)) {
2560
+ el.classList.add(CSS_CLASS$5);
2561
+ }
2562
+
2563
+ el.style.setProperty('--readdy-anim-rgb-glitch-duration', `${options.duration ?? 1100}ms`);
2564
+ el.style.setProperty('--readdy-anim-rgb-glitch-shift', `${options.shift ?? 3}px`);
2565
+ el.style.setProperty('--readdy-anim-rgb-glitch-shadow', `${options.shadowOffset ?? 2}px`);
2566
+ }
2567
+
2568
+ function destroy$5(el) {
2569
+ el.classList.remove(CSS_CLASS$5);
2570
+ el.style.removeProperty('--readdy-anim-rgb-glitch-duration');
2571
+ el.style.removeProperty('--readdy-anim-rgb-glitch-shift');
2572
+ el.style.removeProperty('--readdy-anim-rgb-glitch-shadow');
2573
+ }
2574
+
2575
+ var rgbSplitGlitch = /*#__PURE__*/Object.freeze({
2576
+ __proto__: null,
2577
+ ANIMATION_ID: ANIMATION_ID$5,
2578
+ destroy: destroy$5,
2579
+ init: init$5
2580
+ });
2581
+
2582
+ const ANIMATION_ID$4 = buildAnimId('card-fan-spread');
2583
+
2584
+ const CSS_CLASS$4 = buildAnimClass('card-fan-spread');
2585
+ const STACK_CLASS = buildAnimClass('card-fan-stack');
2586
+ const ITEM_CLASS = buildAnimClass('card-fan-item');
2587
+ const SURFACE_CLASS = buildAnimClass('card-fan-surface');
2588
+ const VISUAL_CLASS = buildAnimClass('card-fan-visual');
2589
+ const VISUAL_TEXT_CLASS = buildAnimClass('card-fan-visual-text');
2590
+ const stateMap$1 = new WeakMap();
2591
+
2592
+ function buildCardVisual(el) {
2593
+ const visual = el.cloneNode(true);
2594
+ visual.classList.add(VISUAL_CLASS);
2595
+ visual.removeAttribute('id');
2596
+ visual.removeAttribute('tabindex');
2597
+ visual.removeAttribute('aria-labelledby');
2598
+ visual.removeAttribute('aria-describedby');
2599
+ visual.removeAttribute('aria-controls');
2600
+ visual.querySelectorAll('[id]').forEach((node) => node.removeAttribute('id'));
2601
+ visual.querySelectorAll('button, a, input, textarea, select, [tabindex]').forEach((node) => {
2602
+ node.setAttribute('aria-hidden', 'true');
2603
+ node.setAttribute('tabindex', '-1');
2604
+ node.style.pointerEvents = 'none';
2605
+ });
2606
+ visual.querySelectorAll('video, audio').forEach((node) => {
2607
+ node.pause?.();
2608
+ node.removeAttribute('autoplay');
2609
+ node.removeAttribute('controls');
2610
+ });
2611
+ visual.querySelectorAll('*').forEach((node) => {
2612
+ if (node.closest(`.${buildAnimClass('card-media')}`)) return
2613
+ if (node.children.length === 0 && (node.textContent ?? '').trim()) {
2614
+ node.classList.add(VISUAL_TEXT_CLASS);
2615
+ }
2616
+ });
2617
+ return visual
2618
+ }
2619
+
2620
+ function buildLayer(visualTemplate, index, radius) {
2621
+ const item = document.createElement('div');
2622
+ item.className = ITEM_CLASS;
2623
+ item.setAttribute('aria-hidden', 'true');
2624
+ item.style.setProperty('--readdy-anim-card-fan-index', `${index}`);
2625
+
2626
+ const surface = document.createElement('div');
2627
+ surface.className = SURFACE_CLASS;
2628
+ surface.style.borderRadius = radius;
2629
+ surface.appendChild(visualTemplate.cloneNode(true));
2630
+ item.appendChild(surface);
2631
+ return item
2632
+ }
2633
+
2634
+ function ensureStack(el, visual) {
2635
+ const stack = document.createElement('div');
2636
+ stack.className = STACK_CLASS;
2637
+ stack.setAttribute('aria-hidden', 'true');
2638
+
2639
+ for (let index = 0; index < 2; index += 1) {
2640
+ stack.appendChild(buildLayer(visual.visualTemplate, index, visual.radius));
2641
+ }
2642
+
2643
+ el.insertBefore(stack, el.firstChild);
2644
+ return stack
2645
+ }
2646
+
2647
+ function init$4(el, options = {}) {
2648
+ destroy$4(el);
2649
+
2650
+ el.classList.add(CSS_CLASS$4);
2651
+ const spreadDistance = options.spreadDistance ?? 72;
2652
+ const spreadRotate = options.spreadRotate ?? 24;
2653
+ const depthRotate = options.depthRotate ?? 18;
2654
+ const lift = options.lift ?? 14;
2655
+ const duration = options.duration ?? 550;
2656
+
2657
+ el.style.setProperty('--readdy-anim-card-fan-distance', `${spreadDistance}px`);
2658
+ el.style.setProperty('--readdy-anim-card-fan-rotate', `${spreadRotate}deg`);
2659
+ el.style.setProperty('--readdy-anim-card-fan-depth-rotate', `${depthRotate}deg`);
2660
+ el.style.setProperty('--readdy-anim-card-fan-lift', `${lift}px`);
2661
+ el.style.setProperty('--readdy-anim-card-fan-duration', `${duration}ms`);
2662
+
2663
+ const visual = {
2664
+ visualTemplate: buildCardVisual(el),
2665
+ radius: window.getComputedStyle(el).borderRadius || 'inherit',
2666
+ };
2667
+ const stack = ensureStack(el, visual);
2668
+ const state = {
2669
+ savedTabIndex: el.getAttribute('tabindex'),
2670
+ toggle: null,
2671
+ onKeyDown: null,
2672
+ stack,
2673
+ };
2674
+
2675
+ el.tabIndex = el.tabIndex >= 0 ? el.tabIndex : 0;
2676
+
2677
+ if (prefersReducedMotion()) {
2678
+ stateMap$1.set(el, state);
2679
+ return
2680
+ }
2681
+
2682
+ state.toggle = () => {
2683
+ el.classList.toggle('is-spread');
2684
+ };
2685
+
2686
+ state.onKeyDown = (event) => {
2687
+ if (event.key === 'Enter' || event.key === ' ') {
2688
+ event.preventDefault();
2689
+ state.toggle();
2690
+ }
2691
+ };
2692
+
2693
+ el.addEventListener('click', state.toggle);
2694
+ el.addEventListener('keydown', state.onKeyDown);
2695
+ stateMap$1.set(el, state);
2696
+ }
2697
+
2698
+ function destroy$4(el) {
2699
+ const state = stateMap$1.get(el);
2700
+ if (state) {
2701
+ if (state.toggle) {
2702
+ el.removeEventListener('click', state.toggle);
2703
+ }
2704
+ if (state.onKeyDown) {
2705
+ el.removeEventListener('keydown', state.onKeyDown);
2706
+ }
2707
+ if (state.savedTabIndex === null) {
2708
+ el.removeAttribute('tabindex');
2709
+ } else {
2710
+ el.setAttribute('tabindex', state.savedTabIndex);
2711
+ }
2712
+ state.stack?.remove();
2713
+ stateMap$1.delete(el);
2714
+ }
2715
+
2716
+ el.classList.remove(CSS_CLASS$4, 'is-spread');
2717
+ el.style.removeProperty('--readdy-anim-card-fan-distance');
2718
+ el.style.removeProperty('--readdy-anim-card-fan-rotate');
2719
+ el.style.removeProperty('--readdy-anim-card-fan-depth-rotate');
2720
+ el.style.removeProperty('--readdy-anim-card-fan-lift');
2721
+ el.style.removeProperty('--readdy-anim-card-fan-duration');
2722
+ el.querySelector(`.${STACK_CLASS}`)?.remove();
2723
+ }
2724
+
2725
+ var cardFanSpread = /*#__PURE__*/Object.freeze({
2726
+ __proto__: null,
2727
+ ANIMATION_ID: ANIMATION_ID$4,
2728
+ destroy: destroy$4,
2729
+ init: init$4
2730
+ });
2731
+
2732
+ const ANIMATION_ID$3 = buildAnimId('image-magnifier');
2733
+
2734
+ const CSS_CLASS$3 = buildAnimClass('image-magnifier');
2735
+ const MEDIA_CLASS = buildAnimClass('card-media');
2736
+ const ENHANCED_MEDIA_CLASS = buildAnimClass('image-magnifier-media');
2737
+ const LENS_CLASS = buildAnimClass('image-magnifier-lens');
2738
+ const stateMap = new WeakMap();
2739
+
2740
+ function resolveImageUrl(image) {
2741
+ try {
2742
+ return new URL(image.currentSrc || image.src, document.baseURI).href
2743
+ } catch {
2744
+ return image.currentSrc || image.src
2745
+ }
2746
+ }
2747
+
2748
+ function parsePositionToken(token, axis) {
2749
+ const value = token.trim().toLowerCase();
2750
+ if (!value) {
2751
+ return null
2752
+ }
2753
+
2754
+ if (value === 'center') {
2755
+ return { type: 'factor', value: 0.5 }
2756
+ }
2757
+
2758
+ if (axis === 'x') {
2759
+ if (value === 'left') return { type: 'factor', value: 0 }
2760
+ if (value === 'right') return { type: 'factor', value: 1 }
2761
+ }
2762
+
2763
+ if (axis === 'y') {
2764
+ if (value === 'top') return { type: 'factor', value: 0 }
2765
+ if (value === 'bottom') return { type: 'factor', value: 1 }
2766
+ }
2767
+
2768
+ if (value.endsWith('%')) {
2769
+ const percentage = Number.parseFloat(value);
2770
+ if (Number.isFinite(percentage)) {
2771
+ return { type: 'factor', value: percentage / 100 }
2772
+ }
2773
+ }
2774
+
2775
+ if (value.endsWith('px')) {
2776
+ const pixels = Number.parseFloat(value);
2777
+ if (Number.isFinite(pixels)) {
2778
+ return { type: 'px', value: pixels }
2779
+ }
2780
+ }
2781
+
2782
+ return null
2783
+ }
2784
+
2785
+ function resolveObjectPosition(image) {
2786
+ const raw = window.getComputedStyle(image).objectPosition || '50% 50%';
2787
+ const tokens = raw.split(/\s+/).filter(Boolean);
2788
+
2789
+ if (tokens.length === 0) {
2790
+ return {
2791
+ x: { type: 'factor', value: 0.5 },
2792
+ y: { type: 'factor', value: 0.5 },
2793
+ }
2794
+ }
2795
+
2796
+ if (tokens.length === 1) {
2797
+ const token = tokens[0];
2798
+ const x = parsePositionToken(token, 'x');
2799
+ const y = parsePositionToken(token, 'y');
2800
+
2801
+ if (y && !x) {
2802
+ return { x: { type: 'factor', value: 0.5 }, y }
2803
+ }
2804
+
2805
+ return {
2806
+ x: x ?? { type: 'factor', value: 0.5 },
2807
+ y: { type: 'factor', value: 0.5 },
2808
+ }
2809
+ }
2810
+
2811
+ let xToken = tokens[0];
2812
+ let yToken = tokens[1];
2813
+ const firstIsVertical = ['top', 'bottom'].includes(tokens[0].toLowerCase());
2814
+ const secondIsHorizontal = ['left', 'right'].includes(tokens[1].toLowerCase());
2815
+
2816
+ if (firstIsVertical && secondIsHorizontal) {
2817
+ xToken = tokens[1];
2818
+ yToken = tokens[0];
2819
+ }
2820
+
2821
+ return {
2822
+ x: parsePositionToken(xToken, 'x') ?? { type: 'factor', value: 0.5 },
2823
+ y: parsePositionToken(yToken, 'y') ?? { type: 'factor', value: 0.5 },
2824
+ }
2825
+ }
2826
+
2827
+ function resolveObjectOffset(availableSpace, position) {
2828
+ if (position.type === 'px') {
2829
+ return position.value
2830
+ }
2831
+ return availableSpace * position.value
2832
+ }
2833
+
2834
+ function ensureLens(el) {
2835
+ const media = resolveCardMediaElement(el, MEDIA_CLASS);
2836
+ media.classList.add(ENHANCED_MEDIA_CLASS);
2837
+
2838
+ let lens = media.querySelector(`.${LENS_CLASS}`);
2839
+ if (!lens) {
2840
+ lens = document.createElement('span');
2841
+ lens.className = LENS_CLASS;
2842
+ media.appendChild(lens);
2843
+ }
2844
+
2845
+ return { media, lens }
2846
+ }
2847
+
2848
+ function syncLensSurface(media, lens, zoomFactor) {
2849
+ const image = media.querySelector('img');
2850
+ const computed = window.getComputedStyle(media);
2851
+
2852
+ if (image?.currentSrc || image?.src) {
2853
+ lens.style.backgroundImage = `url("${resolveImageUrl(image)}")`;
2854
+ lens.style.backgroundColor = 'transparent';
2855
+ lens.style.backgroundRepeat = 'no-repeat';
2856
+ lens.style.removeProperty('background-size');
2857
+ return
2858
+ }
2859
+
2860
+ lens.style.backgroundImage = computed.backgroundImage;
2861
+ lens.style.backgroundColor = computed.backgroundColor;
2862
+ lens.style.backgroundRepeat = computed.backgroundRepeat;
2863
+ lens.style.removeProperty('background-size');
2864
+ }
2865
+
2866
+ function primeLensSurface(el, state, zoomFactor) {
2867
+ const { media, lens, image } = state;
2868
+ const markReady = () => {
2869
+ if (stateMap.get(el) !== state) {
2870
+ return
2871
+ }
2872
+ state.surfaceReady = true;
2873
+ syncLensSurface(media, lens);
2874
+ if (state.lastPointer) {
2875
+ syncLensPosition({
2876
+ mediaRect: media.getBoundingClientRect(),
2877
+ lens,
2878
+ image,
2879
+ pointerX: state.lastPointer.x,
2880
+ pointerY: state.lastPointer.y,
2881
+ lensSize: state.lensSize,
2882
+ zoomFactor,
2883
+ });
2884
+ }
2885
+ };
2886
+
2887
+ if (!(image?.currentSrc || image?.src)) {
2888
+ markReady();
2889
+ return
2890
+ }
2891
+
2892
+ syncLensSurface(media, lens);
2893
+
2894
+ // If the image is already visible enough to be used as a magnifier source,
2895
+ // don't block pointer interaction on decode/load timing.
2896
+ state.surfaceReady = true;
2897
+
2898
+ if (image.complete && image.naturalWidth) {
2899
+ if (typeof image.decode === 'function') {
2900
+ image.decode().then(markReady).catch(markReady);
2901
+ return
2902
+ }
2903
+
2904
+ markReady();
2905
+ return
2906
+ }
2907
+
2908
+ state.onLoad = () => {
2909
+ markReady();
2910
+ };
2911
+ image.addEventListener('load', state.onLoad, { once: true });
2912
+ }
2913
+
2914
+ function syncLensPosition({
2915
+ mediaRect,
2916
+ lens,
2917
+ image,
2918
+ pointerX,
2919
+ pointerY,
2920
+ lensSize,
2921
+ zoomFactor,
2922
+ }) {
2923
+ const lensX = pointerX - mediaRect.left;
2924
+ const lensY = pointerY - mediaRect.top;
2925
+
2926
+ lens.style.setProperty('--readdy-anim-image-magnifier-lens-x', `${lensX}px`);
2927
+ lens.style.setProperty('--readdy-anim-image-magnifier-lens-y', `${lensY}px`);
2928
+ lens.style.opacity = '1';
2929
+
2930
+ if (image?.currentSrc || image?.src) {
2931
+ const imageRect = image.getBoundingClientRect();
2932
+ const naturalWidth = image.naturalWidth;
2933
+ const naturalHeight = image.naturalHeight;
2934
+
2935
+ if (naturalWidth && naturalHeight && imageRect.width && imageRect.height) {
2936
+ const localX = Math.min(Math.max(pointerX - imageRect.left, 0), imageRect.width);
2937
+ const localY = Math.min(Math.max(pointerY - imageRect.top, 0), imageRect.height);
2938
+ const scale = Math.max(imageRect.width / naturalWidth, imageRect.height / naturalHeight);
2939
+ const renderedWidth = naturalWidth * scale;
2940
+ const renderedHeight = naturalHeight * scale;
2941
+ const objectPosition = resolveObjectPosition(image);
2942
+ const offsetX = resolveObjectOffset(imageRect.width - renderedWidth, objectPosition.x);
2943
+ const offsetY = resolveObjectOffset(imageRect.height - renderedHeight, objectPosition.y);
2944
+
2945
+ lens.style.backgroundSize = `${renderedWidth * zoomFactor}px ${renderedHeight * zoomFactor}px`;
2946
+ lens.style.backgroundPosition = `${
2947
+ -(localX - offsetX) * zoomFactor + lensSize / 2
2948
+ }px ${-(localY - offsetY) * zoomFactor + lensSize / 2}px`;
2949
+ return
2950
+ }
2951
+ }
2952
+
2953
+ const localX = (lensX / mediaRect.width) * 100;
2954
+ const localY = (lensY / mediaRect.height) * 100;
2955
+ lens.style.setProperty('--readdy-anim-magnifier-x', `${localX}%`);
2956
+ lens.style.setProperty('--readdy-anim-magnifier-y', `${localY}%`);
2957
+ lens.style.backgroundPosition = `${localX}% ${localY}%`;
2958
+ }
2959
+
2960
+ function init$3(el, options = {}) {
2961
+ destroy$3(el);
2962
+
2963
+ el.classList.add(CSS_CLASS$3);
2964
+
2965
+ if (prefersReducedMotion()) {
2966
+ return
2967
+ }
2968
+
2969
+ const lensSize = options.lensSize ?? 104;
2970
+ const zoom = options.zoom ?? 320;
2971
+ const zoomFactor = zoom / 100;
2972
+ const fadeDuration = options.fadeDuration ?? 160;
2973
+
2974
+ el.style.setProperty('--readdy-anim-image-magnifier-lens-size', `${lensSize}px`);
2975
+ el.style.setProperty('--readdy-anim-image-magnifier-zoom', `${zoom}%`);
2976
+ el.style.setProperty('--readdy-anim-image-magnifier-fade-duration', `${fadeDuration}ms`);
2977
+
2978
+ const { media, lens } = ensureLens(el);
2979
+ const image = media.querySelector('img');
2980
+ const state = {
2981
+ media,
2982
+ lens,
2983
+ cleanupPointerFollow: () => {},
2984
+ image,
2985
+ onLoad: null,
2986
+ surfaceReady: false,
2987
+ lastPointer: null,
2988
+ lensSize,
2989
+ };
2990
+
2991
+ const onMove = (event, context) => {
2992
+ state.lastPointer = {
2993
+ x: event.clientX,
2994
+ y: event.clientY,
2995
+ };
2996
+ if (!state.surfaceReady) {
2997
+ return
2998
+ }
2999
+
3000
+ syncLensPosition({
3001
+ mediaRect: context.rect,
3002
+ lens,
3003
+ image,
3004
+ pointerX: event.clientX,
3005
+ pointerY: event.clientY,
3006
+ lensSize,
3007
+ zoomFactor,
3008
+ });
3009
+ };
3010
+
3011
+ const onLeave = () => {
3012
+ lens.style.opacity = '0';
3013
+ state.lastPointer = null;
3014
+ };
3015
+
3016
+ const onEnter = (event, context) => {
3017
+ state.lastPointer = {
3018
+ x: event.clientX,
3019
+ y: event.clientY,
3020
+ };
3021
+ if (!state.surfaceReady) {
3022
+ return
3023
+ }
3024
+
3025
+ syncLensPosition({
3026
+ mediaRect: context.rect,
3027
+ lens,
3028
+ image,
3029
+ pointerX: event.clientX,
3030
+ pointerY: event.clientY,
3031
+ lensSize,
3032
+ zoomFactor,
3033
+ });
3034
+ };
3035
+
3036
+ const cleanupPointerFollow = attachPointerFollow(media, { onEnter, onMove, onLeave });
3037
+ state.cleanupPointerFollow = cleanupPointerFollow;
3038
+ stateMap.set(el, state);
3039
+ primeLensSurface(el, state, zoomFactor);
3040
+ }
3041
+
3042
+ function destroy$3(el) {
3043
+ const state = stateMap.get(el);
3044
+ if (state) {
3045
+ state.cleanupPointerFollow();
3046
+ if (state.image && state.onLoad) {
3047
+ state.image.removeEventListener('load', state.onLoad);
3048
+ }
3049
+ state.media.classList.remove(ENHANCED_MEDIA_CLASS);
3050
+ stateMap.delete(el);
3051
+ }
3052
+
3053
+ el.classList.remove(CSS_CLASS$3);
3054
+ el.style.removeProperty('--readdy-anim-image-magnifier-lens-size');
3055
+ el.style.removeProperty('--readdy-anim-image-magnifier-zoom');
3056
+ el.style.removeProperty('--readdy-anim-image-magnifier-fade-duration');
3057
+ el.querySelector(`.${LENS_CLASS}`)?.remove();
3058
+ }
3059
+
3060
+ var imageMagnifier = /*#__PURE__*/Object.freeze({
3061
+ __proto__: null,
3062
+ ANIMATION_ID: ANIMATION_ID$3,
3063
+ destroy: destroy$3,
3064
+ init: init$3
3065
+ });
3066
+
3067
+ const ANIMATION_ID$2 = buildAnimId('pop-in-stack');
3068
+
3069
+ const CSS_CLASS$2 = buildAnimClass('pop-in-stack');
3070
+
3071
+ function init$2(el, options = {}) {
3072
+ if (!el.classList.contains(CSS_CLASS$2)) {
3073
+ el.classList.add(CSS_CLASS$2);
3074
+ }
3075
+
3076
+ el.style.setProperty('--readdy-anim-pop-delay', `${options.delay ?? 0}ms`);
3077
+ el.style.setProperty('--readdy-anim-pop-duration', `${options.duration ?? 600}ms`);
3078
+ el.style.setProperty('--readdy-anim-pop-offset', `${options.offset ?? 18}px`);
3079
+ el.style.setProperty('--readdy-anim-pop-scale-start', `${options.scaleStart ?? 0.88}`);
3080
+ }
3081
+
3082
+ function destroy$2(el) {
3083
+ el.classList.remove(CSS_CLASS$2);
3084
+ el.style.removeProperty('--readdy-anim-pop-delay');
3085
+ el.style.removeProperty('--readdy-anim-pop-duration');
3086
+ el.style.removeProperty('--readdy-anim-pop-offset');
3087
+ el.style.removeProperty('--readdy-anim-pop-scale-start');
3088
+ }
3089
+
3090
+ var popInStack = /*#__PURE__*/Object.freeze({
3091
+ __proto__: null,
3092
+ ANIMATION_ID: ANIMATION_ID$2,
3093
+ destroy: destroy$2,
3094
+ init: init$2
3095
+ });
3096
+
3097
+ const ANIMATION_ID$1 = buildAnimId('bounce-in-bottom');
3098
+
3099
+ const CSS_CLASS$1 = buildAnimClass('bounce-in-bottom');
3100
+
3101
+ function init$1(el, options = {}) {
3102
+ if (!el.classList.contains(CSS_CLASS$1)) {
3103
+ el.classList.add(CSS_CLASS$1);
3104
+ }
3105
+ }
3106
+
3107
+ function destroy$1(el) {
3108
+ el.classList.remove(CSS_CLASS$1);
3109
+ }
3110
+
3111
+ var bounceInBottom = /*#__PURE__*/Object.freeze({
3112
+ __proto__: null,
3113
+ ANIMATION_ID: ANIMATION_ID$1,
3114
+ destroy: destroy$1,
3115
+ init: init$1
3116
+ });
3117
+
3118
+ const ANIMATION_ID = buildAnimId('reveal-from-top');
3119
+
3120
+ const CSS_CLASS = buildAnimClass('reveal-from-top');
3121
+
3122
+ function init(el, options = {}) {
3123
+ if (!el.classList.contains(CSS_CLASS)) {
3124
+ el.classList.add(CSS_CLASS);
3125
+ }
3126
+ }
3127
+
3128
+ function destroy(el) {
3129
+ el.classList.remove(CSS_CLASS);
3130
+ }
3131
+
3132
+ var revealFromTop = /*#__PURE__*/Object.freeze({
3133
+ __proto__: null,
3134
+ ANIMATION_ID: ANIMATION_ID,
3135
+ destroy: destroy,
3136
+ init: init
3137
+ });
3138
+
3139
+ /**
3140
+ * UMD bundle 入口 —— 聚合全部唯一动效的 init/destroy
3141
+ * rollup UMD name='ReaddyAnim',默认导出一个以 ANIMATION_ID 为 key 的注册表,
3142
+ * 因此浏览器端可以直接通过 window.ReaddyAnim[id] 取到对应动效。
3143
+ */
3144
+
3145
+
3146
+ function defineAnimation(mod) {
3147
+ return {
3148
+ init: mod.init,
3149
+ destroy: mod.destroy,
3150
+ }
3151
+ }
3152
+
3153
+ const registry = {
3154
+ [ANIMATION_ID$x]: defineAnimation(letterBounce),
3155
+ [ANIMATION_ID$w]: defineAnimation(shimmerText),
3156
+ [ANIMATION_ID$v]: defineAnimation(textType),
3157
+ [ANIMATION_ID$u]: defineAnimation(gradientText),
3158
+ [ANIMATION_ID$t]: defineAnimation(flyInChars),
3159
+ [ANIMATION_ID$s]: defineAnimation(blurRise),
3160
+ [ANIMATION_ID$r]: defineAnimation(splitText),
3161
+ [ANIMATION_ID$q]: defineAnimation(shuffle),
3162
+ [ANIMATION_ID$p]: defineAnimation(rollIn),
3163
+ [ANIMATION_ID$o]: defineAnimation(animeSplittext),
3164
+ [ANIMATION_ID$n]: defineAnimation(wordCurtainReveal),
3165
+ [ANIMATION_ID$m]: defineAnimation(bounceInDown),
3166
+ [ANIMATION_ID$l]: defineAnimation(magneticHover),
3167
+ [ANIMATION_ID$k]: defineAnimation(borderBeam),
3168
+ [ANIMATION_ID$j]: defineAnimation(shimmerBorder),
3169
+ [ANIMATION_ID$i]: defineAnimation(rainbowButton),
3170
+ [ANIMATION_ID$h]: defineAnimation(sketchButton),
3171
+ [ANIMATION_ID$g]: defineAnimation(confettiButton),
3172
+ [ANIMATION_ID$f]: defineAnimation(glowCta),
3173
+ [ANIMATION_ID$e]: defineAnimation(bubbleButton),
3174
+ [ANIMATION_ID$d]: defineAnimation(bounceElastic),
3175
+ [ANIMATION_ID$c]: defineAnimation(pulse),
3176
+ [ANIMATION_ID$b]: defineAnimation(blurFadeIn),
3177
+ [ANIMATION_ID$a]: defineAnimation(flip3d),
3178
+ [ANIMATION_ID$9]: defineAnimation(floatIdle),
3179
+ [ANIMATION_ID$8]: defineAnimation(tiltedCard),
3180
+ [ANIMATION_ID$7]: defineAnimation(cardFlip),
3181
+ [ANIMATION_ID$6]: defineAnimation(imageZoomRotate),
3182
+ [ANIMATION_ID$5]: defineAnimation(rgbSplitGlitch),
3183
+ [ANIMATION_ID$4]: defineAnimation(cardFanSpread),
3184
+ [ANIMATION_ID$3]: defineAnimation(imageMagnifier),
3185
+ [ANIMATION_ID$2]: defineAnimation(popInStack),
3186
+ [ANIMATION_ID$1]: defineAnimation(bounceInBottom),
3187
+ [ANIMATION_ID]: defineAnimation(revealFromTop),
3188
+ };
3189
+
3190
+ return registry;
3191
+
3192
+ }));