@sonordev/site-kit 3.0.4 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/AGENTS.md +107 -0
  2. package/agent-manifest.json +377 -0
  3. package/dist/AnalyticsProvider-CD635CHQ.mjs +8 -0
  4. package/dist/{AnalyticsProvider-MLT26JRP.mjs.map → AnalyticsProvider-CD635CHQ.mjs.map} +1 -1
  5. package/dist/AnalyticsProvider-WK2Z6AIN.js +29 -0
  6. package/dist/{AnalyticsProvider-WTOGN7LV.js.map → AnalyticsProvider-WK2Z6AIN.js.map} +1 -1
  7. package/dist/BlogPostFaqSection-4AD2NIGG.js +13 -0
  8. package/dist/{BlogPostFaqSection-H556RV62.js.map → BlogPostFaqSection-4AD2NIGG.js.map} +1 -1
  9. package/dist/{BlogPostFaqSection-VSHOKKUD.mjs → BlogPostFaqSection-TU6YEC7P.mjs} +3 -3
  10. package/dist/{BlogPostFaqSection-VSHOKKUD.mjs.map → BlogPostFaqSection-TU6YEC7P.mjs.map} +1 -1
  11. package/dist/ChatWidget-AIOOZY6H.js +17 -0
  12. package/dist/{ChatWidget-MAL7FB4M.js.map → ChatWidget-AIOOZY6H.js.map} +1 -1
  13. package/dist/ChatWidget-UAAWDBNS.mjs +8 -0
  14. package/dist/{ChatWidget-QPZTPSPE.mjs.map → ChatWidget-UAAWDBNS.mjs.map} +1 -1
  15. package/dist/EngageWidget-EZ5T6H3K.mjs +7 -0
  16. package/dist/{EngageWidget-IPBUA4DW.mjs.map → EngageWidget-EZ5T6H3K.mjs.map} +1 -1
  17. package/dist/EngageWidget-RWVWW56C.js +16 -0
  18. package/dist/{EngageWidget-N3CABK3L.js.map → EngageWidget-RWVWW56C.js.map} +1 -1
  19. package/dist/{SignalCore-4MDIJUAP.mjs → SignalCore-4B4RNYLV.mjs} +60 -47
  20. package/dist/SignalCore-4B4RNYLV.mjs.map +1 -0
  21. package/dist/{SignalCore-ZMFUE3N4.js → SignalCore-AECW2JFP.js} +60 -47
  22. package/dist/SignalCore-AECW2JFP.js.map +1 -0
  23. package/dist/SitemapSync-AICU4SSV.js +15 -0
  24. package/dist/{SitemapSync-FUCH6Y6J.js.map → SitemapSync-AICU4SSV.js.map} +1 -1
  25. package/dist/SitemapSync-CIZCAZXK.mjs +6 -0
  26. package/dist/{SitemapSync-LCSPRAWU.mjs.map → SitemapSync-CIZCAZXK.mjs.map} +1 -1
  27. package/dist/analytics/index.js +11 -9
  28. package/dist/analytics/index.mjs +4 -2
  29. package/dist/blog/index.js +12 -12
  30. package/dist/blog/index.mjs +2 -2
  31. package/dist/blog/server-ui.js +5 -5
  32. package/dist/blog/server-ui.mjs +1 -1
  33. package/dist/brand.css +8 -3
  34. package/dist/{chunk-QTWA44S3.mjs → chunk-2WYEJOGA.mjs} +7 -8
  35. package/dist/chunk-2WYEJOGA.mjs.map +1 -0
  36. package/dist/{chunk-AN4ATCYQ.mjs → chunk-45QHDA7Q.mjs} +3 -3
  37. package/dist/{chunk-AN4ATCYQ.mjs.map → chunk-45QHDA7Q.mjs.map} +1 -1
  38. package/dist/{chunk-RI6JZUAE.js → chunk-4FBV5BJW.js} +7 -8
  39. package/dist/chunk-4FBV5BJW.js.map +1 -0
  40. package/dist/{chunk-YJWKHCOB.js → chunk-4NTMIU6V.js} +13 -11
  41. package/dist/chunk-4NTMIU6V.js.map +1 -0
  42. package/dist/{chunk-YFGKIKXA.mjs → chunk-57QV6NIY.mjs} +3 -3
  43. package/dist/{chunk-YFGKIKXA.mjs.map → chunk-57QV6NIY.mjs.map} +1 -1
  44. package/dist/chunk-5OWZUNNE.js +102 -0
  45. package/dist/chunk-5OWZUNNE.js.map +1 -0
  46. package/dist/{chunk-EUDTPXUI.mjs → chunk-6HPNFWSC.mjs} +3 -3
  47. package/dist/{chunk-EUDTPXUI.mjs.map → chunk-6HPNFWSC.mjs.map} +1 -1
  48. package/dist/{chunk-ZM2ALSBM.js → chunk-7TX5BKVA.js} +18 -7
  49. package/dist/chunk-7TX5BKVA.js.map +1 -0
  50. package/dist/{chunk-FT5JNCD4.mjs → chunk-AB2VYIYU.mjs} +11 -11
  51. package/dist/{chunk-FT5JNCD4.mjs.map → chunk-AB2VYIYU.mjs.map} +1 -1
  52. package/dist/{chunk-I5TJIESQ.js → chunk-BMKZHXWQ.js} +11 -11
  53. package/dist/{chunk-I5TJIESQ.js.map → chunk-BMKZHXWQ.js.map} +1 -1
  54. package/dist/{chunk-KHFNPPOX.mjs → chunk-DSRPKUQI.mjs} +6 -6
  55. package/dist/{chunk-KHFNPPOX.mjs.map → chunk-DSRPKUQI.mjs.map} +1 -1
  56. package/dist/chunk-EAASMIWX.js +258 -0
  57. package/dist/chunk-EAASMIWX.js.map +1 -0
  58. package/dist/{chunk-T4QBSRA4.mjs → chunk-EIWRPGOK.mjs} +37 -60
  59. package/dist/chunk-EIWRPGOK.mjs.map +1 -0
  60. package/dist/{chunk-O7E6QVK3.js → chunk-GCDVKOSM.js} +3 -3
  61. package/dist/{chunk-O7E6QVK3.js.map → chunk-GCDVKOSM.js.map} +1 -1
  62. package/dist/{chunk-KMZ527EM.mjs → chunk-GN62H6EG.mjs} +34 -8
  63. package/dist/chunk-GN62H6EG.mjs.map +1 -0
  64. package/dist/{chunk-UJQYSVYV.js → chunk-GQF6QAQS.js} +4 -4
  65. package/dist/{chunk-UJQYSVYV.js.map → chunk-GQF6QAQS.js.map} +1 -1
  66. package/dist/{chunk-MLJXELPA.js → chunk-HAZN43I6.js} +60 -94
  67. package/dist/chunk-HAZN43I6.js.map +1 -0
  68. package/dist/chunk-LZSCCJ4O.mjs +253 -0
  69. package/dist/chunk-LZSCCJ4O.mjs.map +1 -0
  70. package/dist/{chunk-TCVHI3JP.mjs → chunk-N2HR2E4Z.mjs} +60 -92
  71. package/dist/chunk-N2HR2E4Z.mjs.map +1 -0
  72. package/dist/{chunk-VCWSSGCU.js → chunk-NAVDN4AE.js} +7 -7
  73. package/dist/{chunk-VCWSSGCU.js.map → chunk-NAVDN4AE.js.map} +1 -1
  74. package/dist/chunk-NDHFU4HV.mjs +97 -0
  75. package/dist/chunk-NDHFU4HV.mjs.map +1 -0
  76. package/dist/{chunk-PST3NOEM.mjs → chunk-O237KKCX.mjs} +4 -4
  77. package/dist/{chunk-PST3NOEM.mjs.map → chunk-O237KKCX.mjs.map} +1 -1
  78. package/dist/{chunk-5AESOLXS.mjs → chunk-OTY7EWET.mjs} +13 -11
  79. package/dist/chunk-OTY7EWET.mjs.map +1 -0
  80. package/dist/chunk-Q2NBD54V.js +69 -0
  81. package/dist/chunk-Q2NBD54V.js.map +1 -0
  82. package/dist/{chunk-DGHPOWLU.js → chunk-R5A64DCX.js} +8 -8
  83. package/dist/{chunk-DGHPOWLU.js.map → chunk-R5A64DCX.js.map} +1 -1
  84. package/dist/{chunk-3YQCPLGP.mjs → chunk-RFIWVH3D.mjs} +41 -79
  85. package/dist/chunk-RFIWVH3D.mjs.map +1 -0
  86. package/dist/{chunk-NNZDHLXN.js → chunk-S3YQGTBF.js} +35 -9
  87. package/dist/chunk-S3YQGTBF.js.map +1 -0
  88. package/dist/{chunk-IBDVZ6BF.js → chunk-SLWTG2LJ.js} +69 -74
  89. package/dist/chunk-SLWTG2LJ.js.map +1 -0
  90. package/dist/chunk-SN2O72UF.mjs +6 -0
  91. package/dist/chunk-SN2O72UF.mjs.map +1 -0
  92. package/dist/{chunk-65SMJBHW.mjs → chunk-T2DEEKVQ.mjs} +69 -74
  93. package/dist/chunk-T2DEEKVQ.mjs.map +1 -0
  94. package/dist/{chunk-3GCEFS73.js → chunk-TE3W5REY.js} +39 -62
  95. package/dist/chunk-TE3W5REY.js.map +1 -0
  96. package/dist/{chunk-IFVMZFNT.js → chunk-TVCCZ7NR.js} +41 -79
  97. package/dist/chunk-TVCCZ7NR.js.map +1 -0
  98. package/dist/{chunk-EBJ4S5DU.js → chunk-UT2CF4FC.js} +4 -4
  99. package/dist/{chunk-EBJ4S5DU.js.map → chunk-UT2CF4FC.js.map} +1 -1
  100. package/dist/chunk-V6NVBFEP.js +54 -0
  101. package/dist/chunk-V6NVBFEP.js.map +1 -0
  102. package/dist/{chunk-6FWQMKVO.mjs → chunk-WN5A3KSY.mjs} +18 -7
  103. package/dist/chunk-WN5A3KSY.mjs.map +1 -0
  104. package/dist/chunk-WRZQS7O4.js +8 -0
  105. package/dist/chunk-WRZQS7O4.js.map +1 -0
  106. package/dist/chunk-WZHWWOUC.js +51 -0
  107. package/dist/chunk-WZHWWOUC.js.map +1 -0
  108. package/dist/chunk-X3S6KXAP.mjs +47 -0
  109. package/dist/chunk-X3S6KXAP.mjs.map +1 -0
  110. package/dist/chunk-X4OPM3SK.mjs +43 -0
  111. package/dist/chunk-X4OPM3SK.mjs.map +1 -0
  112. package/dist/chunk-ZPLN537Q.mjs +57 -0
  113. package/dist/chunk-ZPLN537Q.mjs.map +1 -0
  114. package/dist/cli/index.js +8986 -1276
  115. package/dist/cli/index.js.map +1 -1
  116. package/dist/cli/index.mjs +8972 -1280
  117. package/dist/cli/index.mjs.map +1 -1
  118. package/dist/commerce/index.js +50 -48
  119. package/dist/commerce/index.mjs +5 -3
  120. package/dist/engage/index.js +11 -8
  121. package/dist/engage/index.js.map +1 -1
  122. package/dist/engage/index.mjs +8 -5
  123. package/dist/engage/index.mjs.map +1 -1
  124. package/dist/fleet/contract.d.mts +99 -0
  125. package/dist/fleet/contract.d.ts +99 -0
  126. package/dist/fleet/contract.js +53 -0
  127. package/dist/fleet/contract.js.map +1 -0
  128. package/dist/fleet/contract.mjs +4 -0
  129. package/dist/fleet/contract.mjs.map +1 -0
  130. package/dist/fleet/index.d.mts +89 -0
  131. package/dist/fleet/index.d.ts +89 -0
  132. package/dist/fleet/index.js +74 -0
  133. package/dist/fleet/index.js.map +1 -0
  134. package/dist/fleet/index.mjs +9 -0
  135. package/dist/fleet/index.mjs.map +1 -0
  136. package/dist/forms/contract.d.mts +69 -0
  137. package/dist/forms/contract.d.ts +69 -0
  138. package/dist/forms/contract.js +33 -0
  139. package/dist/forms/contract.js.map +1 -0
  140. package/dist/forms/contract.mjs +4 -0
  141. package/dist/forms/contract.mjs.map +1 -0
  142. package/dist/forms/index.js +21 -17
  143. package/dist/forms/index.js.map +1 -1
  144. package/dist/forms/index.mjs +14 -10
  145. package/dist/forms/index.mjs.map +1 -1
  146. package/dist/forms/styles.css +10 -8
  147. package/dist/images/index.js +10 -8
  148. package/dist/images/index.mjs +3 -1
  149. package/dist/index.js +98 -96
  150. package/dist/index.js.map +1 -1
  151. package/dist/index.mjs +9 -7
  152. package/dist/index.mjs.map +1 -1
  153. package/dist/layout/client.d.mts +8 -1
  154. package/dist/layout/client.d.ts +8 -1
  155. package/dist/layout/client.js +8 -3
  156. package/dist/layout/client.mjs +7 -2
  157. package/dist/layout/index.d.mts +7 -1
  158. package/dist/layout/index.d.ts +7 -1
  159. package/dist/layout/index.js +57 -4
  160. package/dist/layout/index.js.map +1 -1
  161. package/dist/layout/index.mjs +56 -3
  162. package/dist/layout/index.mjs.map +1 -1
  163. package/dist/llms/index.d.mts +4 -0
  164. package/dist/llms/index.d.ts +4 -0
  165. package/dist/llms/index.js +12 -12
  166. package/dist/llms/index.mjs +2 -2
  167. package/dist/maps/index.js +9 -18
  168. package/dist/maps/index.js.map +1 -1
  169. package/dist/maps/index.mjs +9 -18
  170. package/dist/maps/index.mjs.map +1 -1
  171. package/dist/portfolio/contract.d.mts +61 -0
  172. package/dist/portfolio/contract.d.ts +61 -0
  173. package/dist/portfolio/contract.js +43 -0
  174. package/dist/portfolio/contract.js.map +1 -0
  175. package/dist/portfolio/contract.mjs +38 -0
  176. package/dist/portfolio/contract.mjs.map +1 -0
  177. package/dist/seo/client.js +4 -2
  178. package/dist/seo/client.mjs +3 -1
  179. package/dist/seo/index.js +4 -2
  180. package/dist/seo/index.js.map +1 -1
  181. package/dist/seo/index.mjs +3 -1
  182. package/dist/seo/index.mjs.map +1 -1
  183. package/dist/seo-pages/contract.d.mts +62 -0
  184. package/dist/seo-pages/contract.d.ts +62 -0
  185. package/dist/seo-pages/contract.js +48 -0
  186. package/dist/seo-pages/contract.js.map +1 -0
  187. package/dist/seo-pages/contract.mjs +44 -0
  188. package/dist/seo-pages/contract.mjs.map +1 -0
  189. package/dist/signal/index.js +11 -11
  190. package/dist/signal/index.mjs +2 -2
  191. package/dist/sitemap/index.js +2 -2
  192. package/dist/sitemap/index.mjs +1 -1
  193. package/dist/sites/contract.d.mts +57 -0
  194. package/dist/sites/contract.d.ts +57 -0
  195. package/dist/sites/contract.js +37 -0
  196. package/dist/sites/contract.js.map +1 -0
  197. package/dist/sites/contract.mjs +4 -0
  198. package/dist/sites/contract.mjs.map +1 -0
  199. package/package.json +44 -4
  200. package/skills/site-kit/SKILL.md +66 -0
  201. package/dist/AnalyticsProvider-MLT26JRP.mjs +0 -6
  202. package/dist/AnalyticsProvider-WTOGN7LV.js +0 -27
  203. package/dist/BlogPostFaqSection-H556RV62.js +0 -13
  204. package/dist/ChatWidget-MAL7FB4M.js +0 -14
  205. package/dist/ChatWidget-QPZTPSPE.mjs +0 -5
  206. package/dist/EngageWidget-IPBUA4DW.mjs +0 -5
  207. package/dist/EngageWidget-N3CABK3L.js +0 -14
  208. package/dist/SignalCore-4MDIJUAP.mjs.map +0 -1
  209. package/dist/SignalCore-ZMFUE3N4.js.map +0 -1
  210. package/dist/SitemapSync-FUCH6Y6J.js +0 -13
  211. package/dist/SitemapSync-LCSPRAWU.mjs +0 -4
  212. package/dist/chunk-3GCEFS73.js.map +0 -1
  213. package/dist/chunk-3YQCPLGP.mjs.map +0 -1
  214. package/dist/chunk-5AESOLXS.mjs.map +0 -1
  215. package/dist/chunk-65SMJBHW.mjs.map +0 -1
  216. package/dist/chunk-6FWQMKVO.mjs.map +0 -1
  217. package/dist/chunk-IBDVZ6BF.js.map +0 -1
  218. package/dist/chunk-IFVMZFNT.js.map +0 -1
  219. package/dist/chunk-KMZ527EM.mjs.map +0 -1
  220. package/dist/chunk-MLJXELPA.js.map +0 -1
  221. package/dist/chunk-NNZDHLXN.js.map +0 -1
  222. package/dist/chunk-QTWA44S3.mjs.map +0 -1
  223. package/dist/chunk-RI6JZUAE.js.map +0 -1
  224. package/dist/chunk-T4QBSRA4.mjs.map +0 -1
  225. package/dist/chunk-TCVHI3JP.mjs.map +0 -1
  226. package/dist/chunk-YJWKHCOB.js.map +0 -1
  227. package/dist/chunk-ZM2ALSBM.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkUJQYSVYV_js = require('../chunk-UJQYSVYV.js');
5
- var chunkI5TJIESQ_js = require('../chunk-I5TJIESQ.js');
4
+ var chunkGQF6QAQS_js = require('../chunk-GQF6QAQS.js');
5
+ var chunkBMKZHXWQ_js = require('../chunk-BMKZHXWQ.js');
6
6
  var chunkIB4FRJDV_js = require('../chunk-IB4FRJDV.js');
7
7
  var chunkJ7QI3GDX_js = require('../chunk-J7QI3GDX.js');
8
8
  require('../chunk-ZSMWDLMK.js');
@@ -880,43 +880,43 @@ function TableOfContents({
880
880
 
881
881
  Object.defineProperty(exports, "BlogFAQ", {
882
882
  enumerable: true,
883
- get: function () { return chunkUJQYSVYV_js.BlogFAQ; }
883
+ get: function () { return chunkGQF6QAQS_js.BlogFAQ; }
884
884
  });
885
885
  Object.defineProperty(exports, "BlogList", {
886
886
  enumerable: true,
887
- get: function () { return chunkI5TJIESQ_js.BlogList; }
887
+ get: function () { return chunkBMKZHXWQ_js.BlogList; }
888
888
  });
889
889
  Object.defineProperty(exports, "BlogPost", {
890
890
  enumerable: true,
891
- get: function () { return chunkI5TJIESQ_js.BlogPost; }
891
+ get: function () { return chunkBMKZHXWQ_js.BlogPost; }
892
892
  });
893
893
  Object.defineProperty(exports, "ClusterLandingPage", {
894
894
  enumerable: true,
895
- get: function () { return chunkI5TJIESQ_js.ClusterLandingPage; }
895
+ get: function () { return chunkBMKZHXWQ_js.ClusterLandingPage; }
896
896
  });
897
897
  Object.defineProperty(exports, "ClusterNavigation", {
898
898
  enumerable: true,
899
- get: function () { return chunkI5TJIESQ_js.ClusterNavigation; }
899
+ get: function () { return chunkBMKZHXWQ_js.ClusterNavigation; }
900
900
  });
901
901
  Object.defineProperty(exports, "ServiceCallout", {
902
902
  enumerable: true,
903
- get: function () { return chunkI5TJIESQ_js.ServiceCallout; }
903
+ get: function () { return chunkBMKZHXWQ_js.ServiceCallout; }
904
904
  });
905
905
  Object.defineProperty(exports, "ServiceCallouts", {
906
906
  enumerable: true,
907
- get: function () { return chunkI5TJIESQ_js.ServiceCallouts; }
907
+ get: function () { return chunkBMKZHXWQ_js.ServiceCallouts; }
908
908
  });
909
909
  Object.defineProperty(exports, "addExternalLinkTargets", {
910
910
  enumerable: true,
911
- get: function () { return chunkI5TJIESQ_js.addExternalLinkTargets; }
911
+ get: function () { return chunkBMKZHXWQ_js.addExternalLinkTargets; }
912
912
  });
913
913
  Object.defineProperty(exports, "normalizeSiteHost", {
914
914
  enumerable: true,
915
- get: function () { return chunkI5TJIESQ_js.normalizeSiteHost; }
915
+ get: function () { return chunkBMKZHXWQ_js.normalizeSiteHost; }
916
916
  });
917
917
  Object.defineProperty(exports, "resolveBlogSiteUrl", {
918
918
  enumerable: true,
919
- get: function () { return chunkI5TJIESQ_js.resolveBlogSiteUrl; }
919
+ get: function () { return chunkBMKZHXWQ_js.resolveBlogSiteUrl; }
920
920
  });
921
921
  exports.AuthorCard = AuthorCard;
922
922
  exports.AuthorPage = AuthorPage;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
- export { BlogFAQ } from '../chunk-PST3NOEM.mjs';
3
- export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation, ServiceCallout, ServiceCallouts, addExternalLinkTargets, normalizeSiteHost, resolveBlogSiteUrl } from '../chunk-FT5JNCD4.mjs';
2
+ export { BlogFAQ } from '../chunk-O237KKCX.mjs';
3
+ export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation, ServiceCallout, ServiceCallouts, addExternalLinkTargets, normalizeSiteHost, resolveBlogSiteUrl } from '../chunk-AB2VYIYU.mjs';
4
4
  import { generateAuthorSchema } from '../chunk-SH4VZDVX.mjs';
5
5
  import { safeJsonLd } from '../chunk-662YHKWW.mjs';
6
6
  import '../chunk-4XPGGLVP.mjs';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkI5TJIESQ_js = require('../chunk-I5TJIESQ.js');
3
+ var chunkBMKZHXWQ_js = require('../chunk-BMKZHXWQ.js');
4
4
  require('../chunk-IB4FRJDV.js');
5
5
  require('../chunk-ZSMWDLMK.js');
6
6
 
@@ -8,19 +8,19 @@ require('../chunk-ZSMWDLMK.js');
8
8
 
9
9
  Object.defineProperty(exports, "BlogList", {
10
10
  enumerable: true,
11
- get: function () { return chunkI5TJIESQ_js.BlogList; }
11
+ get: function () { return chunkBMKZHXWQ_js.BlogList; }
12
12
  });
13
13
  Object.defineProperty(exports, "BlogPost", {
14
14
  enumerable: true,
15
- get: function () { return chunkI5TJIESQ_js.BlogPost; }
15
+ get: function () { return chunkBMKZHXWQ_js.BlogPost; }
16
16
  });
17
17
  Object.defineProperty(exports, "ClusterLandingPage", {
18
18
  enumerable: true,
19
- get: function () { return chunkI5TJIESQ_js.ClusterLandingPage; }
19
+ get: function () { return chunkBMKZHXWQ_js.ClusterLandingPage; }
20
20
  });
21
21
  Object.defineProperty(exports, "ClusterNavigation", {
22
22
  enumerable: true,
23
- get: function () { return chunkI5TJIESQ_js.ClusterNavigation; }
23
+ get: function () { return chunkBMKZHXWQ_js.ClusterNavigation; }
24
24
  });
25
25
  //# sourceMappingURL=server-ui.js.map
26
26
  //# sourceMappingURL=server-ui.js.map
@@ -1,4 +1,4 @@
1
- export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation } from '../chunk-FT5JNCD4.mjs';
1
+ export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation } from '../chunk-AB2VYIYU.mjs';
2
2
  import '../chunk-SH4VZDVX.mjs';
3
3
  import '../chunk-4XPGGLVP.mjs';
4
4
  //# sourceMappingURL=server-ui.mjs.map
package/dist/brand.css CHANGED
@@ -19,9 +19,14 @@
19
19
 
20
20
  :root {
21
21
  /* ── Brand colors ─────────────────────────────────────────────────────── */
22
- --sk-primary: #3b82f6;
23
- --sk-primary-rgb: 59, 130, 246;
24
- --sk-primary-hover: #2563eb;
22
+ /* Default primary is blue-600 (#2563eb, ~5.2:1 on white) — NOT blue-500
23
+ (#3b82f6, ~3.68:1), which fails WCAG AA for white button text / link text.
24
+ Sites that set their own --sk-primary override this; sites that ship the
25
+ default must still pass Lighthouse a11y. Keep this the single source of
26
+ truth for the default primary — forms/styles.css mirrors it verbatim. */
27
+ --sk-primary: #2563eb;
28
+ --sk-primary-rgb: 37, 99, 235;
29
+ --sk-primary-hover: #1d4ed8;
25
30
  --sk-primary-light: #dbeafe;
26
31
  --sk-secondary: #8b5cf6;
27
32
  --sk-secondary-rgb: 139, 92, 246;
@@ -1,7 +1,7 @@
1
1
  'use client';
2
+ import { sonorFetch } from './chunk-LZSCCJ4O.mjs';
2
3
  import { useRef, useEffect } from 'react';
3
4
 
4
- // src/SitemapSync.tsx
5
5
  function inferPageType(urlPath) {
6
6
  if (urlPath === "/" || urlPath === "") return "homepage";
7
7
  if (/^\/services(\/|$)/i.test(urlPath)) return "service";
@@ -61,7 +61,7 @@ function getApiConfig() {
61
61
  }
62
62
  async function parseSitemap(sitemapUrl, debug) {
63
63
  try {
64
- const response = await fetch(sitemapUrl);
64
+ const response = await sonorFetch(sitemapUrl);
65
65
  if (!response.ok) {
66
66
  if (debug) console.warn("[SitemapSync] Failed to fetch sitemap:", response.status);
67
67
  return [];
@@ -118,11 +118,10 @@ async function syncToPortal(entries, apiUrl, apiKey, site, debug, mode = "additi
118
118
  return { success: true, created: 0, updated: 0 };
119
119
  }
120
120
  try {
121
- const response = await fetch(`${apiUrl}/api/public/seo/register-sitemap`, {
121
+ const response = await sonorFetch(`${apiUrl}/api/public/seo/register-sitemap`, {
122
122
  method: "POST",
123
123
  headers: {
124
- "Content-Type": "application/json",
125
- "x-api-key": apiKey
124
+ "Content-Type": "application/json"
126
125
  },
127
126
  body: JSON.stringify({
128
127
  entries: entries.map((e) => ({
@@ -137,7 +136,7 @@ async function syncToPortal(entries, apiUrl, apiKey, site, debug, mode = "additi
137
136
  // SiteKitClientProviders (see __SITE_KIT_SITE__).
138
137
  ...site ? { site } : {}
139
138
  })
140
- });
139
+ }, { apiKey });
141
140
  if (!response.ok) {
142
141
  if (debug) console.error("[SitemapSync] API error:", response.status, response.statusText);
143
142
  return { success: false, created: 0, updated: 0 };
@@ -210,5 +209,5 @@ function SitemapSync({
210
209
  }
211
210
 
212
211
  export { SitemapSync };
213
- //# sourceMappingURL=chunk-QTWA44S3.mjs.map
214
- //# sourceMappingURL=chunk-QTWA44S3.mjs.map
212
+ //# sourceMappingURL=chunk-2WYEJOGA.mjs.map
213
+ //# sourceMappingURL=chunk-2WYEJOGA.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/SitemapSync.tsx"],"names":[],"mappings":"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","file":"chunk-2WYEJOGA.mjs","sourcesContent":["/**\n * SitemapSync - Automatically sync sitemap.xml to Portal API\n *\n * Client-only component. Lives at package root so the main entry does not\n * pull in seo/ (and server-only code). For use in SiteKitProvider and\n * from @sonordev/site-kit/seo.\n *\n * @example\n * ```tsx\n * import { SitemapSync } from '@sonordev/site-kit'\n * // or\n * import { SitemapSync } from '@sonordev/site-kit/seo'\n * ```\n */\n\n'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { sonorFetch } from './shared/sonorFetch'\n\ninterface SitemapSyncProps {\n /** Custom sitemap URL (defaults to /sitemap.xml) */\n sitemapUrl?: string\n /** How often to re-sync in minutes (0 = only on mount, default: 60) */\n syncInterval?: number\n /** Enable debug logging */\n debug?: boolean\n /**\n * Sync mode:\n * - 'additive' (default for runtime): adds/updates pages but never deletes existing ones\n * - 'full-replace': replaces the entire page set (use only for build-time sync via createSitemap)\n */\n mode?: 'additive' | 'full-replace'\n}\n\ninterface SitemapEntry {\n path: string\n lastmod?: string\n changefreq?: string\n priority?: number\n pageType?: string\n}\n\n/**\n * Infer page type from URL path pattern for Signal context.\n */\nfunction inferPageType(urlPath: string): string {\n if (urlPath === '/' || urlPath === '') return 'homepage'\n if (/^\\/services(\\/|$)/i.test(urlPath)) return 'service'\n if (/^\\/compare(\\/|$)/i.test(urlPath)) return 'comparison'\n if (/^\\/(insights|blog)(\\/|$)/i.test(urlPath)) return 'blog'\n if (/^\\/industries(\\/|$)/i.test(urlPath)) return 'industry'\n if (/^\\/work(\\/|$)/i.test(urlPath)) return 'portfolio'\n if (/^\\/faq(\\/|$)/i.test(urlPath)) return 'faq'\n if (/^\\/pricing(\\/|$)/i.test(urlPath)) return 'pricing'\n return 'page'\n}\n\n/**\n * Per-browser-session sync throttle. Build-time sync (createSitemap) is the\n * canonical source of truth; runtime SitemapSync is only a safety net — so\n * re-registering the sitemap on every full page load of every visitor is pure\n * waste (fetch + DOMParser on the visitor's main thread, plus a write per\n * pageview against the API). Stamp the last successful sync in sessionStorage\n * and skip while inside the throttle window.\n */\nconst SYNC_STAMP_KEY = '_sk_sitemap_synced_at'\nconst SYNC_HASH_KEY = '_sk_sitemap_hash'\n\nfunction isRecentlySynced(throttleMinutes: number): boolean {\n try {\n const stamp = sessionStorage.getItem(SYNC_STAMP_KEY)\n if (!stamp) return false\n const elapsed = Date.now() - parseInt(stamp, 10)\n return elapsed >= 0 && elapsed < throttleMinutes * 60 * 1000\n } catch {\n return false // storage unavailable (private mode) — sync as before\n }\n}\n\nfunction stampSynced(): void {\n try {\n sessionStorage.setItem(SYNC_STAMP_KEY, Date.now().toString())\n } catch {\n /* storage unavailable — throttle simply won't apply */\n }\n}\n\n/**\n * Content-hash guard (localStorage, so it survives across sessions): the\n * sitemap of a static site only changes at deploy, so once ONE sync of a given\n * sitemap succeeded from this browser, re-POSTing the identical entry set is\n * pure API load. Hash the parsed entries; skip the POST when unchanged.\n * Keyed by sitemap URL so multiple SitemapSync instances don't collide.\n */\nfunction hashEntries(sitemapUrl: string, entries: SitemapEntry[]): string {\n const text = entries\n .map(e => `${e.path}|${e.lastmod ?? ''}|${e.changefreq ?? ''}|${e.priority ?? ''}`)\n .join('\\n')\n let hash = 0\n for (let i = 0; i < text.length; i++) {\n hash = ((hash << 5) - hash + text.charCodeAt(i)) | 0\n }\n return `${sitemapUrl}:${entries.length}:${hash.toString(16)}`\n}\n\nfunction isAlreadySyncedHash(hash: string): boolean {\n try {\n return localStorage.getItem(SYNC_HASH_KEY) === hash\n } catch {\n return false\n }\n}\n\nfunction storeSyncedHash(hash: string): void {\n try {\n localStorage.setItem(SYNC_HASH_KEY, hash)\n } catch {\n /* storage unavailable — guard simply won't apply */\n }\n}\n\nfunction getApiConfig() {\n if (typeof window === 'undefined') return { apiUrl: '', apiKey: '', site: '' }\n\n const apiUrl = (window as any).__SITE_KIT_API_URL__ || 'https://api.sonor.io'\n const apiKey = (window as any).__SITE_KIT_API_KEY__ || ''\n // Sub-site host — set by SiteKitClientProviders from analytics.site config,\n // NEXT_PUBLIC_SITE_URL host, or window.location.host. Tagged on every\n // seo_pages row from this sitemap so the dashboard can scope the page tree\n // when one Sonor project hosts many sites.\n const site = (window as any).__SITE_KIT_SITE__ || window.location.host || ''\n return { apiUrl, apiKey, site }\n}\n\nasync function parseSitemap(sitemapUrl: string, debug: boolean): Promise<SitemapEntry[]> {\n try {\n const response = await sonorFetch(sitemapUrl)\n if (!response.ok) {\n if (debug) console.warn('[SitemapSync] Failed to fetch sitemap:', response.status)\n return []\n }\n\n const text = await response.text()\n const parser = new DOMParser()\n const doc = parser.parseFromString(text, 'application/xml')\n\n const parseError = doc.querySelector('parsererror')\n if (parseError) {\n if (debug) console.warn('[SitemapSync] Sitemap parse error:', parseError.textContent)\n return []\n }\n\n const urls = doc.querySelectorAll('url')\n const entries: SitemapEntry[] = []\n\n urls.forEach(url => {\n const loc = url.querySelector('loc')?.textContent?.trim()\n if (!loc) return\n\n let path: string\n try {\n const urlObj = new URL(loc)\n path = urlObj.pathname\n } catch {\n path = loc.startsWith('/') ? loc : `/${loc}`\n }\n\n if (path !== '/' && path.endsWith('/')) {\n path = path.slice(0, -1)\n }\n\n // Reject malformed paths (embedded domains, double protocols, etc.)\n if (path.includes('://') || /\\/\\/[a-z0-9.-]+\\.[a-z]{2,}/i.test(path)) {\n if (debug) console.warn(`[SitemapSync] Skipping malformed path: ${path}`)\n return\n }\n\n const lastmod = url.querySelector('lastmod')?.textContent || undefined\n const changefreq = url.querySelector('changefreq')?.textContent || undefined\n const priorityStr = url.querySelector('priority')?.textContent\n const priority = priorityStr ? parseFloat(priorityStr) : undefined\n\n entries.push({ path, lastmod, changefreq, priority })\n })\n\n if (debug) {\n console.log(`[SitemapSync] Parsed ${entries.length} entries from sitemap`)\n }\n\n return entries\n } catch (error) {\n if (debug) console.error('[SitemapSync] Error parsing sitemap:', error)\n return []\n }\n}\n\nasync function syncToPortal(\n entries: SitemapEntry[],\n apiUrl: string,\n apiKey: string,\n site: string,\n debug: boolean,\n mode: 'additive' | 'full-replace' = 'additive'\n): Promise<{ success: boolean; created: number; updated: number }> {\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key configured')\n return { success: false, created: 0, updated: 0 }\n }\n\n if (entries.length === 0) {\n if (debug) console.log('[SitemapSync] No entries to sync')\n return { success: true, created: 0, updated: 0 }\n }\n\n try {\n // Registration is idempotent in both modes (same payload → same final\n // state), so retrying a timed-out attempt is safe.\n const response = await sonorFetch(`${apiUrl}/api/public/seo/register-sitemap`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n entries: entries.map(e => ({\n path: e.path,\n priority: e.priority,\n changefreq: e.changefreq,\n pageType: inferPageType(e.path),\n })),\n mode,\n // Sub-site host — tagged on every seo_pages row so the dashboard\n // can scope the page tree to one microsite. Resolved by\n // SiteKitClientProviders (see __SITE_KIT_SITE__).\n ...(site ? { site } : {}),\n }),\n }, { apiKey })\n\n if (!response.ok) {\n if (debug) console.error('[SitemapSync] API error:', response.status, response.statusText)\n return { success: false, created: 0, updated: 0 }\n }\n\n const result = await response.json()\n\n if (debug) {\n console.log(`[SitemapSync] Synced: ${result.created} created, ${result.updated} updated`)\n }\n\n return {\n success: true,\n created: result.created || 0,\n updated: result.updated || 0,\n }\n } catch (error) {\n if (debug) console.error('[SitemapSync] Sync error:', error)\n return { success: false, created: 0, updated: 0 }\n }\n}\n\nexport function SitemapSync({\n sitemapUrl = '/sitemap.xml',\n syncInterval = 60,\n debug = false,\n mode = 'additive',\n}: SitemapSyncProps) {\n const hasSyncedRef = useRef(false)\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)\n\n useEffect(() => {\n // Build-time sync via createSitemap is the canonical source of truth, but\n // it can fail during ISR revalidation (app/ dir unavailable on serverless).\n // Runtime SitemapSync in additive mode is a safe fallback — it adds/updates\n // pages that may be missing without ever deleting existing ones.\n // Full-replace is never safe at runtime — always force additive.\n const effectiveMode: 'additive' | 'full-replace' = 'additive'\n\n // Throttle window: reuse syncInterval when periodic syncing is on,\n // otherwise default to 60 minutes for the on-mount sync.\n const throttleMinutes = syncInterval > 0 ? syncInterval : 60\n\n const doSync = async () => {\n const { apiUrl, apiKey, site } = getApiConfig()\n\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key found')\n return\n }\n\n if (isRecentlySynced(throttleMinutes)) {\n if (debug) console.log('[SitemapSync] Skipped — synced within the last', throttleMinutes, 'min this session')\n return\n }\n\n if (debug) console.log('[SitemapSync] Starting sitemap sync...', site ? `(site: ${site})` : '')\n\n const entries = await parseSitemap(sitemapUrl, debug)\n\n if (entries.length > 0) {\n const hash = hashEntries(sitemapUrl, entries)\n if (isAlreadySyncedHash(hash)) {\n // This exact sitemap already synced from this browser — the server\n // state can't be improved by re-POSTing it. Stamp the session so we\n // don't even re-fetch/parse for the rest of the throttle window.\n stampSynced()\n if (debug) console.log('[SitemapSync] Skipped POST — sitemap unchanged since last successful sync')\n return\n }\n const result = await syncToPortal(entries, apiUrl, apiKey, site, debug, effectiveMode)\n if (result.success) {\n stampSynced()\n storeSyncedHash(hash)\n }\n }\n }\n\n if (!hasSyncedRef.current) {\n hasSyncedRef.current = true\n doSync()\n }\n\n if (syncInterval > 0) {\n intervalRef.current = setInterval(doSync, syncInterval * 60 * 1000)\n }\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [sitemapUrl, syncInterval, debug, mode])\n\n return null\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { useAnalytics } from './chunk-65SMJBHW.mjs';
2
+ import { useAnalytics } from './chunk-T2DEEKVQ.mjs';
3
3
  import { useCallback, useEffect } from 'react';
4
4
 
5
5
  function useContactTracking(options = {}) {
@@ -65,5 +65,5 @@ function ContactTracking({ debug = false }) {
65
65
  }
66
66
 
67
67
  export { ContactTracking, useContactTracking };
68
- //# sourceMappingURL=chunk-AN4ATCYQ.mjs.map
69
- //# sourceMappingURL=chunk-AN4ATCYQ.mjs.map
68
+ //# sourceMappingURL=chunk-45QHDA7Q.mjs.map
69
+ //# sourceMappingURL=chunk-45QHDA7Q.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/analytics/useContactTracking.ts"],"names":["trackConversion"],"mappings":"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","file":"chunk-AN4ATCYQ.mjs","sourcesContent":["/**\n * @sonordev/site-kit/analytics - Contact Tracking Hook\n * \n * Tracks phone calls and email clicks as conversions.\n * Use this hook to automatically track tel: and mailto: links,\n * or manually track contact interactions.\n */\n\n'use client'\n\nimport { useCallback, useEffect } from 'react'\nimport { useAnalytics } from './AnalyticsProvider'\n\nexport interface UseContactTrackingOptions {\n /** Automatically track all tel: and mailto: links (default: true) */\n autoTrack?: boolean\n /** Debug mode - logs events to console */\n debug?: boolean\n}\n\nexport interface ContactTrackingReturn {\n /** Manually track a phone call click */\n trackPhoneClick: (phoneNumber: string, metadata?: Record<string, unknown>) => void\n /** Manually track an email click */\n trackEmailClick: (email: string, metadata?: Record<string, unknown>) => void\n}\n\n/**\n * Hook for tracking phone and email contact interactions as conversions.\n * \n * @example\n * ```tsx\n * // Auto-track all tel: and mailto: links\n * useContactTracking()\n * \n * // Manual tracking\n * const { trackPhoneClick, trackEmailClick } = useContactTracking()\n * trackPhoneClick('513-555-1234')\n * trackEmailClick('hello@example.com')\n * ```\n */\nexport function useContactTracking(options: UseContactTrackingOptions = {}): ContactTrackingReturn {\n const { autoTrack = true, debug = false } = options\n const { trackConversion } = useAnalytics()\n \n const trackPhoneClick = useCallback((phoneNumber: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Phone click:', phoneNumber)\n \n trackConversion({\n type: 'phone_call',\n metadata: {\n phoneNumber: phoneNumber.replace(/\\D/g, ''), // Normalize to digits\n rawNumber: phoneNumber,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n const trackEmailClick = useCallback((email: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Email click:', email)\n \n trackConversion({\n type: 'email_click',\n metadata: {\n email,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n // Auto-track tel: and mailto: links\n useEffect(() => {\n if (!autoTrack || typeof document === 'undefined') return\n \n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n const anchor = target.closest('a')\n if (!anchor) return\n \n const href = anchor.getAttribute('href')\n if (!href) return\n \n if (href.startsWith('tel:')) {\n const phone = href.replace('tel:', '').trim()\n trackPhoneClick(phone, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n } else if (href.startsWith('mailto:')) {\n const email = href.replace('mailto:', '').split('?')[0].trim()\n trackEmailClick(email, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n }\n }\n \n document.addEventListener('click', handleClick, { capture: true })\n \n return () => {\n document.removeEventListener('click', handleClick, { capture: true })\n }\n }, [autoTrack, trackPhoneClick, trackEmailClick])\n \n return {\n trackPhoneClick,\n trackEmailClick,\n }\n}\n\n/**\n * Component wrapper for contact tracking\n * Simply include this component to auto-track all tel: and mailto: links\n * \n * @example\n * ```tsx\n * <ContactTracking />\n * ```\n */\nexport function ContactTracking({ debug = false }: { debug?: boolean }) {\n useContactTracking({ autoTrack: true, debug })\n return null\n}\n"]}
1
+ {"version":3,"sources":["../src/analytics/useContactTracking.ts"],"names":["trackConversion"],"mappings":"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","file":"chunk-45QHDA7Q.mjs","sourcesContent":["/**\n * @sonordev/site-kit/analytics - Contact Tracking Hook\n * \n * Tracks phone calls and email clicks as conversions.\n * Use this hook to automatically track tel: and mailto: links,\n * or manually track contact interactions.\n */\n\n'use client'\n\nimport { useCallback, useEffect } from 'react'\nimport { useAnalytics } from './AnalyticsProvider'\n\nexport interface UseContactTrackingOptions {\n /** Automatically track all tel: and mailto: links (default: true) */\n autoTrack?: boolean\n /** Debug mode - logs events to console */\n debug?: boolean\n}\n\nexport interface ContactTrackingReturn {\n /** Manually track a phone call click */\n trackPhoneClick: (phoneNumber: string, metadata?: Record<string, unknown>) => void\n /** Manually track an email click */\n trackEmailClick: (email: string, metadata?: Record<string, unknown>) => void\n}\n\n/**\n * Hook for tracking phone and email contact interactions as conversions.\n * \n * @example\n * ```tsx\n * // Auto-track all tel: and mailto: links\n * useContactTracking()\n * \n * // Manual tracking\n * const { trackPhoneClick, trackEmailClick } = useContactTracking()\n * trackPhoneClick('513-555-1234')\n * trackEmailClick('hello@example.com')\n * ```\n */\nexport function useContactTracking(options: UseContactTrackingOptions = {}): ContactTrackingReturn {\n const { autoTrack = true, debug = false } = options\n const { trackConversion } = useAnalytics()\n \n const trackPhoneClick = useCallback((phoneNumber: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Phone click:', phoneNumber)\n \n trackConversion({\n type: 'phone_call',\n metadata: {\n phoneNumber: phoneNumber.replace(/\\D/g, ''), // Normalize to digits\n rawNumber: phoneNumber,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n const trackEmailClick = useCallback((email: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Email click:', email)\n \n trackConversion({\n type: 'email_click',\n metadata: {\n email,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n // Auto-track tel: and mailto: links\n useEffect(() => {\n if (!autoTrack || typeof document === 'undefined') return\n \n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n const anchor = target.closest('a')\n if (!anchor) return\n \n const href = anchor.getAttribute('href')\n if (!href) return\n \n if (href.startsWith('tel:')) {\n const phone = href.replace('tel:', '').trim()\n trackPhoneClick(phone, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n } else if (href.startsWith('mailto:')) {\n const email = href.replace('mailto:', '').split('?')[0].trim()\n trackEmailClick(email, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n }\n }\n \n document.addEventListener('click', handleClick, { capture: true })\n \n return () => {\n document.removeEventListener('click', handleClick, { capture: true })\n }\n }, [autoTrack, trackPhoneClick, trackEmailClick])\n \n return {\n trackPhoneClick,\n trackEmailClick,\n }\n}\n\n/**\n * Component wrapper for contact tracking\n * Simply include this component to auto-track all tel: and mailto: links\n * \n * @example\n * ```tsx\n * <ContactTracking />\n * ```\n */\nexport function ContactTracking({ debug = false }: { debug?: boolean }) {\n useContactTracking({ autoTrack: true, debug })\n return null\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
+ var chunkEAASMIWX_js = require('./chunk-EAASMIWX.js');
4
5
  var react = require('react');
5
6
 
6
- // src/SitemapSync.tsx
7
7
  function inferPageType(urlPath) {
8
8
  if (urlPath === "/" || urlPath === "") return "homepage";
9
9
  if (/^\/services(\/|$)/i.test(urlPath)) return "service";
@@ -63,7 +63,7 @@ function getApiConfig() {
63
63
  }
64
64
  async function parseSitemap(sitemapUrl, debug) {
65
65
  try {
66
- const response = await fetch(sitemapUrl);
66
+ const response = await chunkEAASMIWX_js.sonorFetch(sitemapUrl);
67
67
  if (!response.ok) {
68
68
  if (debug) console.warn("[SitemapSync] Failed to fetch sitemap:", response.status);
69
69
  return [];
@@ -120,11 +120,10 @@ async function syncToPortal(entries, apiUrl, apiKey, site, debug, mode = "additi
120
120
  return { success: true, created: 0, updated: 0 };
121
121
  }
122
122
  try {
123
- const response = await fetch(`${apiUrl}/api/public/seo/register-sitemap`, {
123
+ const response = await chunkEAASMIWX_js.sonorFetch(`${apiUrl}/api/public/seo/register-sitemap`, {
124
124
  method: "POST",
125
125
  headers: {
126
- "Content-Type": "application/json",
127
- "x-api-key": apiKey
126
+ "Content-Type": "application/json"
128
127
  },
129
128
  body: JSON.stringify({
130
129
  entries: entries.map((e) => ({
@@ -139,7 +138,7 @@ async function syncToPortal(entries, apiUrl, apiKey, site, debug, mode = "additi
139
138
  // SiteKitClientProviders (see __SITE_KIT_SITE__).
140
139
  ...site ? { site } : {}
141
140
  })
142
- });
141
+ }, { apiKey });
143
142
  if (!response.ok) {
144
143
  if (debug) console.error("[SitemapSync] API error:", response.status, response.statusText);
145
144
  return { success: false, created: 0, updated: 0 };
@@ -212,5 +211,5 @@ function SitemapSync({
212
211
  }
213
212
 
214
213
  exports.SitemapSync = SitemapSync;
215
- //# sourceMappingURL=chunk-RI6JZUAE.js.map
216
- //# sourceMappingURL=chunk-RI6JZUAE.js.map
214
+ //# sourceMappingURL=chunk-4FBV5BJW.js.map
215
+ //# sourceMappingURL=chunk-4FBV5BJW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/SitemapSync.tsx"],"names":["sonorFetch","useRef","useEffect"],"mappings":"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","file":"chunk-4FBV5BJW.js","sourcesContent":["/**\n * SitemapSync - Automatically sync sitemap.xml to Portal API\n *\n * Client-only component. Lives at package root so the main entry does not\n * pull in seo/ (and server-only code). For use in SiteKitProvider and\n * from @sonordev/site-kit/seo.\n *\n * @example\n * ```tsx\n * import { SitemapSync } from '@sonordev/site-kit'\n * // or\n * import { SitemapSync } from '@sonordev/site-kit/seo'\n * ```\n */\n\n'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { sonorFetch } from './shared/sonorFetch'\n\ninterface SitemapSyncProps {\n /** Custom sitemap URL (defaults to /sitemap.xml) */\n sitemapUrl?: string\n /** How often to re-sync in minutes (0 = only on mount, default: 60) */\n syncInterval?: number\n /** Enable debug logging */\n debug?: boolean\n /**\n * Sync mode:\n * - 'additive' (default for runtime): adds/updates pages but never deletes existing ones\n * - 'full-replace': replaces the entire page set (use only for build-time sync via createSitemap)\n */\n mode?: 'additive' | 'full-replace'\n}\n\ninterface SitemapEntry {\n path: string\n lastmod?: string\n changefreq?: string\n priority?: number\n pageType?: string\n}\n\n/**\n * Infer page type from URL path pattern for Signal context.\n */\nfunction inferPageType(urlPath: string): string {\n if (urlPath === '/' || urlPath === '') return 'homepage'\n if (/^\\/services(\\/|$)/i.test(urlPath)) return 'service'\n if (/^\\/compare(\\/|$)/i.test(urlPath)) return 'comparison'\n if (/^\\/(insights|blog)(\\/|$)/i.test(urlPath)) return 'blog'\n if (/^\\/industries(\\/|$)/i.test(urlPath)) return 'industry'\n if (/^\\/work(\\/|$)/i.test(urlPath)) return 'portfolio'\n if (/^\\/faq(\\/|$)/i.test(urlPath)) return 'faq'\n if (/^\\/pricing(\\/|$)/i.test(urlPath)) return 'pricing'\n return 'page'\n}\n\n/**\n * Per-browser-session sync throttle. Build-time sync (createSitemap) is the\n * canonical source of truth; runtime SitemapSync is only a safety net — so\n * re-registering the sitemap on every full page load of every visitor is pure\n * waste (fetch + DOMParser on the visitor's main thread, plus a write per\n * pageview against the API). Stamp the last successful sync in sessionStorage\n * and skip while inside the throttle window.\n */\nconst SYNC_STAMP_KEY = '_sk_sitemap_synced_at'\nconst SYNC_HASH_KEY = '_sk_sitemap_hash'\n\nfunction isRecentlySynced(throttleMinutes: number): boolean {\n try {\n const stamp = sessionStorage.getItem(SYNC_STAMP_KEY)\n if (!stamp) return false\n const elapsed = Date.now() - parseInt(stamp, 10)\n return elapsed >= 0 && elapsed < throttleMinutes * 60 * 1000\n } catch {\n return false // storage unavailable (private mode) — sync as before\n }\n}\n\nfunction stampSynced(): void {\n try {\n sessionStorage.setItem(SYNC_STAMP_KEY, Date.now().toString())\n } catch {\n /* storage unavailable — throttle simply won't apply */\n }\n}\n\n/**\n * Content-hash guard (localStorage, so it survives across sessions): the\n * sitemap of a static site only changes at deploy, so once ONE sync of a given\n * sitemap succeeded from this browser, re-POSTing the identical entry set is\n * pure API load. Hash the parsed entries; skip the POST when unchanged.\n * Keyed by sitemap URL so multiple SitemapSync instances don't collide.\n */\nfunction hashEntries(sitemapUrl: string, entries: SitemapEntry[]): string {\n const text = entries\n .map(e => `${e.path}|${e.lastmod ?? ''}|${e.changefreq ?? ''}|${e.priority ?? ''}`)\n .join('\\n')\n let hash = 0\n for (let i = 0; i < text.length; i++) {\n hash = ((hash << 5) - hash + text.charCodeAt(i)) | 0\n }\n return `${sitemapUrl}:${entries.length}:${hash.toString(16)}`\n}\n\nfunction isAlreadySyncedHash(hash: string): boolean {\n try {\n return localStorage.getItem(SYNC_HASH_KEY) === hash\n } catch {\n return false\n }\n}\n\nfunction storeSyncedHash(hash: string): void {\n try {\n localStorage.setItem(SYNC_HASH_KEY, hash)\n } catch {\n /* storage unavailable — guard simply won't apply */\n }\n}\n\nfunction getApiConfig() {\n if (typeof window === 'undefined') return { apiUrl: '', apiKey: '', site: '' }\n\n const apiUrl = (window as any).__SITE_KIT_API_URL__ || 'https://api.sonor.io'\n const apiKey = (window as any).__SITE_KIT_API_KEY__ || ''\n // Sub-site host — set by SiteKitClientProviders from analytics.site config,\n // NEXT_PUBLIC_SITE_URL host, or window.location.host. Tagged on every\n // seo_pages row from this sitemap so the dashboard can scope the page tree\n // when one Sonor project hosts many sites.\n const site = (window as any).__SITE_KIT_SITE__ || window.location.host || ''\n return { apiUrl, apiKey, site }\n}\n\nasync function parseSitemap(sitemapUrl: string, debug: boolean): Promise<SitemapEntry[]> {\n try {\n const response = await sonorFetch(sitemapUrl)\n if (!response.ok) {\n if (debug) console.warn('[SitemapSync] Failed to fetch sitemap:', response.status)\n return []\n }\n\n const text = await response.text()\n const parser = new DOMParser()\n const doc = parser.parseFromString(text, 'application/xml')\n\n const parseError = doc.querySelector('parsererror')\n if (parseError) {\n if (debug) console.warn('[SitemapSync] Sitemap parse error:', parseError.textContent)\n return []\n }\n\n const urls = doc.querySelectorAll('url')\n const entries: SitemapEntry[] = []\n\n urls.forEach(url => {\n const loc = url.querySelector('loc')?.textContent?.trim()\n if (!loc) return\n\n let path: string\n try {\n const urlObj = new URL(loc)\n path = urlObj.pathname\n } catch {\n path = loc.startsWith('/') ? loc : `/${loc}`\n }\n\n if (path !== '/' && path.endsWith('/')) {\n path = path.slice(0, -1)\n }\n\n // Reject malformed paths (embedded domains, double protocols, etc.)\n if (path.includes('://') || /\\/\\/[a-z0-9.-]+\\.[a-z]{2,}/i.test(path)) {\n if (debug) console.warn(`[SitemapSync] Skipping malformed path: ${path}`)\n return\n }\n\n const lastmod = url.querySelector('lastmod')?.textContent || undefined\n const changefreq = url.querySelector('changefreq')?.textContent || undefined\n const priorityStr = url.querySelector('priority')?.textContent\n const priority = priorityStr ? parseFloat(priorityStr) : undefined\n\n entries.push({ path, lastmod, changefreq, priority })\n })\n\n if (debug) {\n console.log(`[SitemapSync] Parsed ${entries.length} entries from sitemap`)\n }\n\n return entries\n } catch (error) {\n if (debug) console.error('[SitemapSync] Error parsing sitemap:', error)\n return []\n }\n}\n\nasync function syncToPortal(\n entries: SitemapEntry[],\n apiUrl: string,\n apiKey: string,\n site: string,\n debug: boolean,\n mode: 'additive' | 'full-replace' = 'additive'\n): Promise<{ success: boolean; created: number; updated: number }> {\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key configured')\n return { success: false, created: 0, updated: 0 }\n }\n\n if (entries.length === 0) {\n if (debug) console.log('[SitemapSync] No entries to sync')\n return { success: true, created: 0, updated: 0 }\n }\n\n try {\n // Registration is idempotent in both modes (same payload → same final\n // state), so retrying a timed-out attempt is safe.\n const response = await sonorFetch(`${apiUrl}/api/public/seo/register-sitemap`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n entries: entries.map(e => ({\n path: e.path,\n priority: e.priority,\n changefreq: e.changefreq,\n pageType: inferPageType(e.path),\n })),\n mode,\n // Sub-site host — tagged on every seo_pages row so the dashboard\n // can scope the page tree to one microsite. Resolved by\n // SiteKitClientProviders (see __SITE_KIT_SITE__).\n ...(site ? { site } : {}),\n }),\n }, { apiKey })\n\n if (!response.ok) {\n if (debug) console.error('[SitemapSync] API error:', response.status, response.statusText)\n return { success: false, created: 0, updated: 0 }\n }\n\n const result = await response.json()\n\n if (debug) {\n console.log(`[SitemapSync] Synced: ${result.created} created, ${result.updated} updated`)\n }\n\n return {\n success: true,\n created: result.created || 0,\n updated: result.updated || 0,\n }\n } catch (error) {\n if (debug) console.error('[SitemapSync] Sync error:', error)\n return { success: false, created: 0, updated: 0 }\n }\n}\n\nexport function SitemapSync({\n sitemapUrl = '/sitemap.xml',\n syncInterval = 60,\n debug = false,\n mode = 'additive',\n}: SitemapSyncProps) {\n const hasSyncedRef = useRef(false)\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)\n\n useEffect(() => {\n // Build-time sync via createSitemap is the canonical source of truth, but\n // it can fail during ISR revalidation (app/ dir unavailable on serverless).\n // Runtime SitemapSync in additive mode is a safe fallback — it adds/updates\n // pages that may be missing without ever deleting existing ones.\n // Full-replace is never safe at runtime — always force additive.\n const effectiveMode: 'additive' | 'full-replace' = 'additive'\n\n // Throttle window: reuse syncInterval when periodic syncing is on,\n // otherwise default to 60 minutes for the on-mount sync.\n const throttleMinutes = syncInterval > 0 ? syncInterval : 60\n\n const doSync = async () => {\n const { apiUrl, apiKey, site } = getApiConfig()\n\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key found')\n return\n }\n\n if (isRecentlySynced(throttleMinutes)) {\n if (debug) console.log('[SitemapSync] Skipped — synced within the last', throttleMinutes, 'min this session')\n return\n }\n\n if (debug) console.log('[SitemapSync] Starting sitemap sync...', site ? `(site: ${site})` : '')\n\n const entries = await parseSitemap(sitemapUrl, debug)\n\n if (entries.length > 0) {\n const hash = hashEntries(sitemapUrl, entries)\n if (isAlreadySyncedHash(hash)) {\n // This exact sitemap already synced from this browser — the server\n // state can't be improved by re-POSTing it. Stamp the session so we\n // don't even re-fetch/parse for the rest of the throttle window.\n stampSynced()\n if (debug) console.log('[SitemapSync] Skipped POST — sitemap unchanged since last successful sync')\n return\n }\n const result = await syncToPortal(entries, apiUrl, apiKey, site, debug, effectiveMode)\n if (result.success) {\n stampSynced()\n storeSyncedHash(hash)\n }\n }\n }\n\n if (!hasSyncedRef.current) {\n hasSyncedRef.current = true\n doSync()\n }\n\n if (syncInterval > 0) {\n intervalRef.current = setInterval(doSync, syncInterval * 60 * 1000)\n }\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [sitemapUrl, syncInterval, debug, mode])\n\n return null\n}\n"]}
@@ -2,6 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  var chunk3BNFUMLL_js = require('./chunk-3BNFUMLL.js');
5
+ var chunkEAASMIWX_js = require('./chunk-EAASMIWX.js');
5
6
  var React = require('react');
6
7
  var ReactDOM = require('react-dom');
7
8
  var dynamic = require('next/dynamic');
@@ -274,7 +275,7 @@ function DesignRenderer({
274
275
  )) });
275
276
  }
276
277
  var LazyChatWidget = dynamic__default.default(
277
- () => import('./ChatWidget-MAL7FB4M.js').then((m) => ({ default: m.ChatWidget })),
278
+ () => import('./ChatWidget-AIOOZY6H.js').then((m) => ({ default: m.ChatWidget })),
278
279
  { ssr: false }
279
280
  );
280
281
  function getApiConfig() {
@@ -310,9 +311,10 @@ function EngageWidget({
310
311
  const visitorId = chunk3BNFUMLL_js.getOrCreateVisitorId();
311
312
  const url = typeof window !== "undefined" ? window.location.href : "";
312
313
  try {
313
- const response = await fetch(
314
+ const response = await chunkEAASMIWX_js.sonorFetch(
314
315
  `${apiUrl.replace(/\/$/, "")}/engage/widget/elements?url=${encodeURIComponent(url)}&visitorId=${encodeURIComponent(visitorId)}`,
315
- { headers: { "x-api-key": apiKey } }
316
+ {},
317
+ { apiKey }
316
318
  );
317
319
  if (!response.ok) {
318
320
  if (debug) console.error("[Engage] Error loading elements:", response.statusText);
@@ -441,8 +443,8 @@ function EngageWidget({
441
443
  projectId: propProjectId ?? void 0,
442
444
  config: {
443
445
  position,
444
- buttonColor: "#3b82f6"
445
- // Default blue, overridden by --sk-primary CSS var or API brand_primary
446
+ buttonColor: "#2563eb"
447
+ // Default blue-600 (AA on white), overridden by --sk-primary CSS var or API brand_primary
446
448
  }
447
449
  }
448
450
  )
@@ -453,12 +455,12 @@ function EngageWidget({
453
455
  function trackEngageEvent(apiUrl, apiKey, endpoint, data) {
454
456
  if (!apiKey) return;
455
457
  const visitorId = typeof localStorage !== "undefined" ? localStorage.getItem("_sk_vid") : null;
456
- fetch(`${apiUrl.replace(/\/$/, "")}/engage/widget/${endpoint}`, {
458
+ chunkEAASMIWX_js.sonorFetch(`${apiUrl.replace(/\/$/, "")}/engage/widget/${endpoint}`, {
457
459
  method: "POST",
458
- headers: { "Content-Type": "application/json", "x-api-key": apiKey },
460
+ headers: { "Content-Type": "application/json" },
459
461
  body: JSON.stringify({ ...data, visitorId, pageUrl: window.location.href }),
460
462
  keepalive: true
461
- }).catch(() => {
463
+ }, { apiKey, retries: 0 }).catch(() => {
462
464
  });
463
465
  }
464
466
  function handleEngageAction(action, _node, element, apiUrl, apiKey) {
@@ -677,7 +679,7 @@ function EngageElementRenderer({
677
679
  top: 0,
678
680
  left: 0,
679
681
  right: 0,
680
- backgroundColor: element.config?.backgroundColor || "var(--sk-primary, #3b82f6)",
682
+ backgroundColor: element.config?.backgroundColor || "var(--sk-primary, #2563eb)",
681
683
  color: element.config?.textColor || "var(--sk-bg, #ffffff)",
682
684
  padding: "12px 24px",
683
685
  display: "flex",
@@ -724,5 +726,5 @@ function getDeviceType() {
724
726
 
725
727
  exports.DesignRenderer = DesignRenderer;
726
728
  exports.EngageWidget = EngageWidget;
727
- //# sourceMappingURL=chunk-YJWKHCOB.js.map
728
- //# sourceMappingURL=chunk-YJWKHCOB.js.map
729
+ //# sourceMappingURL=chunk-4NTMIU6V.js.map
730
+ //# sourceMappingURL=chunk-4NTMIU6V.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/engage/DesignRenderer.tsx","../src/engage/EngageWidget.tsx"],"names":["useState","jsx","createElement","jsxs","React","dynamic","usePathname","useEffect","getOrCreateVisitorId","sonorFetch","useCallback","ReactDOM","Fragment","useRef"],"mappings":";;;;;;;;;;;;;;;;AA0EA,SAAS,YAAA,CACP,MAAA,EACA,IAAA,EACA,OAAA,EACA,QAAA,EACM;AACN,EAAA,IAAI,CAAC,MAAA,EAAQ,MAAA,IAAU,MAAA,CAAO,WAAW,MAAA,EAAQ;AAGjD,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,QAAA,CAAS,QAAQ,IAAI,CAAA;AAAA,EACvB;AAEA,EAAA,QAAQ,OAAO,MAAA;AAAQ,IACrB,KAAK,MAAA;AACH,MAAA,IAAI,OAAO,GAAA,EAAK;AACd,QAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,UAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,GAAA,EAAK,QAAA,EAAU,qBAAqB,CAAA;AAAA,QACzD,CAAA,MAAO;AACL,UAAA,MAAA,CAAO,QAAA,CAAS,OAAO,MAAA,CAAO,GAAA;AAAA,QAChC;AAAA,MACF;AACA,MAAA;AAAA,IAEF,KAAK,QAAA;AACH,MAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,QAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,MAAA,CAAO,MAAM,CAAA;AACpD,QAAA,OAAA,EAAS,cAAA,CAAe,EAAE,QAAA,EAAU,QAAA,EAAU,CAAA;AAAA,MAChD;AACA,MAAA;AAAA,IAEF,KAAK,OAAA;AACH,MAAA,OAAA,IAAU;AACV,MAAA;AAAA,IAEF,KAAK,MAAA;AACH,MAAA,IAAI,OAAO,IAAA,EAAM;AACf,QAAA,SAAA,CAAU,UAAU,SAAA,CAAU,MAAA,CAAO,IAAI,CAAA,CAAE,KAAA,CAAM,QAAQ,KAAK,CAAA;AAAA,MAChE;AACA,MAAA;AAAA,IAEF,KAAK,OAAA;AACH,MAAA,IAAI,UAAU,KAAA,EAAO;AACnB,QAAA,SAAA,CAAU,KAAA,CAAM;AAAA,UACd,OAAO,QAAA,CAAS,KAAA;AAAA,UAChB,GAAA,EAAK,OAAO,QAAA,CAAS;AAAA,SACtB,CAAA,CAAE,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA;AAAA,MACxB;AACA,MAAA;AAAA,IAEF,KAAK,UAAA;AACH,MAAA,IAAI,OAAO,GAAA,EAAK;AACd,QAAA,MAAM,CAAA,GAAI,QAAA,CAAS,aAAA,CAAc,GAAG,CAAA;AACpC,QAAA,CAAA,CAAE,OAAO,MAAA,CAAO,GAAA;AAChB,QAAA,CAAA,CAAE,QAAA,GAAW,EAAA;AACb,QAAA,CAAA,CAAE,KAAA,EAAM;AAAA,MACV;AACA,MAAA;AASA;AAEN;AAMA,IAAM,kBAAA,GAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAW3B,SAAS,iBAAA,CAAkB,SAAA,EAAoB,KAAA,EAAgB,QAAA,EAAkC;AAC/F,EAAA,IAAI,CAAC,SAAA,IAAa,SAAA,KAAc,MAAA,SAAe,EAAC;AAEhD,EAAA,MAAM,YAAA,GAAuC;AAAA,IAC3C,MAAA,EAAQ,cAAA;AAAA,IACR,QAAA,EAAU,gBAAA;AAAA,IACV,UAAA,EAAY,kBAAA;AAAA,IACZ,WAAA,EAAa,mBAAA;AAAA,IACb,YAAA,EAAc,oBAAA;AAAA,IACd,SAAA,EAAW,iBAAA;AAAA,IACX,OAAA,EAAS,eAAA;AAAA,IACT,QAAA,EAAU;AAAA,GACZ;AAEA,EAAA,MAAM,aAAA,GAAgB,aAAa,SAAS,CAAA;AAC5C,EAAA,IAAI,CAAC,aAAA,EAAe,OAAO,EAAC;AAE5B,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,GAAG,aAAa,CAAA,CAAA,EAAI,YAAY,GAAG,CAAA,YAAA,EAAe,SAAS,CAAC,CAAA,WAAA,CAAA;AAAA,IACvE,OAAA,EAAS;AAAA;AAAA,GACX;AACF;AAaA,SAAS,aAAa,EAAE,IAAA,EAAM,OAAA,EAAS,QAAA,EAAU,SAAQ,EAAiD;AACxG,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,eAAS,KAAK,CAAA;AAChD,EAAA,MAAM,EAAE,MAAM,KAAA,GAAQ,IAAI,KAAA,GAAQ,EAAC,EAAG,QAAA,EAAS,GAAI,IAAA;AAGnD,EAAA,MAAM,aAAA,GAA+B,EAAE,GAAG,KAAA,EAAM;AAGhD,EAAA,IAAI,MAAM,SAAA,EAAW;AACnB,IAAA,MAAA,CAAO,OAAO,aAAA,EAAe,iBAAA;AAAA,MAC3B,KAAA,CAAM,SAAA;AAAA,MACN,KAAA,CAAM,cAAA;AAAA,MACN,KAAA,CAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,IAAI,KAAA,CAAM,UAAA,IAAc,KAAA,CAAM,UAAA,KAAe,MAAA,EAAQ;AACnD,MAAA,aAAA,CAAc,SAAA,GAAY,CAAA,MAAA,EAAS,KAAA,CAAM,UAAU,CAAA,CAAA,CAAA;AACnD,MAAA,aAAA,CAAc,UAAA,GAAa,qBAAA;AAAA,IAC7B;AACA,IAAA,IAAI,KAAA,CAAM,WAAA,IAAe,KAAA,CAAM,WAAA,KAAgB,MAAA,EAAQ;AACrD,MAAA,MAAM,SAAA,GAAoC;AAAA,QACxC,EAAA,EAAI,+BAAA;AAAA,QACJ,EAAA,EAAI,iCAAA;AAAA,QACJ,EAAA,EAAI;AAAA,OACN;AACA,MAAA,aAAA,CAAc,SAAA,GAAY,SAAA,CAAU,KAAA,CAAM,WAAW,CAAA;AAAA,IACvD;AAAA,EACF;AAGA,EAAA,MAAM,aAAA,GAAyD;AAAA,IAC7D,YAAA,EAAc,MAAM,YAAA,CAAa,IAAI,CAAA;AAAA,IACrC,YAAA,EAAc,MAAM,YAAA,CAAa,KAAK;AAAA,GACxC;AAGA,EAAA,IAAI,MAAM,OAAA,EAAS;AACjB,IAAA,aAAA,CAAc,OAAA,GAAU,CAAC,CAAA,KAAkB;AACzC,MAAA,CAAA,CAAE,cAAA,EAAe;AACjB,MAAA,YAAA,CAAa,KAAA,CAAM,OAAA,EAAS,IAAA,EAAM,OAAA,EAAS,QAAQ,CAAA;AAAA,IACrD,CAAA;AACA,IAAA,aAAA,CAAc,MAAA,GAAS,SAAA;AAAA,EACzB;AAGA,EAAA,MAAM,gBAAA,GAAmB,QAAA,EAAU,GAAA,CAAI,CAAC,KAAA,qBACtCC,cAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MAEC,IAAA,EAAM,KAAA;AAAA,MACN,OAAA;AAAA,MACA,QAAA;AAAA,MACA;AAAA,KAAA;AAAA,IAJK,KAAA,CAAM;AAAA,GAMd,CAAA;AAGD,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,WAAA;AAAA,IACL,KAAK,KAAA;AAAA,IACL,KAAK,SAAA;AACH,MAAA,sCACG,KAAA,EAAA,EAAI,KAAA,EAAO,aAAA,EAAgB,GAAG,eAC5B,QAAA,EAAA,gBAAA,EACH,CAAA;AAAA,IAGJ,KAAK,MAAA;AACH,MAAA,uBACEA,cAAA,CAAC,GAAA,EAAA,EAAE,KAAA,EAAO,aAAA,EAAgB,GAAG,eAC1B,QAAA,EAAA,WAAA,CAAY,KAAA,CAAM,IAAA,EAAM,OAAO,CAAA,EAClC,CAAA;AAAA,IAGJ,KAAK,SAAA;AACH,MAAA,MAAM,UAAA,GAAa,CAAA,CAAA,EAAI,KAAA,CAAM,KAAA,IAAS,CAAC,CAAA,CAAA;AACvC,MAAA,OAAOC,mBAAA;AAAA,QACL,UAAA;AAAA,QACA,EAAE,KAAA,EAAO,aAAA,EAAe,GAAG,aAAA,EAAc;AAAA,QACzC,WAAA,CAAY,KAAA,CAAM,IAAA,EAAM,OAAO;AAAA,OACjC;AAAA,IAEF,KAAK,QAAA;AAAA,IACL,KAAK,eAAA;AAAA,IACL,KAAK,QAAA;AAAA,IACL,KAAK,WAAA;AAAA,IACL,KAAK,WAAA;AACH,MAAA,uBACED,cAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,aAAA;AAAA,UACN,GAAG,aAAA;AAAA,UACJ,IAAA,EAAK,QAAA;AAAA,UAEJ,sBAAY,KAAA,CAAM,IAAA,IAAQ,KAAA,CAAM,KAAA,EAAO,OAAO,CAAA,IAAK;AAAA;AAAA,OACtD;AAAA,IAGJ,KAAK,OAAA;AACH,MAAA,uBACEA,cAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,KAAK,KAAA,CAAM,GAAA;AAAA,UACX,GAAA,EAAK,MAAM,GAAA,IAAO,EAAA;AAAA,UAClB,KAAA,EAAO,aAAA;AAAA,UACN,GAAG;AAAA;AAAA,OACN;AAAA,IAGJ,KAAK,MAAA;AACH,MAAA,uBACEA,cAAA;AAAA,QAAC,GAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAM,MAAM,IAAA,IAAQ,GAAA;AAAA,UACpB,MAAA,EAAQ,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,MAAA;AAAA,UAClC,GAAA,EAAK,KAAA,CAAM,MAAA,GAAS,qBAAA,GAAwB,MAAA;AAAA,UAC5C,KAAA,EAAO,aAAA;AAAA,UACN,GAAG,aAAA;AAAA,UAEH,QAAA,EAAA,WAAA,CAAY,KAAA,CAAM,IAAA,EAAM,OAAO,CAAA,IAAK;AAAA;AAAA,OACvC;AAAA,IAGJ,KAAK,OAAA;AACH,MAAA,uBACEA,cAAA;AAAA,QAAC,OAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAM,MAAM,SAAA,IAAa,MAAA;AAAA,UACzB,aAAa,KAAA,CAAM,WAAA;AAAA,UACnB,KAAA,EAAO,aAAA;AAAA,UACN,GAAG;AAAA;AAAA,OACN;AAAA,IAGJ,KAAK,SAAA;AACH,MAAA,uBAAOA,cAAA,CAAC,IAAA,EAAA,EAAG,KAAA,EAAO,EAAE,MAAA,EAAQ,QAAQ,SAAA,EAAW,qCAAA,EAAuC,GAAG,aAAA,EAAc,EAAG,CAAA;AAAA,IAE5G,KAAK,QAAA;AACH,MAAA,uBAAOA,cAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,GAAG,aAAA,EAAe,KAAA,EAAO,KAAA,CAAM,KAAA,EAAO,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAO,EAAG,CAAA;AAAA,IAErF,KAAK,MAAA;AAEH,MAAA,uBACEA,cAAA,CAAC,UAAK,KAAA,EAAO,aAAA,EAAgB,GAAG,aAAA,EAC7B,QAAA,EAAA,KAAA,CAAM,QAAQ,QAAA,EACjB,CAAA;AAAA,IAGJ,KAAK,WAAA;AAGH,MAAA,uBACEA,cAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,aAAA;AAAA,UACP,oBAAkB,KAAA,CAAM,OAAA;AAAA,UACvB,GAAG,aAAA;AAAA,UAGJ,QAAA,kBAAAE,eAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,UAAA,EAAY,gCAAA,EAAkC,YAAA,EAAc,KAAA,EAAO,SAAA,EAAW,QAAA,EAAS,EAAG,QAAA,EAAA;AAAA,YAAA,QAAA;AAAA,YAChH,MAAM,OAAA,IAAW;AAAA,WAAA,EAC1B;AAAA;AAAA,OACF;AAAA,IAGJ,KAAK,aAAA;AAAA,IACL,KAAK,WAAA;AAEH,MAAA,uBACEF,cAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,aAAA;AAAA,UACP,wBAAsB,KAAA,CAAM,WAAA;AAAA,UAC3B,GAAG,aAAA;AAAA,UAEH,QAAA,EAAA;AAAA;AAAA,OACH;AAAA,IAGJ;AAEE,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,oCAAA,EAAuC,IAAI,CAAA,CAAE,CAAA;AAC1D,MAAA,sCACG,KAAA,EAAA,EAAI,KAAA,EAAO,aAAA,EAAgB,GAAG,eAC5B,QAAA,EAAA,gBAAA,EACH,CAAA;AAAA;AAGR;AAMA,SAAS,WAAA,CAAY,MAA0B,OAAA,EAAiC;AAC9E,EAAA,IAAI,CAAC,MAAM,OAAO,EAAA;AAClB,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAGrB,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,0BAAA,EAA4B,CAAC,OAAO,IAAA,KAAS;AAC/D,IAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,OAAA,EAAS,IAAI,CAAA;AAC1C,IAAA,OAAO,KAAA,KAAU,MAAA,GAAY,MAAA,CAAO,KAAK,CAAA,GAAI,KAAA;AAAA,EAC/C,CAAC,CAAA;AACH;AAEA,SAAS,cAAA,CAAe,KAA0B,IAAA,EAAmB;AACnE,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,CAAE,MAAA,CAAO,CAAC,GAAA,EAAK,GAAA,KAAQ,GAAA,GAAM,GAAG,CAAA,EAAG,GAAG,CAAA;AAC7D;AAMO,SAAS,cAAA,CAAe;AAAA,EAC7B,MAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAA4C;AAE1C,EAAAG,sBAAA,CAAM,UAAU,MAAM;AACpB,IAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AAErC,IAAA,MAAM,OAAA,GAAU,mCAAA;AAChB,IAAA,IAAI,CAAC,QAAA,CAAS,cAAA,CAAe,OAAO,CAAA,EAAG;AACrC,MAAA,MAAM,UAAA,GAAa,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AACjD,MAAA,UAAA,CAAW,EAAA,GAAK,OAAA;AAChB,MAAA,UAAA,CAAW,WAAA,GAAc,kBAAA;AACzB,MAAA,QAAA,CAAS,IAAA,CAAK,YAAY,UAAU,CAAA;AAAA,IACtC;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,MAAM,SAAA,GAA2B;AAAA,IAC/B,GAAG,MAAA,CAAO;AAAA,GACZ;AAEA,EAAA,uBACEH,cAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,SAAA,EAAW,oBAAA,EAAoB,MAAA,CAAO,EAAA,EAC/C,QAAA,EAAA,MAAA,CAAO,QAAA,EAAU,GAAA,CAAI,CAAC,IAAA,qBACrBA,cAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MAEC,IAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA;AAAA,MACA;AAAA,KAAA;AAAA,IAJK,IAAA,CAAK;AAAA,GAMb,CAAA,EACH,CAAA;AAEJ;AClaA,IAAM,cAAA,GAAiBI,wBAAA;AAAA,EACrB,MAAM,OAAO,0BAAc,CAAA,CAAE,IAAA,CAAK,QAAM,EAAE,OAAA,EAAS,CAAA,CAAE,UAAA,EAAW,CAAE,CAAA;AAAA,EAClE,EAAE,KAAK,KAAA;AACT,CAAA;AAYA,SAAS,YAAA,GAAe;AACtB,EAAA,MAAM,QAAQ,OAAO,OAAA,KAAY,WAAA,IAAe,OAAA,CAAQ,KAAK,QAAA,KAAa,aAAA;AAC1E,EAAA,MAAM,gBAAgB,KAAA,IAAS,OAAA,CAAQ,KAAK,aAAA,GACxC,OAAA,CAAQ,IAAI,aAAA,GACZ,sBAAA;AACJ,EAAA,MAAM,SAAS,OAAO,MAAA,KAAW,WAAA,GAC5B,MAAA,CAAe,wBAAwB,aAAA,GACxC,aAAA;AACJ,EAAA,MAAM,MAAA,GAAS,OAAO,MAAA,KAAW,WAAA,GAAe,OAAe,oBAAA,GAAuB,MAAA;AACtF,EAAA,OAAO,EAAE,QAAQ,MAAA,EAAO;AAC1B;AAEO,SAAS,YAAA,CAAa;AAAA,EAC3B,MAAA,EAAQ,UAAA;AAAA,EACR,MAAA,EAAQ,UAAA;AAAA,EACR,SAAA,EAAW,aAAA;AAAA,EACX,QAAA,GAAW,cAAA;AAAA,EACX,MAAA,GAAS,IAAA;AAAA,EACT,WAAA,GAAc,IAAA;AAAA,EACd,KAAA,GAAQ;AACV,CAAA,EAAsB;AACpB,EAAA,MAAM,WAAWC,sBAAA,EAAY;AAC7B,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIN,cAAAA,CAA0B,EAAE,CAAA;AAC5D,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAIA,cAAAA,CAAmB,EAAE,CAAA;AACjE,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,IAAIA,cAAAA,iBAAsB,IAAI,KAAK,CAAA;AACjF,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,eAAS,KAAK,CAAA;AAGhD,EAAAO,eAAA,CAAU,MAAM;AACd,IAAA,eAAe,YAAA,GAAe;AAC5B,MAAA,MAAM,EAAE,MAAA,EAAQ,YAAA,EAAc,MAAA,EAAQ,YAAA,KAAiB,YAAA,EAAa;AACpE,MAAA,MAAM,SAAS,UAAA,IAAc,YAAA;AAC7B,MAAA,MAAM,SAAS,UAAA,IAAc,YAAA;AAE7B,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,gCAAgC,CAAA;AACxD,QAAA;AAAA,MACF;AAGA,MAAA,MAAM,YAAYC,qCAAA,EAAqB;AACvC,MAAA,MAAM,MAAM,OAAO,MAAA,KAAW,WAAA,GAAc,MAAA,CAAO,SAAS,IAAA,GAAO,EAAA;AAEnE,MAAA,IAAI;AACF,QAAA,MAAM,WAAW,MAAMC,2BAAA;AAAA,UACrB,CAAA,EAAG,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,4BAAA,EAA+B,kBAAA,CAAmB,GAAG,CAAC,CAAA,WAAA,EAAc,kBAAA,CAAmB,SAAS,CAAC,CAAA,CAAA;AAAA,UAC7H,EAAC;AAAA,UACD,EAAE,MAAA;AAAO,SACX;AAEA,QAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,UAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,KAAA,CAAM,kCAAA,EAAoC,SAAS,UAAU,CAAA;AAChF,UAAA;AAAA,QACF;AAEA,QAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,QAAA,MAAM,eAAe,IAAA,CAAK,IAAA,EAAM,QAAA,IAAY,IAAA,CAAK,YAAY,EAAC;AAC9D,QAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,2BAAA,EAA6B,YAAY,CAAA;AAChE,QAAA,WAAA,CAAY,YAAY,CAAA;AAAA,MAC1B,SAAS,KAAA,EAAO;AACd,QAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,KAAA,CAAM,kCAAA,EAAoC,KAAK,CAAA;AAAA,MACpE;AAAA,IACF;AAEA,IAAA,YAAA,EAAa;AAAA,EACf,CAAA,EAAG,CAAC,UAAA,EAAY,UAAA,EAAY,KAAK,CAAC,CAAA;AAGlC,EAAAF,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,WAAA,EAAa;AAClB,IAAA,MAAM,KACJ,OAAO,mBAAA,KAAwB,cAC3B,mBAAA,CAAoB,MAAM,aAAa,IAAI,CAAA,EAAG,EAAE,OAAA,EAAS,GAAA,EAAM,CAAA,GAC/D,UAAA,CAAW,MAAM,YAAA,CAAa,IAAI,GAAG,CAAC,CAAA;AAC5C,IAAA,OAAO,MAAM;AACX,MAAA,OAAO,uBAAuB,WAAA,GAAc,kBAAA,CAAmB,EAAY,CAAA,GAAI,aAAa,EAAE,CAAA;AAAA,IAChG,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAGhB,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,SAAS,MAAA,EAAQ;AAEtB,IAAA,MAAM,YAAA,GAAe,CAAC,OAAA,KAAoC;AAExD,MAAA,IAAI,iBAAA,CAAkB,GAAA,CAAI,OAAA,CAAQ,EAAE,GAAG,OAAO,KAAA;AAG9C,MAAA,IAAI,OAAA,CAAQ,WAAW,KAAA,EAAO;AAC5B,QAAA,MAAM,EAAE,OAAA,EAAS,OAAA,EAAQ,GAAI,QAAQ,SAAA,CAAU,KAAA;AAE/C,QAAA,IAAI,OAAA,EAAS,KAAK,CAAA,CAAA,KAAK,SAAA,CAAU,UAAU,CAAC,CAAC,GAAG,OAAO,KAAA;AACvD,QAAA,IAAI,OAAA,IAAW,CAAC,OAAA,CAAQ,IAAA,CAAK,CAAA,CAAA,KAAK,UAAU,QAAA,EAAU,CAAC,CAAC,CAAA,EAAG,OAAO,KAAA;AAAA,MACpE;AAGA,MAAA,IAAI,OAAA,CAAQ,WAAW,OAAA,EAAS;AAC9B,QAAA,MAAM,SAAS,aAAA,EAAc;AAC7B,QAAA,IAAI,CAAC,OAAA,CAAQ,SAAA,CAAU,QAAQ,QAAA,CAAS,MAAM,GAAG,OAAO,KAAA;AAAA,MAC1D;AAGA,MAAA,IAAI,OAAA,CAAQ,SAAS,SAAA,EAAW;AAC9B,QAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,QAAQ,OAAA,CAAQ,SAAA;AACvC,QAAA,MAAM,GAAA,GAAM,CAAA,QAAA,EAAW,OAAA,CAAQ,EAAE,CAAA,CAAA;AAEjC,QAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,UAAA,IAAI,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA,EAAG,OAAO,KAAA;AAAA,QACxC,CAAA,MAAA,IAAW,SAAS,kBAAA,EAAoB;AACtC,UAAA,IAAI,cAAA,CAAe,OAAA,CAAQ,GAAG,CAAA,EAAG,OAAO,KAAA;AAAA,QAC1C,CAAA,MAAA,IAAW,IAAA,KAAS,cAAA,IAAkB,IAAA,EAAM;AAC1C,UAAA,MAAM,SAAA,GAAY,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AAC1C,UAAA,IAAI,SAAA,EAAW;AACb,YAAA,MAAM,UAAU,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,CAAS,WAAW,EAAE,CAAA;AACnD,YAAA,IAAI,UAAU,IAAA,GAAO,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,KAAM,OAAO,KAAA;AAAA,UACnD;AAAA,QACF;AAAA,MACF;AAEA,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAGA,IAAA,MAAM,QAAA,GAAW,QAAA,CAAS,MAAA,CAAO,YAAY,CAAA;AAE7C,IAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,6BAAA,EAA+B,QAAQ,CAAA;AAK9D,IAAA,MAAM,QAAA,GAAW,CAAC,EAAA,KAAe;AAC/B,MAAA,iBAAA,CAAkB,CAAA,IAAA,KAAS,IAAA,CAAK,QAAA,CAAS,EAAE,CAAA,GAAI,OAAO,CAAC,GAAG,IAAA,EAAM,EAAE,CAAE,CAAA;AAAA,IACtE,CAAA;AAKA,IAAA,MAAM,WAA8B,EAAC;AAErC,IAAA,QAAA,CAAS,QAAQ,CAAA,OAAA,KAAW;AAC1B,MAAA,MAAM,UAAU,OAAA,CAAQ,OAAA;AAExB,MAAA,IAAI,OAAA,EAAS,IAAA,KAAS,WAAA,IAAe,CAAC,SAAS,IAAA,EAAM;AACnD,QAAA,QAAA,CAAS,QAAQ,EAAE,CAAA;AAAA,MACrB,CAAA,MAAA,IAAW,OAAA,EAAS,IAAA,KAAS,OAAA,IAAW,QAAQ,KAAA,EAAO;AACrD,QAAA,MAAM,KAAA,GAAQ,WAAW,MAAM,QAAA,CAAS,QAAQ,EAAE,CAAA,EAAG,OAAA,CAAQ,KAAA,GAAQ,GAAI,CAAA;AACzE,QAAA,QAAA,CAAS,IAAA,CAAK,MAAM,YAAA,CAAa,KAAK,CAAC,CAAA;AAAA,MACzC,CAAA,MAAA,IAAW,OAAA,EAAS,IAAA,KAAS,aAAA,EAAe;AAC1C,QAAA,MAAM,gBAAA,GAAmB,CAAC,CAAA,KAAkB;AAC1C,UAAA,IAAI,CAAA,CAAE,UAAU,EAAA,EAAI;AAClB,YAAA,QAAA,CAAS,QAAQ,EAAE,CAAA;AACnB,YAAA,QAAA,CAAS,mBAAA,CAAoB,cAAc,gBAAgB,CAAA;AAAA,UAC7D;AAAA,QACF,CAAA;AACA,QAAA,QAAA,CAAS,gBAAA,CAAiB,cAAc,gBAAgB,CAAA;AACxD,QAAA,QAAA,CAAS,KAAK,MAAM,QAAA,CAAS,mBAAA,CAAoB,YAAA,EAAc,gBAAgB,CAAC,CAAA;AAAA,MAClF,CAAA,MAAA,IAAW,OAAA,EAAS,IAAA,KAAS,QAAA,IAAY,QAAQ,gBAAA,EAAkB;AACjE,QAAA,MAAM,eAAe,MAAM;AACzB,UAAA,MAAM,gBAAiB,MAAA,CAAO,OAAA,IAAW,SAAS,IAAA,CAAK,YAAA,GAAe,OAAO,WAAA,CAAA,GAAgB,GAAA;AAC7F,UAAA,IAAI,aAAA,KAAkB,OAAA,CAAQ,gBAAA,IAAoB,EAAA,CAAA,EAAK;AACrD,YAAA,QAAA,CAAS,QAAQ,EAAE,CAAA;AACnB,YAAA,MAAA,CAAO,mBAAA,CAAoB,UAAU,YAAY,CAAA;AAAA,UACnD;AAAA,QACF,CAAA;AACA,QAAA,MAAA,CAAO,iBAAiB,QAAA,EAAU,YAAA,EAAc,EAAE,OAAA,EAAS,MAAM,CAAA;AACjE,QAAA,QAAA,CAAS,KAAK,MAAM,MAAA,CAAO,mBAAA,CAAoB,QAAA,EAAU,YAAY,CAAC,CAAA;AAAA,MACxE;AAAA,IACF,CAAC,CAAA;AAED,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,OAAA,CAAQ,CAAA,EAAA,KAAM,EAAA,EAAI,CAAA;AAAA,IAC7B,CAAA;AAAA,EACF,GAAG,CAAC,QAAA,EAAU,QAAA,EAAU,iBAAA,EAAmB,KAAK,CAAC,CAAA;AAEjD,EAAA,MAAM,aAAA,GAAgBG,iBAAA,CAAY,CAAC,SAAA,KAAsB;AACvD,IAAA,oBAAA,CAAqB,CAAA,IAAA,yBAAY,GAAA,CAAI,CAAC,GAAG,IAAA,EAAM,SAAS,CAAC,CAAC,CAAA;AAC1D,IAAA,iBAAA,CAAkB,UAAQ,IAAA,CAAK,MAAA,CAAO,CAAA,EAAA,KAAM,EAAA,KAAO,SAAS,CAAC,CAAA;AAG7D,IAAA,MAAM,UAAU,QAAA,CAAS,IAAA,CAAK,CAAA,CAAA,KAAK,CAAA,CAAE,OAAO,SAAS,CAAA;AACrD,IAAA,IAAI,OAAA,EAAS,SAAS,SAAA,EAAW;AAC/B,MAAA,MAAM,GAAA,GAAM,WAAW,SAAS,CAAA,CAAA;AAChC,MAAA,IAAI,OAAA,CAAQ,OAAA,CAAQ,SAAA,CAAU,IAAA,KAAS,kBAAA,EAAoB;AACzD,QAAA,cAAA,CAAe,OAAA,CAAQ,KAAK,MAAM,CAAA;AAAA,MACpC,CAAA,MAAO;AACL,QAAA,YAAA,CAAa,QAAQ,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI,CAAE,UAAU,CAAA;AAAA,MACjD;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAKb,EAAA,IAAI,OAAO,QAAA,KAAa,WAAA,EAAa,OAAO,IAAA;AAE5C,EAAA,OAAOC,yBAAA,CAAS,YAAA;AAAA,oBACdR,gBAAAS,mBAAA,EAAA,EACG,QAAA,EAAA;AAAA,MAAA,cAAA,CAAe,IAAI,CAAA,SAAA,KAAa;AAC/B,QAAA,MAAM,UAAU,QAAA,CAAS,IAAA,CAAK,CAAA,CAAA,KAAK,CAAA,CAAE,OAAO,SAAS,CAAA;AACrD,QAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,QAAA,MAAM,EAAE,MAAA,EAAQ,YAAA,EAAc,MAAA,EAAQ,YAAA,KAAiB,YAAA,EAAa;AACpE,QAAA,uBACEX,cAAAA;AAAA,UAAC,qBAAA;AAAA,UAAA;AAAA,YAEC,OAAA;AAAA,YACA,SAAA,EAAW,MAAM,aAAA,CAAc,OAAA,CAAQ,EAAE,CAAA;AAAA,YACzC,MAAA;AAAA,YACA,QAAQ,UAAA,IAAc,YAAA;AAAA,YACtB,QAAQ,UAAA,IAAc;AAAA,WAAA;AAAA,UALjB,OAAA,CAAQ;AAAA,SAMf;AAAA,MAEJ,CAAC,CAAA;AAAA,MAGA,WAAA,IAAe,6BACdA,cAAAA;AAAA,QAAC,cAAA;AAAA,QAAA;AAAA,UACC,WAAW,aAAA,IAAiB,MAAA;AAAA,UAC5B,MAAA,EAAQ;AAAA,YACN,QAAA;AAAA,YACA,WAAA,EAAa;AAAA;AAAA;AACf;AAAA;AACF,KAAA,EAEJ,CAAA;AAAA,IACA,QAAA,CAAS;AAAA,GACX;AACF;AAMA,SAAS,gBAAA,CACP,MAAA,EACA,MAAA,EACA,QAAA,EACA,IAAA,EACA;AACA,EAAA,IAAI,CAAC,MAAA,EAAQ;AACb,EAAA,MAAM,YAAY,OAAO,YAAA,KAAiB,cACtC,YAAA,CAAa,OAAA,CAAQ,SAAS,CAAA,GAC9B,IAAA;AACJ,EAAAQ,2BAAA,CAAW,CAAA,EAAG,OAAO,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,eAAA,EAAkB,QAAQ,CAAA,CAAA,EAAI;AAAA,IACnE,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,IAC9C,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,GAAG,IAAA,EAAM,SAAA,EAAW,OAAA,EAAS,MAAA,CAAO,QAAA,CAAS,IAAA,EAAM,CAAA;AAAA,IAC1E,SAAA,EAAW;AAAA,GACb,EAAG,EAAE,MAAA,EAAQ,OAAA,EAAS,GAAG,CAAA,CAAE,MAAM,MAAM;AAAA,EAAC,CAAC,CAAA;AAC3C;AAEA,SAAS,kBAAA,CACP,MAAA,EACA,KAAA,EACA,OAAA,EACA,QACA,MAAA,EACA;AAEA,EAAA,gBAAA,CAAiB,MAAA,EAAQ,QAAQ,OAAA,EAAS;AAAA,IACxC,WAAW,OAAA,CAAQ,EAAA;AAAA,IACnB,QAAQ,MAAA,CAAO;AAAA,GAChB,CAAA;AAED,EAAA,QAAQ,OAAO,MAAA;AAAQ,IACrB,KAAK,UAAA;AACH,MAAA,IAAI,MAAA,CAAO,GAAA,EAAK,MAAA,CAAO,QAAA,CAAS,OAAO,MAAA,CAAO,GAAA;AAC9C,MAAA;AAAA,IACF,KAAK,UAAA;AACH,MAAA,IAAI,OAAO,GAAA,EAAK,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,KAAK,QAAQ,CAAA;AAChD,MAAA;AAAA,IACF,KAAK,aAAA;AAAA,IACL,KAAK,aAAA;AACH,MAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,oBAAA,EAAsB;AAAA,QACzD,MAAA,EAAQ,EAAE,MAAA,EAAQ,MAAA,CAAO,UAAU,MAAA,CAAO,GAAA,EAAK,SAAA,EAAW,OAAA,CAAQ,EAAA;AAAG,OACtE,CAAC,CAAA;AACF,MAAA;AAAA,IACF,KAAK,kBAAA;AACH,MAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,mBAAA,EAAqB;AAAA,QACxD,MAAA,EAAQ,EAAE,MAAA,EAAQ,SAAA,EAAW,QAAQ,EAAA;AAAG,OACzC,CAAC,CAAA;AACF,MAAA;AAAA,IACF;AACE,MAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,eAAA,EAAiB;AAAA,QACpD,MAAA,EAAQ,EAAE,MAAA,EAAQ,SAAA,EAAW,QAAQ,EAAA;AAAG,OACzC,CAAC,CAAA;AACF,MAAA;AAAA;AAEN;AAGA,SAAS,qBAAA,CAAsB;AAAA,EAC7B,OAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAMG;AAED,EAAA,MAAM,YAAA,GAAeI,aAAuB,IAAI,CAAA;AAChD,EAAA,MAAM,oBAAA,GAAuBA,aAAO,KAAK,CAAA;AAEzC,EAAAN,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,KAAK,YAAA,CAAa,OAAA;AACxB,IAAA,IAAI,CAAC,EAAA,IAAM,oBAAA,CAAqB,OAAA,EAAS;AAEzC,IAAA,MAAM,WAAW,IAAI,oBAAA;AAAA,MACnB,CAAC,CAAC,KAAK,CAAA,KAAM;AACX,QAAA,IAAI,KAAA,CAAM,cAAA,IAAkB,CAAC,oBAAA,CAAqB,OAAA,EAAS;AACzD,UAAA,oBAAA,CAAqB,OAAA,GAAU,IAAA;AAC/B,UAAA,gBAAA,CAAiB,QAAQ,MAAA,EAAQ,YAAA,EAAc,EAAE,SAAA,EAAW,OAAA,CAAQ,IAAI,CAAA;AACxE,UAAA,QAAA,CAAS,UAAA,EAAW;AAAA,QACtB;AAAA,MACF,CAAA;AAAA,MACA,EAAE,WAAW,GAAA;AAAI,KACnB;AACA,IAAA,QAAA,CAAS,QAAQ,EAAE,CAAA;AACnB,IAAA,OAAO,MAAM,SAAS,UAAA,EAAW;AAAA,EACnC,GAAG,CAAC,MAAA,EAAQ,MAAA,EAAQ,OAAA,CAAQ,EAAE,CAAC,CAAA;AAE/B,EAAA,MAAM,QAAA,GAAWG,iBAAA;AAAA,IACf,CAAC,QAAsB,IAAA,KAAkB;AACvC,MAAA,kBAAA,CAAmB,MAAA,EAAQ,IAAA,EAAM,OAAA,EAAS,MAAA,EAAQ,MAAM,CAAA;AAAA,IAC1D,CAAA;AAAA,IACA,CAAC,OAAA,EAAS,MAAA,EAAQ,MAAM;AAAA,GAC1B;AAGA,EAAA,IAAI,QAAQ,WAAA,EAAa;AAEvB,IAAA,IAAI,OAAA,CAAQ,SAAS,OAAA,EAAS;AAC5B,MAAA,uBACET,cAAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,GAAA,EAAK,YAAA;AAAA,UACL,uBAAqB,OAAA,CAAQ,EAAA;AAAA,UAC7B,KAAA,EAAO;AAAA,YACL,QAAA,EAAU,OAAA;AAAA,YACV,GAAA,EAAK,CAAA;AAAA,YACL,IAAA,EAAM,CAAA;AAAA,YACN,KAAA,EAAO,CAAA;AAAA,YACP,MAAA,EAAQ,CAAA;AAAA,YACR,eAAA,EAAiB,iBAAA;AAAA,YACjB,OAAA,EAAS,MAAA;AAAA,YACT,UAAA,EAAY,QAAA;AAAA,YACZ,cAAA,EAAgB,QAAA;AAAA,YAChB;AAAA,WACF;AAAA,UACA,OAAA,EAAS,SAAA;AAAA,UAET,QAAA,kBAAAA,eAAC,KAAA,EAAA,EAAI,OAAA,EAAS,OAAK,CAAA,CAAE,eAAA,IACnB,QAAA,kBAAAA,cAAAA;AAAA,YAAC,cAAA;AAAA,YAAA;AAAA,cACC,QAAQ,OAAA,CAAQ,WAAA;AAAA,cAChB,OAAA,EAAS,SAAA;AAAA,cACT;AAAA;AAAA,WACF,EACF;AAAA;AAAA,OACF;AAAA,IAEJ;AAEA,IAAA,IAAI,OAAA,CAAQ,SAAS,KAAA,EAAO;AAC1B,MAAA,uBACEA,cAAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,GAAA,EAAK,YAAA;AAAA,UACL,uBAAqB,OAAA,CAAQ,EAAA;AAAA,UAC7B,KAAA,EAAO;AAAA,YACL,QAAA,EAAU,OAAA;AAAA,YACV,GAAA,EAAK,CAAA;AAAA,YACL,IAAA,EAAM,CAAA;AAAA,YACN,KAAA,EAAO,CAAA;AAAA,YACP;AAAA,WACF;AAAA,UAEA,QAAA,kBAAAA,cAAAA;AAAA,YAAC,cAAA;AAAA,YAAA;AAAA,cACC,QAAQ,OAAA,CAAQ,WAAA;AAAA,cAChB,OAAA,EAAS,SAAA;AAAA,cACT;AAAA;AAAA;AACF;AAAA,OACF;AAAA,IAEJ;AAEA,IAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,OAAA,IAAW,OAAA,CAAQ,SAAS,UAAA,EAAY;AAC3D,MAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,MAAA,EAAQ,QAAA,IAAY,cAAA;AAC7C,MAAA,MAAM,cAAA,GAAsD;AAAA,QAC1D,cAAA,EAAgB,EAAE,MAAA,EAAQ,EAAA,EAAI,OAAO,EAAA,EAAG;AAAA,QACxC,aAAA,EAAe,EAAE,MAAA,EAAQ,EAAA,EAAI,MAAM,EAAA,EAAG;AAAA,QACtC,WAAA,EAAa,EAAE,GAAA,EAAK,EAAA,EAAI,OAAO,EAAA,EAAG;AAAA,QAClC,UAAA,EAAY,EAAE,GAAA,EAAK,EAAA,EAAI,MAAM,EAAA;AAAG,OAClC;AAEA,MAAA,uBACEA,cAAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,GAAA,EAAK,YAAA;AAAA,UACL,uBAAqB,OAAA,CAAQ,EAAA;AAAA,UAC7B,KAAA,EAAO;AAAA,YACL,QAAA,EAAU,OAAA;AAAA,YACV,MAAA;AAAA,YACA,GAAG,eAAe,QAAQ;AAAA,WAC5B;AAAA,UAEA,QAAA,kBAAAA,cAAAA;AAAA,YAAC,cAAA;AAAA,YAAA;AAAA,cACC,QAAQ,OAAA,CAAQ,WAAA;AAAA,cAChB,OAAA,EAAS,SAAA;AAAA,cACT;AAAA;AAAA;AACF;AAAA,OACF;AAAA,IAEJ;AAGA,IAAA,uBACEA,eAAC,KAAA,EAAA,EAAI,GAAA,EAAK,cAAc,qBAAA,EAAqB,OAAA,CAAQ,IACnD,QAAA,kBAAAA,cAAAA;AAAA,MAAC,cAAA;AAAA,MAAA;AAAA,QACC,QAAQ,OAAA,CAAQ,WAAA;AAAA,QAChB,OAAA,EAAS,SAAA;AAAA,QACT;AAAA;AAAA,KACF,EACF,CAAA;AAAA,EAEJ;AAGA,EAAA,IAAI,OAAA,CAAQ,SAAS,OAAA,EAAS;AAC5B,IAAA,uBACEA,cAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO;AAAA,UACL,QAAA,EAAU,OAAA;AAAA,UACV,GAAA,EAAK,CAAA;AAAA,UACL,IAAA,EAAM,CAAA;AAAA,UACN,KAAA,EAAO,CAAA;AAAA,UACP,MAAA,EAAQ,CAAA;AAAA,UACR,eAAA,EAAiB,iBAAA;AAAA,UACjB,OAAA,EAAS,MAAA;AAAA,UACT,UAAA,EAAY,QAAA;AAAA,UACZ,cAAA,EAAgB,QAAA;AAAA,UAChB;AAAA,SACF;AAAA,QACA,OAAA,EAAS,SAAA;AAAA,QAET,QAAA,kBAAAE,eAAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO;AAAA,cACL,eAAA,EAAiB,uBAAA;AAAA,cACjB,OAAA,EAAS,EAAA;AAAA,cACT,YAAA,EAAc,CAAA;AAAA,cACd,QAAA,EAAU,GAAA;AAAA,cACV,KAAA,EAAO;AAAA,aACT;AAAA,YACA,OAAA,EAAS,CAAA,CAAA,KAAK,CAAA,CAAE,eAAA,EAAgB;AAAA,YAEhC,QAAA,EAAA;AAAA,8BAAAF,cAAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBACC,OAAA,EAAS,SAAA;AAAA,kBACT,KAAA,EAAO;AAAA,oBACL,QAAA,EAAU,UAAA;AAAA,oBACV,GAAA,EAAK,CAAA;AAAA,oBACL,KAAA,EAAO,CAAA;AAAA,oBACP,UAAA,EAAY,MAAA;AAAA,oBACZ,MAAA,EAAQ,MAAA;AAAA,oBACR,QAAA,EAAU,EAAA;AAAA,oBACV,MAAA,EAAQ;AAAA,mBACV;AAAA,kBACD,QAAA,EAAA;AAAA;AAAA,eAED;AAAA,cACC,OAAA,CAAQ,QAAQ,KAAA,oBAASA,eAAC,IAAA,EAAA,EAAI,QAAA,EAAA,OAAA,CAAQ,OAAO,KAAA,EAAM,CAAA;AAAA,cACnD,OAAA,CAAQ,QAAQ,OAAA,oBAAWA,eAAC,GAAA,EAAA,EAAG,QAAA,EAAA,OAAA,CAAQ,OAAO,OAAA,EAAQ;AAAA;AAAA;AAAA;AACzD;AAAA,KACF;AAAA,EAEJ;AAGA,EAAA,IAAI,OAAA,CAAQ,SAAS,KAAA,EAAO;AAC1B,IAAA,uBACEE,eAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO;AAAA,UACL,QAAA,EAAU,OAAA;AAAA,UACV,GAAA,EAAK,CAAA;AAAA,UACL,IAAA,EAAM,CAAA;AAAA,UACN,KAAA,EAAO,CAAA;AAAA,UACP,eAAA,EAAiB,OAAA,CAAQ,MAAA,EAAQ,eAAA,IAAmB,4BAAA;AAAA,UACpD,KAAA,EAAO,OAAA,CAAQ,MAAA,EAAQ,SAAA,IAAa,uBAAA;AAAA,UACpC,OAAA,EAAS,WAAA;AAAA,UACT,OAAA,EAAS,MAAA;AAAA,UACT,UAAA,EAAY,QAAA;AAAA,UACZ,cAAA,EAAgB,QAAA;AAAA,UAChB,GAAA,EAAK,EAAA;AAAA,UACL;AAAA,SACF;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAAF,cAAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,OAAA,CAAQ,MAAA,EAAQ,OAAA,EAAQ,CAAA;AAAA,0BAC/BA,cAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAS,SAAA;AAAA,cACT,KAAA,EAAO;AAAA,gBACL,UAAA,EAAY,MAAA;AAAA,gBACZ,MAAA,EAAQ,MAAA;AAAA,gBACR,KAAA,EAAO,SAAA;AAAA,gBACP,QAAA,EAAU,EAAA;AAAA,gBACV,MAAA,EAAQ;AAAA,eACV;AAAA,cACD,QAAA,EAAA;AAAA;AAAA;AAED;AAAA;AAAA,KACF;AAAA,EAEJ;AAEA,EAAA,OAAO,IAAA;AACT;AAGA,SAAS,SAAA,CAAU,UAAkB,OAAA,EAA0B;AAC7D,EAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAAG;AACzB,IAAA,OAAO,SAAS,UAAA,CAAW,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA;AAAA,EACjD;AACA,EAAA,OAAO,QAAA,KAAa,OAAA;AACtB;AAEA,SAAS,aAAA,GAAiD;AACxD,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,SAAA;AAC1C,EAAA,MAAM,KAAK,SAAA,CAAU,SAAA;AACrB,EAAA,IAAI,4BAAA,CAA6B,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,QAAA;AAClD,EAAA,IAAI,4DAAA,CAA6D,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,QAAA;AAClF,EAAA,OAAO,SAAA;AACT","file":"chunk-4NTMIU6V.js","sourcesContent":["/**\n * @sonordev/site-kit/engage - Design Renderer\n * \n * Renders design_json from Engage Studio as React components.\n * This is the runtime renderer that converts the visual builder's\n * JSON structure into actual React elements.\n */\n\n'use client'\n\nimport React, { createElement, CSSProperties, MouseEvent, useState } from 'react'\n\n// ============================================\n// Types\n// ============================================\n\nexport interface DesignNode {\n id: string\n type: string\n name: string\n children?: DesignNode[]\n props?: Record<string, any>\n style?: CSSProperties\n}\n\nexport interface DesignDocument {\n id: string\n type: string\n name: string\n children: DesignNode[]\n style?: CSSProperties\n props?: Record<string, any>\n}\n\nexport interface DesignRendererProps {\n design: DesignDocument\n onClose?: () => void\n onAction?: (action: ActionConfig, node: DesignNode) => void\n context?: EngageContext\n}\n\nexport interface ActionConfig {\n action: string\n url?: string\n newTab?: boolean\n target?: string\n text?: string\n productId?: string\n formId?: string\n}\n\nexport interface EngageContext {\n // Site-Kit context data that can be bound to elements\n user?: {\n name?: string\n email?: string\n isLoggedIn?: boolean\n }\n cart?: {\n itemCount?: number\n total?: number\n }\n page?: {\n url?: string\n title?: string\n }\n // Custom data from the page\n [key: string]: any\n}\n\n// ============================================\n// Action Handlers\n// ============================================\n\nfunction handleAction(\n action: ActionConfig,\n node: DesignNode,\n onClose?: () => void,\n onAction?: (action: ActionConfig, node: DesignNode) => void,\n): void {\n if (!action?.action || action.action === 'none') return\n\n // Let parent handle custom actions\n if (onAction) {\n onAction(action, node)\n }\n\n switch (action.action) {\n case 'link':\n if (action.url) {\n if (action.newTab) {\n window.open(action.url, '_blank', 'noopener,noreferrer')\n } else {\n window.location.href = action.url\n }\n }\n break\n\n case 'scroll':\n if (action.target) {\n const element = document.querySelector(action.target)\n element?.scrollIntoView({ behavior: 'smooth' })\n }\n break\n\n case 'close':\n onClose?.()\n break\n\n case 'copy':\n if (action.text) {\n navigator.clipboard.writeText(action.text).catch(console.error)\n }\n break\n\n case 'share':\n if (navigator.share) {\n navigator.share({\n title: document.title,\n url: window.location.href,\n }).catch(console.error)\n }\n break\n\n case 'download':\n if (action.url) {\n const a = document.createElement('a')\n a.href = action.url\n a.download = ''\n a.click()\n }\n break\n\n // Commerce actions - these should be handled by onAction callback\n case 'add_to_cart':\n case 'checkout':\n case 'book':\n case 'submit_form':\n case 'open_form':\n // Handled by parent via onAction\n break\n }\n}\n\n// ============================================\n// Animation Styles\n// ============================================\n\nconst animationKeyframes = `\n@keyframes engageFadeIn { from { opacity: 0; } to { opacity: 1; } }\n@keyframes engageFadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes engageFadeInDown { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes engageSlideInLeft { from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: translateX(0); } }\n@keyframes engageSlideInRight { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: translateX(0); } }\n@keyframes engageSlideInUp { from { opacity: 0; transform: translateY(100%); } to { opacity: 1; transform: translateY(0); } }\n@keyframes engageScaleIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }\n@keyframes engageBounceIn { 0% { opacity: 0; transform: scale(0.3); } 50% { transform: scale(1.05); } 70% { transform: scale(0.9); } 100% { opacity: 1; transform: scale(1); } }\n`\n\nfunction getAnimationStyle(animation?: string, delay?: number, duration?: number): CSSProperties {\n if (!animation || animation === 'none') return {}\n \n const animationMap: Record<string, string> = {\n fadeIn: 'engageFadeIn',\n fadeInUp: 'engageFadeInUp',\n fadeInDown: 'engageFadeInDown',\n slideInLeft: 'engageSlideInLeft',\n slideInRight: 'engageSlideInRight',\n slideInUp: 'engageSlideInUp',\n scaleIn: 'engageScaleIn',\n bounceIn: 'engageBounceIn',\n }\n \n const animationName = animationMap[animation]\n if (!animationName) return {}\n \n return {\n animation: `${animationName} ${duration || 300}ms ease-out ${delay || 0}ms forwards`,\n opacity: 0, // Start invisible, animation will show it\n }\n}\n\n// ============================================\n// Node Renderer\n// ============================================\n\ninterface NodeRendererProps {\n node: DesignNode\n onClose?: () => void\n onAction?: (action: ActionConfig, node: DesignNode) => void\n context?: EngageContext\n}\n\nfunction NodeRenderer({ node, onClose, onAction, context }: NodeRendererProps): React.ReactElement | null {\n const [isHovered, setIsHovered] = useState(false)\n const { type, props = {}, style = {}, children } = node\n\n // Build styles with hover effects\n const computedStyle: CSSProperties = { ...style }\n \n // Apply animation\n if (props.animation) {\n Object.assign(computedStyle, getAnimationStyle(\n props.animation,\n props.animationDelay,\n props.animationDuration\n ))\n }\n \n // Apply hover effects\n if (isHovered) {\n if (props.hoverScale && props.hoverScale !== 'none') {\n computedStyle.transform = `scale(${props.hoverScale})`\n computedStyle.transition = 'transform 0.2s ease'\n }\n if (props.hoverShadow && props.hoverShadow !== 'none') {\n const shadowMap: Record<string, string> = {\n sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',\n md: '0 4px 6px -1px rgb(0 0 0 / 0.1)',\n lg: '0 10px 15px -3px rgb(0 0 0 / 0.1)',\n }\n computedStyle.boxShadow = shadowMap[props.hoverShadow]\n }\n }\n\n // Event handlers\n const eventHandlers: Record<string, (e: MouseEvent) => void> = {\n onMouseEnter: () => setIsHovered(true),\n onMouseLeave: () => setIsHovered(false),\n }\n \n // Click handler\n if (props.onClick) {\n eventHandlers.onClick = (e: MouseEvent) => {\n e.preventDefault()\n handleAction(props.onClick, node, onClose, onAction)\n }\n computedStyle.cursor = 'pointer'\n }\n\n // Render children recursively\n const renderedChildren = children?.map((child) => (\n <NodeRenderer\n key={child.id}\n node={child}\n onClose={onClose}\n onAction={onAction}\n context={context}\n />\n ))\n\n // Render based on type\n switch (type) {\n case 'Container':\n case 'Box':\n case 'Section':\n return (\n <div style={computedStyle} {...eventHandlers}>\n {renderedChildren}\n </div>\n )\n\n case 'Text':\n return (\n <p style={computedStyle} {...eventHandlers}>\n {resolveText(props.text, context)}\n </p>\n )\n\n case 'Heading':\n const HeadingTag = `h${props.level || 2}` as keyof React.JSX.IntrinsicElements\n return createElement(\n HeadingTag,\n { style: computedStyle, ...eventHandlers },\n resolveText(props.text, context)\n )\n\n case 'Button':\n case 'BookingButton':\n case 'BuyNow':\n case 'AddToCart':\n case 'EventRSVP':\n return (\n <button\n style={computedStyle}\n {...eventHandlers}\n type=\"button\"\n >\n {resolveText(props.text || props.label, context) || 'Button'}\n </button>\n )\n\n case 'Image':\n return (\n <img\n src={props.src}\n alt={props.alt || ''}\n style={computedStyle}\n {...eventHandlers}\n />\n )\n\n case 'Link':\n return (\n <a\n href={props.href || '#'}\n target={props.newTab ? '_blank' : undefined}\n rel={props.newTab ? 'noopener noreferrer' : undefined}\n style={computedStyle}\n {...eventHandlers}\n >\n {resolveText(props.text, context) || renderedChildren}\n </a>\n )\n\n case 'Input':\n return (\n <input\n type={props.inputType || 'text'}\n placeholder={props.placeholder}\n style={computedStyle}\n {...eventHandlers}\n />\n )\n\n case 'Divider':\n return <hr style={{ border: 'none', borderTop: '1px solid var(--sk-border, #e5e7eb)', ...computedStyle }} />\n\n case 'Spacer':\n return <div style={{ ...computedStyle, width: props.width, height: props.height }} />\n\n case 'Icon':\n // Simple emoji/text icon rendering\n return (\n <span style={computedStyle} {...eventHandlers}>\n {props.icon || '★'}\n </span>\n )\n\n case 'FormEmbed':\n // For form embeds, we need to render the form from Forms module\n // This would integrate with the ManagedForm component\n return (\n <div \n style={computedStyle} \n data-engage-form={props.form_id}\n {...eventHandlers}\n >\n {/* ManagedForm would be rendered here by the parent */}\n <div style={{ padding: '16px', background: 'var(--sk-bg-elevated, #f5f5f5)', borderRadius: '8px', textAlign: 'center' }}>\n Form: {props.form_id || 'Not configured'}\n </div>\n </div>\n )\n\n case 'ProductCard':\n case 'EventCard':\n // Product/event cards need data binding from Commerce\n return (\n <div \n style={computedStyle} \n data-engage-offering={props.offering_id}\n {...eventHandlers}\n >\n {renderedChildren}\n </div>\n )\n\n default:\n // Unknown type - render as div with children\n console.warn(`[DesignRenderer] Unknown node type: ${type}`)\n return (\n <div style={computedStyle} {...eventHandlers}>\n {renderedChildren}\n </div>\n )\n }\n}\n\n// ============================================\n// Text Resolution (Data Bindings)\n// ============================================\n\nfunction resolveText(text: string | undefined, context?: EngageContext): string {\n if (!text) return ''\n if (!context) return text\n \n // Replace {{variable}} patterns with context values\n return text.replace(/\\{\\{(\\w+(?:\\.\\w+)*)\\}\\}/g, (match, path) => {\n const value = getNestedValue(context, path)\n return value !== undefined ? String(value) : match\n })\n}\n\nfunction getNestedValue(obj: Record<string, any>, path: string): any {\n return path.split('.').reduce((acc, key) => acc?.[key], obj)\n}\n\n// ============================================\n// Main Component\n// ============================================\n\nexport function DesignRenderer({\n design,\n onClose,\n onAction,\n context,\n}: DesignRendererProps): React.ReactElement {\n // Inject animation keyframes\n React.useEffect(() => {\n if (typeof document === 'undefined') return\n \n const styleId = 'engage-design-renderer-animations'\n if (!document.getElementById(styleId)) {\n const styleSheet = document.createElement('style')\n styleSheet.id = styleId\n styleSheet.textContent = animationKeyframes\n document.head.appendChild(styleSheet)\n }\n }, [])\n\n // Render the root container\n const rootStyle: CSSProperties = {\n ...design.style,\n }\n\n return (\n <div style={rootStyle} data-engage-design={design.id}>\n {design.children?.map((node) => (\n <NodeRenderer\n key={node.id}\n node={node}\n onClose={onClose}\n onAction={onAction}\n context={context}\n />\n ))}\n </div>\n )\n}\n\nexport default DesignRenderer\n","/**\n * @sonordev/site-kit/engage - Engage Widget\n * \n * Loads and renders engagement widgets (popups, nudges, bars, chat) via Portal API\n * Supports both legacy config-based rendering and new design_json from Engage Studio\n */\n\n'use client'\n\nimport React, { useEffect, useRef, useState, useCallback } from 'react'\nimport ReactDOM from 'react-dom'\nimport dynamic from 'next/dynamic'\nimport { usePathname } from 'next/navigation'\nimport type { EngageElement } from './types'\nimport { getOrCreateVisitorId } from '../shared/identity'\nimport { sonorFetch } from '../shared/sonorFetch'\nimport { DesignRenderer, type ActionConfig, type DesignDocument } from './DesignRenderer'\n\n// ChatWidget pulls react-markdown (and lazily socket.io) — keep it out of the\n// engage chunk entirely and only download it when the idle-gated `chatReady`\n// flips and the widget actually renders.\nconst LazyChatWidget = dynamic(\n () => import('./ChatWidget').then(m => ({ default: m.ChatWidget })),\n { ssr: false },\n)\n\ninterface EngageWidgetProps {\n apiUrl?: string\n apiKey?: string\n projectId?: string\n position?: 'bottom-right' | 'bottom-left'\n zIndex?: number\n chatEnabled?: boolean\n debug?: boolean\n}\n\nfunction getApiConfig() {\n const isDev = typeof process !== 'undefined' && process.env?.NODE_ENV === 'development'\n const defaultApiUrl = isDev && process.env?.SONOR_API_URL\n ? process.env.SONOR_API_URL\n : 'https://api.sonor.io'\n const apiUrl = typeof window !== 'undefined'\n ? (window as any).__SITE_KIT_API_URL__ || defaultApiUrl\n : defaultApiUrl\n const apiKey = typeof window !== 'undefined' ? (window as any).__SITE_KIT_API_KEY__ : undefined\n return { apiUrl, apiKey }\n}\n\nexport function EngageWidget({\n apiUrl: propApiUrl,\n apiKey: propApiKey,\n projectId: propProjectId,\n position = 'bottom-right',\n zIndex = 9999,\n chatEnabled = true,\n debug = false,\n}: EngageWidgetProps) {\n const pathname = usePathname()\n const [elements, setElements] = useState<EngageElement[]>([])\n const [activeElements, setActiveElements] = useState<string[]>([])\n const [dismissedElements, setDismissedElements] = useState<Set<string>>(new Set())\n const [chatReady, setChatReady] = useState(false)\n \n // Load elements from API (GET /engage/widget/elements)\n useEffect(() => {\n async function loadElements() {\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n const apiUrl = propApiUrl || globalApiUrl\n const apiKey = propApiKey || globalApiKey\n \n if (!apiKey) {\n if (debug) console.warn('[Engage] No API key configured')\n return\n }\n \n // Shared identity (_sk_vid) — same visitor ID as Analytics & Signal\n const visitorId = getOrCreateVisitorId()\n const url = typeof window !== 'undefined' ? window.location.href : ''\n \n try {\n const response = await sonorFetch(\n `${apiUrl.replace(/\\/$/, '')}/engage/widget/elements?url=${encodeURIComponent(url)}&visitorId=${encodeURIComponent(visitorId)}`,\n {},\n { apiKey },\n )\n \n if (!response.ok) {\n if (debug) console.error('[Engage] Error loading elements:', response.statusText)\n return\n }\n \n const json = await response.json()\n const elementsList = json.data?.elements ?? json.elements ?? []\n if (debug) console.log('[Engage] Loaded elements:', elementsList)\n setElements(elementsList)\n } catch (error) {\n if (debug) console.error('[Engage] Error loading elements:', error)\n }\n }\n \n loadElements()\n }, [propApiUrl, propApiKey, debug])\n\n // Defer ChatWidget until the browser is idle (reduces main-thread blocking)\n useEffect(() => {\n if (!chatEnabled) return\n const id =\n typeof requestIdleCallback !== 'undefined'\n ? requestIdleCallback(() => setChatReady(true), { timeout: 3000 })\n : setTimeout(() => setChatReady(true), 1)\n return () => {\n typeof cancelIdleCallback !== 'undefined' ? cancelIdleCallback(id as number) : clearTimeout(id)\n }\n }, [chatEnabled])\n \n // Check targeting and trigger for each element\n useEffect(() => {\n if (!elements.length) return\n \n const checkElement = (element: EngageElement): boolean => {\n // Check if dismissed\n if (dismissedElements.has(element.id)) return false\n \n // Check page targeting\n if (element.targeting?.pages) {\n const { include, exclude } = element.targeting.pages\n \n if (exclude?.some(p => matchPath(pathname, p))) return false\n if (include && !include.some(p => matchPath(pathname, p))) return false\n }\n \n // Check device targeting\n if (element.targeting?.devices) {\n const device = getDeviceType()\n if (!element.targeting.devices.includes(device)) return false\n }\n \n // Check frequency capping\n if (element.trigger?.frequency) {\n const { type, days } = element.trigger.frequency\n const key = `_engage_${element.id}`\n \n if (type === 'once') {\n if (localStorage.getItem(key)) return false\n } else if (type === 'once-per-session') {\n if (sessionStorage.getItem(key)) return false\n } else if (type === 'every-n-days' && days) {\n const lastShown = localStorage.getItem(key)\n if (lastShown) {\n const elapsed = Date.now() - parseInt(lastShown, 10)\n if (elapsed < days * 24 * 60 * 60 * 1000) return false\n }\n }\n }\n \n return true\n }\n \n // Filter elements that pass targeting\n const eligible = elements.filter(checkElement)\n\n if (debug) console.log('[Engage] Eligible elements:', eligible)\n\n // Dedupe on add: this effect re-runs when dismissedElements changes, so a\n // still-eligible immediate element would otherwise be pushed again\n // (duplicate ids → duplicate keys → double render).\n const activate = (id: string) => {\n setActiveElements(prev => (prev.includes(id) ? prev : [...prev, id]))\n }\n\n // Every timer/listener registered here is torn down on cleanup — the old\n // version leaked delay timeouts and exit-intent/scroll listeners on each\n // effect re-run and on unmount.\n const cleanups: Array<() => void> = []\n\n eligible.forEach(element => {\n const trigger = element.trigger\n\n if (trigger?.type === 'immediate' || !trigger?.type) {\n activate(element.id)\n } else if (trigger?.type === 'delay' && trigger.delay) {\n const timer = setTimeout(() => activate(element.id), trigger.delay * 1000)\n cleanups.push(() => clearTimeout(timer))\n } else if (trigger?.type === 'exit-intent') {\n const handleMouseLeave = (e: MouseEvent) => {\n if (e.clientY < 10) {\n activate(element.id)\n document.removeEventListener('mouseleave', handleMouseLeave)\n }\n }\n document.addEventListener('mouseleave', handleMouseLeave)\n cleanups.push(() => document.removeEventListener('mouseleave', handleMouseLeave))\n } else if (trigger?.type === 'scroll' && trigger.scrollPercentage) {\n const handleScroll = () => {\n const scrollPercent = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100\n if (scrollPercent >= (trigger.scrollPercentage || 50)) {\n activate(element.id)\n window.removeEventListener('scroll', handleScroll)\n }\n }\n window.addEventListener('scroll', handleScroll, { passive: true })\n cleanups.push(() => window.removeEventListener('scroll', handleScroll))\n }\n })\n\n return () => {\n cleanups.forEach(fn => fn())\n }\n }, [elements, pathname, dismissedElements, debug])\n \n const handleDismiss = useCallback((elementId: string) => {\n setDismissedElements(prev => new Set([...prev, elementId]))\n setActiveElements(prev => prev.filter(id => id !== elementId))\n \n // Record dismissal in storage\n const element = elements.find(e => e.id === elementId)\n if (element?.trigger?.frequency) {\n const key = `_engage_${elementId}`\n if (element.trigger.frequency.type === 'once-per-session') {\n sessionStorage.setItem(key, 'true')\n } else {\n localStorage.setItem(key, Date.now().toString())\n }\n }\n }, [elements])\n \n // Render active elements + chat widget\n // Use portal to document.body so widgets always land inside <body>,\n // even when SiteKitLayout wraps <body> (common in root layouts)\n if (typeof document === 'undefined') return null\n\n return ReactDOM.createPortal(\n <>\n {activeElements.map(elementId => {\n const element = elements.find(e => e.id === elementId)\n if (!element) return null\n\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n return (\n <EngageElementRenderer\n key={element.id}\n element={element}\n onDismiss={() => handleDismiss(element.id)}\n zIndex={zIndex}\n apiUrl={propApiUrl || globalApiUrl}\n apiKey={propApiKey || globalApiKey}\n />\n )\n })}\n\n {/* Chat Widget - deferred until idle; chunk downloads on first render */}\n {chatEnabled && chatReady && (\n <LazyChatWidget\n projectId={propProjectId ?? undefined}\n config={{\n position,\n buttonColor: '#2563eb', // Default blue-600 (AA on white), overridden by --sk-primary CSS var or API brand_primary\n }}\n />\n )}\n </>,\n document.body,\n )\n}\n\n// ============================================\n// Action Handler + Tracking\n// ============================================\n\nfunction trackEngageEvent(\n apiUrl: string,\n apiKey: string | undefined,\n endpoint: 'impression' | 'click',\n data: Record<string, unknown>\n) {\n if (!apiKey) return\n const visitorId = typeof localStorage !== 'undefined'\n ? localStorage.getItem('_sk_vid')\n : null\n sonorFetch(`${apiUrl.replace(/\\/$/, '')}/engage/widget/${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ ...data, visitorId, pageUrl: window.location.href }),\n keepalive: true,\n }, { apiKey, retries: 0 }).catch(() => {})\n}\n\nfunction handleEngageAction(\n action: ActionConfig,\n _node: unknown,\n element: EngageElement,\n apiUrl: string,\n apiKey: string | undefined\n) {\n // Track click\n trackEngageEvent(apiUrl, apiKey, 'click', {\n elementId: element.id,\n action: action.action,\n })\n\n switch (action.action) {\n case 'navigate':\n if (action.url) window.location.href = action.url\n break\n case 'open-url':\n if (action.url) window.open(action.url, '_blank')\n break\n case 'submit-form':\n case 'submit_form':\n window.dispatchEvent(new CustomEvent('engage:submit-form', {\n detail: { formId: action.formId || action.url, elementId: element.id },\n }))\n break\n case 'track-conversion':\n window.dispatchEvent(new CustomEvent('engage:conversion', {\n detail: { action, elementId: element.id },\n }))\n break\n default:\n window.dispatchEvent(new CustomEvent('engage:action', {\n detail: { action, elementId: element.id },\n }))\n break\n }\n}\n\n// Helper components\nfunction EngageElementRenderer({\n element,\n onDismiss,\n zIndex,\n apiUrl,\n apiKey,\n}: {\n element: EngageElement\n onDismiss: () => void\n zIndex: number\n apiUrl: string\n apiKey: string | undefined\n}) {\n // Impression tracking via IntersectionObserver\n const containerRef = useRef<HTMLDivElement>(null)\n const impressionTrackedRef = useRef(false)\n\n useEffect(() => {\n const el = containerRef.current\n if (!el || impressionTrackedRef.current) return\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting && !impressionTrackedRef.current) {\n impressionTrackedRef.current = true\n trackEngageEvent(apiUrl, apiKey, 'impression', { elementId: element.id })\n observer.disconnect()\n }\n },\n { threshold: 0.5 }\n )\n observer.observe(el)\n return () => observer.disconnect()\n }, [apiUrl, apiKey, element.id])\n\n const onAction = useCallback(\n (action: ActionConfig, node: unknown) => {\n handleEngageAction(action, node, element, apiUrl, apiKey)\n },\n [element, apiUrl, apiKey]\n )\n\n // If element has design_json from Engage Studio, use DesignRenderer\n if (element.design_json) {\n // Wrap in appropriate container based on element type\n if (element.type === 'popup') {\n return (\n <div\n ref={containerRef}\n data-engage-element={element.id}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0,0,0,0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex,\n }}\n onClick={onDismiss}\n >\n <div onClick={e => e.stopPropagation()}>\n <DesignRenderer\n design={element.design_json}\n onClose={onDismiss}\n onAction={onAction}\n />\n </div>\n </div>\n )\n }\n\n if (element.type === 'bar') {\n return (\n <div\n ref={containerRef}\n data-engage-element={element.id}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n zIndex,\n }}\n >\n <DesignRenderer\n design={element.design_json}\n onClose={onDismiss}\n onAction={onAction}\n />\n </div>\n )\n }\n\n if (element.type === 'nudge' || element.type === 'slide-in') {\n const position = element.config?.position || 'bottom-right'\n const positionStyles: Record<string, React.CSSProperties> = {\n 'bottom-right': { bottom: 20, right: 20 },\n 'bottom-left': { bottom: 20, left: 20 },\n 'top-right': { top: 20, right: 20 },\n 'top-left': { top: 20, left: 20 },\n }\n\n return (\n <div\n ref={containerRef}\n data-engage-element={element.id}\n style={{\n position: 'fixed',\n zIndex,\n ...positionStyles[position],\n }}\n >\n <DesignRenderer\n design={element.design_json}\n onClose={onDismiss}\n onAction={onAction}\n />\n </div>\n )\n }\n\n // Default: render design_json directly\n return (\n <div ref={containerRef} data-engage-element={element.id}>\n <DesignRenderer\n design={element.design_json}\n onClose={onDismiss}\n onAction={onAction}\n />\n </div>\n )\n }\n\n // Legacy: Simple popup rendering for elements without design_json\n if (element.type === 'popup') {\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0,0,0,0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex,\n }}\n onClick={onDismiss}\n >\n <div\n style={{\n backgroundColor: 'var(--sk-bg, #ffffff)',\n padding: 24,\n borderRadius: 8,\n maxWidth: 500,\n width: '90%',\n }}\n onClick={e => e.stopPropagation()}\n >\n <button\n onClick={onDismiss}\n style={{\n position: 'absolute',\n top: 8,\n right: 8,\n background: 'none',\n border: 'none',\n fontSize: 24,\n cursor: 'pointer',\n }}\n >\n ×\n </button>\n {element.config?.title && <h2>{element.config.title}</h2>}\n {element.config?.message && <p>{element.config.message}</p>}\n </div>\n </div>\n )\n }\n \n // Bar/banner rendering\n if (element.type === 'bar') {\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n backgroundColor: element.config?.backgroundColor || 'var(--sk-primary, #2563eb)',\n color: element.config?.textColor || 'var(--sk-bg, #ffffff)',\n padding: '12px 24px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 16,\n zIndex,\n }}\n >\n <span>{element.config?.message}</span>\n <button\n onClick={onDismiss}\n style={{\n background: 'none',\n border: 'none',\n color: 'inherit',\n fontSize: 20,\n cursor: 'pointer',\n }}\n >\n ×\n </button>\n </div>\n )\n }\n \n return null\n}\n\n// Utilities\nfunction matchPath(pathname: string, pattern: string): boolean {\n if (pattern.endsWith('*')) {\n return pathname.startsWith(pattern.slice(0, -1))\n }\n return pathname === pattern\n}\n\nfunction getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof window === 'undefined') return 'desktop'\n const ua = navigator.userAgent\n if (/tablet|ipad|playbook|silk/i.test(ua)) return 'tablet'\n if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) return 'mobile'\n return 'desktop'\n}\n"]}
@@ -5,7 +5,7 @@ import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
6
6
  // src/signal/SignalBridge.tsx
7
7
  var LazySignalCore = dynamic(
8
- () => import('./SignalCore-4MDIJUAP.mjs').then((m) => ({ default: m.SignalCore })),
8
+ () => import('./SignalCore-4B4RNYLV.mjs').then((m) => ({ default: m.SignalCore })),
9
9
  { ssr: false }
10
10
  );
11
11
  var SignalContext = createContext(null);
@@ -116,5 +116,5 @@ function useSignalExperiment(experimentId) {
116
116
  }
117
117
 
118
118
  export { SignalBridge, useSignal, useSignalConfig, useSignalEvent, useSignalExperiment, useSignalOutcome };
119
- //# sourceMappingURL=chunk-YFGKIKXA.mjs.map
120
- //# sourceMappingURL=chunk-YFGKIKXA.mjs.map
119
+ //# sourceMappingURL=chunk-57QV6NIY.mjs.map
120
+ //# sourceMappingURL=chunk-57QV6NIY.mjs.map