@backbay/glia 0.2.0-alpha.6 → 0.2.0-alpha.8

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 (226) hide show
  1. package/dist/audio/index.js +1145 -5
  2. package/dist/audio/index.js.map +1 -1
  3. package/dist/components/index.js +3187 -10
  4. package/dist/components/index.js.map +1 -1
  5. package/dist/core.js +19714 -12
  6. package/dist/core.js.map +1 -1
  7. package/dist/emotion/index.js +1 -1
  8. package/dist/emotion/index.js.map +1 -1
  9. package/dist/hooks/index.js +941 -6
  10. package/dist/hooks/index.js.map +1 -1
  11. package/dist/index.js +31841 -183
  12. package/dist/index.js.map +1 -1
  13. package/dist/primitives/index.js +21111 -57
  14. package/dist/primitives/index.js.map +1 -1
  15. package/dist/protocol/index.js +360 -2
  16. package/dist/protocol/index.js.map +1 -1
  17. package/dist/speakeasy/index.js +2786 -38
  18. package/dist/speakeasy/index.js.map +1 -1
  19. package/dist/styles.css +1 -1
  20. package/dist/theme/index.js +1150 -3
  21. package/dist/theme/index.js.map +1 -1
  22. package/dist/vision/index.js +370 -2
  23. package/dist/vision/index.js.map +1 -1
  24. package/dist/workspace/index.js +16824 -2
  25. package/dist/workspace/index.js.map +1 -1
  26. package/package.json +16 -10
  27. package/dist/AuroraBackground-AP6ZHVFA.js +0 -6
  28. package/dist/AuroraBackground-AP6ZHVFA.js.map +0 -1
  29. package/dist/BentoGrid-CDARICNM.js +0 -6
  30. package/dist/BentoGrid-CDARICNM.js.map +0 -1
  31. package/dist/CommandPalette-JCWJKRBY.js +0 -6
  32. package/dist/CommandPalette-JCWJKRBY.js.map +0 -1
  33. package/dist/Glass-H4X4ZI4P.js +0 -7
  34. package/dist/Glass-H4X4ZI4P.js.map +0 -1
  35. package/dist/GlitchText-KLQ57PPY.js +0 -6
  36. package/dist/GlitchText-KLQ57PPY.js.map +0 -1
  37. package/dist/GlowButton-VGBPMZO7.js +0 -6
  38. package/dist/GlowButton-VGBPMZO7.js.map +0 -1
  39. package/dist/Graph3D-GO7N2EZQ.js +0 -540
  40. package/dist/Graph3D-GO7N2EZQ.js.map +0 -1
  41. package/dist/HUDProgressRing-N6C5NAEV.js +0 -6
  42. package/dist/HUDProgressRing-N6C5NAEV.js.map +0 -1
  43. package/dist/KPIStat-PBQK27ZB.js +0 -6
  44. package/dist/KPIStat-PBQK27ZB.js.map +0 -1
  45. package/dist/NeonToast-W5F7MU3U.js +0 -6
  46. package/dist/NeonToast-W5F7MU3U.js.map +0 -1
  47. package/dist/ParticleField-WK6CNHWU.js +0 -51
  48. package/dist/ParticleField-WK6CNHWU.js.map +0 -1
  49. package/dist/TextGenerateEffect-EUCEIIUJ.js +0 -6
  50. package/dist/TextGenerateEffect-EUCEIIUJ.js.map +0 -1
  51. package/dist/ThreeDCard-VH5I3SSY.js +0 -6
  52. package/dist/ThreeDCard-VH5I3SSY.js.map +0 -1
  53. package/dist/TypingAnimation-GIWOHPIX.js +0 -6
  54. package/dist/TypingAnimation-GIWOHPIX.js.map +0 -1
  55. package/dist/alert-dialog-QOSYBIIE.js +0 -19
  56. package/dist/alert-dialog-QOSYBIIE.js.map +0 -1
  57. package/dist/avatar-N5R37PCU.js +0 -10
  58. package/dist/avatar-N5R37PCU.js.map +0 -1
  59. package/dist/badge-GTVIIGPY.js +0 -8
  60. package/dist/badge-GTVIIGPY.js.map +0 -1
  61. package/dist/button-D7IMSV2D.js +0 -8
  62. package/dist/button-D7IMSV2D.js.map +0 -1
  63. package/dist/chunk-3CMPQOMY.js +0 -69
  64. package/dist/chunk-3CMPQOMY.js.map +0 -1
  65. package/dist/chunk-3OQT6IYR.js +0 -41
  66. package/dist/chunk-3OQT6IYR.js.map +0 -1
  67. package/dist/chunk-43B2WVLS.js +0 -85
  68. package/dist/chunk-43B2WVLS.js.map +0 -1
  69. package/dist/chunk-4SRFO5W3.js +0 -121
  70. package/dist/chunk-4SRFO5W3.js.map +0 -1
  71. package/dist/chunk-5IZELOOU.js +0 -362
  72. package/dist/chunk-5IZELOOU.js.map +0 -1
  73. package/dist/chunk-6DM4ACSS.js +0 -154
  74. package/dist/chunk-6DM4ACSS.js.map +0 -1
  75. package/dist/chunk-6IGT34PC.js +0 -50
  76. package/dist/chunk-6IGT34PC.js.map +0 -1
  77. package/dist/chunk-6RKBCJHN.js +0 -194
  78. package/dist/chunk-6RKBCJHN.js.map +0 -1
  79. package/dist/chunk-6RX2WGCO.js +0 -108
  80. package/dist/chunk-6RX2WGCO.js.map +0 -1
  81. package/dist/chunk-7K4WZM3U.js +0 -189
  82. package/dist/chunk-7K4WZM3U.js.map +0 -1
  83. package/dist/chunk-7MDBHJPT.js +0 -407
  84. package/dist/chunk-7MDBHJPT.js.map +0 -1
  85. package/dist/chunk-7UQD6ROV.js +0 -9
  86. package/dist/chunk-7UQD6ROV.js.map +0 -1
  87. package/dist/chunk-AFNIVLZP.js +0 -1069
  88. package/dist/chunk-AFNIVLZP.js.map +0 -1
  89. package/dist/chunk-ANWYRO6A.js +0 -407
  90. package/dist/chunk-ANWYRO6A.js.map +0 -1
  91. package/dist/chunk-DIXPOHDO.js +0 -71
  92. package/dist/chunk-DIXPOHDO.js.map +0 -1
  93. package/dist/chunk-DWYMKYPI.js +0 -3
  94. package/dist/chunk-DWYMKYPI.js.map +0 -1
  95. package/dist/chunk-E3NVDCZG.js +0 -280
  96. package/dist/chunk-E3NVDCZG.js.map +0 -1
  97. package/dist/chunk-EBM7YBKL.js +0 -399
  98. package/dist/chunk-EBM7YBKL.js.map +0 -1
  99. package/dist/chunk-EPAM7IWW.js +0 -294
  100. package/dist/chunk-EPAM7IWW.js.map +0 -1
  101. package/dist/chunk-EXQ7GYRS.js +0 -134
  102. package/dist/chunk-EXQ7GYRS.js.map +0 -1
  103. package/dist/chunk-F4QTUZ3C.js +0 -136
  104. package/dist/chunk-F4QTUZ3C.js.map +0 -1
  105. package/dist/chunk-FEW533R2.js +0 -105
  106. package/dist/chunk-FEW533R2.js.map +0 -1
  107. package/dist/chunk-FFZLJKC7.js +0 -270
  108. package/dist/chunk-FFZLJKC7.js.map +0 -1
  109. package/dist/chunk-GEAMOBF7.js +0 -8486
  110. package/dist/chunk-GEAMOBF7.js.map +0 -1
  111. package/dist/chunk-GRTRSCTD.js +0 -74
  112. package/dist/chunk-GRTRSCTD.js.map +0 -1
  113. package/dist/chunk-IKGYOGLK.js +0 -16
  114. package/dist/chunk-IKGYOGLK.js.map +0 -1
  115. package/dist/chunk-IQ7WYWVJ.js +0 -73
  116. package/dist/chunk-IQ7WYWVJ.js.map +0 -1
  117. package/dist/chunk-IXIVWQLF.js +0 -543
  118. package/dist/chunk-IXIVWQLF.js.map +0 -1
  119. package/dist/chunk-JCJU57RC.js +0 -115
  120. package/dist/chunk-JCJU57RC.js.map +0 -1
  121. package/dist/chunk-KORSTBU4.js +0 -117
  122. package/dist/chunk-KORSTBU4.js.map +0 -1
  123. package/dist/chunk-KSEZ6UM2.js +0 -235
  124. package/dist/chunk-KSEZ6UM2.js.map +0 -1
  125. package/dist/chunk-MHPF7R3O.js +0 -1376
  126. package/dist/chunk-MHPF7R3O.js.map +0 -1
  127. package/dist/chunk-MPC5IH7E.js +0 -81
  128. package/dist/chunk-MPC5IH7E.js.map +0 -1
  129. package/dist/chunk-MQIU2NYA.js +0 -114
  130. package/dist/chunk-MQIU2NYA.js.map +0 -1
  131. package/dist/chunk-NYMBJOGR.js +0 -2192
  132. package/dist/chunk-NYMBJOGR.js.map +0 -1
  133. package/dist/chunk-OBZD2M3C.js +0 -169
  134. package/dist/chunk-OBZD2M3C.js.map +0 -1
  135. package/dist/chunk-ODM2AG6G.js +0 -176
  136. package/dist/chunk-ODM2AG6G.js.map +0 -1
  137. package/dist/chunk-ONDKF5LP.js +0 -53
  138. package/dist/chunk-ONDKF5LP.js.map +0 -1
  139. package/dist/chunk-P25YCWQB.js +0 -41
  140. package/dist/chunk-P25YCWQB.js.map +0 -1
  141. package/dist/chunk-PFYVNM6H.js +0 -14
  142. package/dist/chunk-PFYVNM6H.js.map +0 -1
  143. package/dist/chunk-PWNNSGFL.js +0 -20
  144. package/dist/chunk-PWNNSGFL.js.map +0 -1
  145. package/dist/chunk-Q2PGZVOT.js +0 -36
  146. package/dist/chunk-Q2PGZVOT.js.map +0 -1
  147. package/dist/chunk-Q2XDMV7U.js +0 -76
  148. package/dist/chunk-Q2XDMV7U.js.map +0 -1
  149. package/dist/chunk-QG7FH2FI.js +0 -45
  150. package/dist/chunk-QG7FH2FI.js.map +0 -1
  151. package/dist/chunk-R7HUOK2D.js +0 -1914
  152. package/dist/chunk-R7HUOK2D.js.map +0 -1
  153. package/dist/chunk-REUYY7G5.js +0 -773
  154. package/dist/chunk-REUYY7G5.js.map +0 -1
  155. package/dist/chunk-RHC2Z2HT.js +0 -199
  156. package/dist/chunk-RHC2Z2HT.js.map +0 -1
  157. package/dist/chunk-RMCVLIFE.js +0 -23
  158. package/dist/chunk-RMCVLIFE.js.map +0 -1
  159. package/dist/chunk-ROZLTXGR.js +0 -234
  160. package/dist/chunk-ROZLTXGR.js.map +0 -1
  161. package/dist/chunk-RSS2C2O3.js +0 -17
  162. package/dist/chunk-RSS2C2O3.js.map +0 -1
  163. package/dist/chunk-SAGCG5SH.js +0 -355
  164. package/dist/chunk-SAGCG5SH.js.map +0 -1
  165. package/dist/chunk-TM6AOUSD.js +0 -40
  166. package/dist/chunk-TM6AOUSD.js.map +0 -1
  167. package/dist/chunk-TPK4BYCO.js +0 -970
  168. package/dist/chunk-TPK4BYCO.js.map +0 -1
  169. package/dist/chunk-UNQIL4K2.js +0 -34
  170. package/dist/chunk-UNQIL4K2.js.map +0 -1
  171. package/dist/chunk-UUG6L75Y.js +0 -47
  172. package/dist/chunk-UUG6L75Y.js.map +0 -1
  173. package/dist/chunk-V2SYMV4W.js +0 -114
  174. package/dist/chunk-V2SYMV4W.js.map +0 -1
  175. package/dist/chunk-V7EN5CTH.js +0 -130
  176. package/dist/chunk-V7EN5CTH.js.map +0 -1
  177. package/dist/chunk-VITKG2HL.js +0 -1125
  178. package/dist/chunk-VITKG2HL.js.map +0 -1
  179. package/dist/chunk-VYEWU5LO.js +0 -2631
  180. package/dist/chunk-VYEWU5LO.js.map +0 -1
  181. package/dist/chunk-W67QAGSH.js +0 -178
  182. package/dist/chunk-W67QAGSH.js.map +0 -1
  183. package/dist/chunk-WWBIN6KV.js +0 -1353
  184. package/dist/chunk-WWBIN6KV.js.map +0 -1
  185. package/dist/chunk-X77Z4PFB.js +0 -224
  186. package/dist/chunk-X77Z4PFB.js.map +0 -1
  187. package/dist/chunk-X7VG7OTT.js +0 -8
  188. package/dist/chunk-X7VG7OTT.js.map +0 -1
  189. package/dist/chunk-XE4K2SGI.js +0 -74
  190. package/dist/chunk-XE4K2SGI.js.map +0 -1
  191. package/dist/chunk-YIUG7IJK.js +0 -628
  192. package/dist/chunk-YIUG7IJK.js.map +0 -1
  193. package/dist/chunk-YNVN3V4Y.js +0 -13
  194. package/dist/chunk-YNVN3V4Y.js.map +0 -1
  195. package/dist/chunk-Z2S54IZX.js +0 -198
  196. package/dist/chunk-Z2S54IZX.js.map +0 -1
  197. package/dist/chunk-ZR6AH25Z.js +0 -17
  198. package/dist/chunk-ZR6AH25Z.js.map +0 -1
  199. package/dist/dialog-SPM3DTTI.js +0 -17
  200. package/dist/dialog-SPM3DTTI.js.map +0 -1
  201. package/dist/dropdown-menu-HMTWKWGK.js +0 -21
  202. package/dist/dropdown-menu-HMTWKWGK.js.map +0 -1
  203. package/dist/input-BH4P4S26.js +0 -6
  204. package/dist/input-BH4P4S26.js.map +0 -1
  205. package/dist/label-5Z4Q6VER.js +0 -8
  206. package/dist/label-5Z4Q6VER.js.map +0 -1
  207. package/dist/popover-IFOUXYLI.js +0 -18
  208. package/dist/popover-IFOUXYLI.js.map +0 -1
  209. package/dist/scroll-area-DJXNW6QX.js +0 -14
  210. package/dist/scroll-area-DJXNW6QX.js.map +0 -1
  211. package/dist/select-FZ277C3G.js +0 -22
  212. package/dist/select-FZ277C3G.js.map +0 -1
  213. package/dist/separator-BTMLN4NB.js +0 -8
  214. package/dist/separator-BTMLN4NB.js.map +0 -1
  215. package/dist/skeleton-DXIWBH4W.js +0 -6
  216. package/dist/skeleton-DXIWBH4W.js.map +0 -1
  217. package/dist/switch-4MCXIZBY.js +0 -13
  218. package/dist/switch-4MCXIZBY.js.map +0 -1
  219. package/dist/tabs-O7AW3APK.js +0 -17
  220. package/dist/tabs-O7AW3APK.js.map +0 -1
  221. package/dist/textarea-IB5WAFDO.js +0 -6
  222. package/dist/textarea-IB5WAFDO.js.map +0 -1
  223. package/dist/toggle-XVPPG6P4.js +0 -10
  224. package/dist/toggle-XVPPG6P4.js.map +0 -1
  225. package/dist/tooltip-JICZTD4F.js +0 -18
  226. package/dist/tooltip-JICZTD4F.js.map +0 -1
@@ -1,12 +1,3189 @@
1
- export { CLUSTER_CONFIGS, ClusterHero, ClusterHeroPage, getClusterConfig } from '../chunk-R7HUOK2D.js';
2
- export { AgentPanel, PlaySession, SyncDocument } from '../chunk-EPAM7IWW.js';
3
- import '../chunk-YIUG7IJK.js';
4
- export { BBProvider, useBBContext, useBBContextOptional } from '../chunk-Q2XDMV7U.js';
5
- import '../chunk-F4QTUZ3C.js';
6
- import '../chunk-VITKG2HL.js';
7
- import '../chunk-6RX2WGCO.js';
8
- import '../chunk-3CMPQOMY.js';
9
- import '../chunk-OBZD2M3C.js';
10
- import '../chunk-TM6AOUSD.js';
1
+ import * as React3 from 'react';
2
+ import { createContext, useState, useMemo, useCallback, useContext, useRef, useEffect, Component, useId } from 'react';
3
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
+ import { clsx } from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import { useReducedMotion, motion, useScroll, useTransform, AnimatePresence, useMotionValue, useSpring } from 'framer-motion';
7
+ import { Trophy, Vote, Zap, FileText, ArrowRight } from 'lucide-react';
8
+
9
+ // src/components/BBProvider.tsx
10
+ var ErrorBoundaryContext = createContext(null);
11
+ function ErrorThrower({ children }) {
12
+ const [error, setError] = useState(null);
13
+ if (error) {
14
+ throw error;
15
+ }
16
+ const throwError = useCallback((err) => {
17
+ setError(err);
18
+ }, []);
19
+ return /* @__PURE__ */ jsx(ErrorBoundaryContext.Provider, { value: { throwError }, children });
20
+ }
21
+ function DefaultFallback({
22
+ error,
23
+ reset,
24
+ variant = "card"
25
+ }) {
26
+ const isFullscreen = variant === "fullscreen";
27
+ const isInline = variant === "inline";
28
+ const containerStyle = isFullscreen ? {
29
+ position: "fixed",
30
+ inset: 0,
31
+ display: "flex",
32
+ alignItems: "center",
33
+ justifyContent: "center",
34
+ zIndex: 9999,
35
+ background: "rgba(0, 0, 0, 0.6)",
36
+ backdropFilter: "blur(12px)",
37
+ WebkitBackdropFilter: "blur(12px)"
38
+ } : isInline ? {
39
+ display: "inline-flex",
40
+ alignItems: "center",
41
+ gap: 8,
42
+ padding: "4px 8px",
43
+ borderRadius: 6,
44
+ background: "rgba(255, 60, 60, 0.08)",
45
+ border: "1px solid rgba(255, 60, 60, 0.2)"
46
+ } : {};
47
+ const cardStyle = {
48
+ background: "rgba(20, 20, 30, 0.85)",
49
+ backdropFilter: "blur(16px)",
50
+ WebkitBackdropFilter: "blur(16px)",
51
+ border: "1px solid rgba(255, 255, 255, 0.08)",
52
+ borderRadius: 12,
53
+ padding: isInline ? void 0 : "24px 28px",
54
+ maxWidth: isFullscreen ? 480 : "100%",
55
+ width: isFullscreen ? "90%" : void 0,
56
+ color: "rgba(255, 255, 255, 0.9)",
57
+ fontFamily: "system-ui, -apple-system, sans-serif"
58
+ };
59
+ if (isInline) {
60
+ return /* @__PURE__ */ jsxs("span", { style: containerStyle, children: [
61
+ /* @__PURE__ */ jsxs("span", { style: { color: "rgba(255, 100, 100, 0.9)", fontSize: 12 }, children: [
62
+ "Error: ",
63
+ error.message
64
+ ] }),
65
+ /* @__PURE__ */ jsx(
66
+ "button",
67
+ {
68
+ onClick: reset,
69
+ style: {
70
+ background: "none",
71
+ border: "none",
72
+ color: "rgba(100, 180, 255, 0.9)",
73
+ cursor: "pointer",
74
+ fontSize: 12,
75
+ textDecoration: "underline",
76
+ padding: 0
77
+ },
78
+ children: "Retry"
79
+ }
80
+ )
81
+ ] });
82
+ }
83
+ return /* @__PURE__ */ jsx("div", { style: containerStyle, children: /* @__PURE__ */ jsxs("div", { style: cardStyle, children: [
84
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 12 }, children: [
85
+ /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "rgba(255, 100, 100, 0.9)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
86
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
87
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
88
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
89
+ ] }),
90
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, fontSize: 15 }, children: "Something went wrong" })
91
+ ] }),
92
+ /* @__PURE__ */ jsx("p", { style: { color: "rgba(255, 255, 255, 0.5)", fontSize: 13, lineHeight: 1.5, margin: "0 0 16px", wordBreak: "break-word" }, children: error.message }),
93
+ /* @__PURE__ */ jsx(
94
+ "button",
95
+ {
96
+ onClick: reset,
97
+ style: {
98
+ background: "rgba(255, 255, 255, 0.08)",
99
+ border: "1px solid rgba(255, 255, 255, 0.12)",
100
+ borderRadius: 8,
101
+ padding: "8px 16px",
102
+ color: "rgba(255, 255, 255, 0.9)",
103
+ cursor: "pointer",
104
+ fontSize: 13,
105
+ fontWeight: 500,
106
+ transition: "background 0.15s"
107
+ },
108
+ onMouseEnter: (e) => {
109
+ e.currentTarget.style.background = "rgba(255, 255, 255, 0.14)";
110
+ },
111
+ onMouseLeave: (e) => {
112
+ e.currentTarget.style.background = "rgba(255, 255, 255, 0.08)";
113
+ },
114
+ children: "Try again"
115
+ }
116
+ )
117
+ ] }) });
118
+ }
119
+ var GliaErrorBoundary = class extends Component {
120
+ static displayName = "GliaErrorBoundary";
121
+ autoRetryTimer = null;
122
+ constructor(props) {
123
+ super(props);
124
+ this.state = { error: null };
125
+ }
126
+ static getDerivedStateFromError(error) {
127
+ return { error };
128
+ }
129
+ componentDidCatch(error, errorInfo) {
130
+ this.props.onError?.(error, errorInfo);
131
+ if (this.props.autoRetryMs && this.props.autoRetryMs > 0) {
132
+ this.autoRetryTimer = setTimeout(() => {
133
+ this.reset();
134
+ }, this.props.autoRetryMs);
135
+ }
136
+ }
137
+ componentWillUnmount() {
138
+ if (this.autoRetryTimer) {
139
+ clearTimeout(this.autoRetryTimer);
140
+ }
141
+ }
142
+ reset = () => {
143
+ if (this.autoRetryTimer) {
144
+ clearTimeout(this.autoRetryTimer);
145
+ this.autoRetryTimer = null;
146
+ }
147
+ this.setState({ error: null });
148
+ };
149
+ render() {
150
+ const { error } = this.state;
151
+ const { children, fallback, variant = "card" } = this.props;
152
+ if (error) {
153
+ if (typeof fallback === "function") {
154
+ return fallback({ error, reset: this.reset });
155
+ }
156
+ if (fallback !== void 0) {
157
+ return fallback;
158
+ }
159
+ return /* @__PURE__ */ jsx(DefaultFallback, { error, reset: this.reset, variant });
160
+ }
161
+ return /* @__PURE__ */ jsx(ErrorThrower, { children });
162
+ }
163
+ };
164
+ var BBContext = createContext(null);
165
+ function BBProvider({
166
+ children,
167
+ config,
168
+ agents = [],
169
+ initialSyncStatus = "synced"
170
+ }) {
171
+ const [activeRuns, setActiveRuns] = useState([]);
172
+ const [runHistory, setRunHistory] = useState([]);
173
+ const [syncStatus, setSyncStatus] = useState(initialSyncStatus);
174
+ const totalCost = useMemo(() => {
175
+ return runHistory.reduce((sum, run) => sum + (run.cost ?? 0), 0);
176
+ }, [runHistory]);
177
+ const addRun = useCallback((run) => {
178
+ setActiveRuns((prev) => [...prev, run]);
179
+ setRunHistory((prev) => [...prev, run]);
180
+ }, []);
181
+ const updateRun = useCallback((runId, updates) => {
182
+ const updateInList = (runs) => runs.map((run) => run.id === runId ? { ...run, ...updates } : run);
183
+ setActiveRuns((prev) => {
184
+ const updated = updateInList(prev);
185
+ return updated.filter(
186
+ (run) => run.status === "idle" || run.status === "running"
187
+ );
188
+ });
189
+ setRunHistory(updateInList);
190
+ }, []);
191
+ const getAgent = useCallback(
192
+ (agentId) => agents.find((a) => a.id === agentId),
193
+ [agents]
194
+ );
195
+ const value = useMemo(
196
+ () => ({
197
+ config,
198
+ agents,
199
+ activeRuns,
200
+ runHistory,
201
+ totalCost,
202
+ syncStatus,
203
+ addRun,
204
+ updateRun,
205
+ setSyncStatus,
206
+ getAgent
207
+ }),
208
+ [
209
+ config,
210
+ agents,
211
+ activeRuns,
212
+ runHistory,
213
+ totalCost,
214
+ syncStatus,
215
+ addRun,
216
+ updateRun,
217
+ getAgent
218
+ ]
219
+ );
220
+ return /* @__PURE__ */ jsx(BBContext.Provider, { value, children: /* @__PURE__ */ jsx(GliaErrorBoundary, { variant: "fullscreen", children }) });
221
+ }
222
+ function useBBContext() {
223
+ const context = useContext(BBContext);
224
+ if (!context) {
225
+ throw new Error("useBBContext must be used within a BBProvider");
226
+ }
227
+ return context;
228
+ }
229
+ function useBBContextOptional() {
230
+ return useContext(BBContext);
231
+ }
232
+ function stableStringify(value) {
233
+ if (value === null || typeof value !== "object") {
234
+ const encoded = JSON.stringify(value);
235
+ return encoded === void 0 ? "null" : encoded;
236
+ }
237
+ if (Array.isArray(value)) {
238
+ return `[${value.map(stableStringify).join(",")}]`;
239
+ }
240
+ const record = value;
241
+ const keys = Object.keys(record).sort();
242
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(record[k])}`).join(",")}}`;
243
+ }
244
+ function hashString(input) {
245
+ let hash = 2166136261;
246
+ for (let i = 0; i < input.length; i++) {
247
+ hash ^= input.charCodeAt(i);
248
+ hash = hash * 16777619 >>> 0;
249
+ }
250
+ return hash.toString(36);
251
+ }
252
+ function hashData(value) {
253
+ return hashString(stableStringify(value));
254
+ }
255
+ function normalizeStoredData(raw) {
256
+ if (!raw || typeof raw !== "object") return null;
257
+ const record = raw;
258
+ if ("data" in record && typeof record.lastModifiedAt === "number" && typeof record.lastSyncedAt === "number" && typeof record.lastSyncedHash === "string") {
259
+ return record;
260
+ }
261
+ if ("data" in record && typeof record.timestamp === "number" && typeof record.version === "number") {
262
+ const legacy = record;
263
+ const syncedHash = hashData(legacy.data);
264
+ return {
265
+ data: legacy.data,
266
+ lastModifiedAt: legacy.timestamp,
267
+ lastSyncedAt: legacy.timestamp,
268
+ lastSyncedHash: syncedHash
269
+ };
270
+ }
271
+ return null;
272
+ }
273
+ function getStoredData(key) {
274
+ try {
275
+ const raw = localStorage.getItem(key);
276
+ if (!raw) return null;
277
+ const parsed = JSON.parse(raw);
278
+ return normalizeStoredData(parsed);
279
+ } catch {
280
+ return null;
281
+ }
282
+ }
283
+ function setStoredData(key, record) {
284
+ localStorage.setItem(key, JSON.stringify(record));
285
+ }
286
+ function useSync({
287
+ key,
288
+ endpoint,
289
+ debounce = 2e3,
290
+ initialData,
291
+ fetcher,
292
+ saver,
293
+ onConflict,
294
+ onError,
295
+ onSync
296
+ }) {
297
+ const [data, setDataState] = useState(initialData ?? null);
298
+ const [status, setStatus] = useState("synced");
299
+ const [pendingChanges, setPendingChanges] = useState(0);
300
+ const [lastSyncedAt, setLastSyncedAt] = useState(null);
301
+ const [conflict, setConflict] = useState(null);
302
+ const [isLoaded, setIsLoaded] = useState(false);
303
+ const debounceTimerRef = useRef(null);
304
+ const isSavingRef = useRef(false);
305
+ const doFetch = useCallback(
306
+ async (url) => {
307
+ if (fetcher) return fetcher(url);
308
+ const response = await fetch(url);
309
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
310
+ return response.json();
311
+ },
312
+ [fetcher]
313
+ );
314
+ const doSave = useCallback(
315
+ async (url, payload) => {
316
+ if (saver) return saver(url, payload);
317
+ const response = await fetch(url, {
318
+ method: "PUT",
319
+ headers: { "Content-Type": "application/json" },
320
+ body: JSON.stringify(payload)
321
+ });
322
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
323
+ return response.json();
324
+ },
325
+ [saver]
326
+ );
327
+ useEffect(() => {
328
+ const loadInitial = async () => {
329
+ const stored = getStoredData(key);
330
+ if (stored) {
331
+ setDataState(stored.data);
332
+ const storedSyncedAt = stored.lastSyncedAt > 0 ? stored.lastSyncedAt : null;
333
+ setLastSyncedAt(storedSyncedAt);
334
+ const hasLocalChanges = stored.lastModifiedAt > stored.lastSyncedAt;
335
+ if (hasLocalChanges) {
336
+ setStatus("pending");
337
+ setPendingChanges((c) => Math.max(c, 1));
338
+ }
339
+ }
340
+ try {
341
+ const serverData = await doFetch(endpoint);
342
+ const remoteTimestamp = Date.now();
343
+ const remoteHash = hashData(serverData);
344
+ if (stored) {
345
+ const hasLocalChanges = stored.lastModifiedAt > stored.lastSyncedAt;
346
+ const baselineHash = stored.lastSyncedHash || hashData(stored.data);
347
+ const remoteChangedSinceSync = remoteHash !== baselineHash;
348
+ if (hasLocalChanges && remoteChangedSinceSync) {
349
+ const localConflict = {
350
+ local: stored.data,
351
+ remote: serverData,
352
+ localTimestamp: stored.lastModifiedAt,
353
+ remoteTimestamp
354
+ };
355
+ setConflict(localConflict);
356
+ setStatus("conflict");
357
+ onConflict?.(localConflict);
358
+ } else if (!hasLocalChanges) {
359
+ setDataState(serverData);
360
+ setStoredData(key, {
361
+ data: serverData,
362
+ lastModifiedAt: remoteTimestamp,
363
+ lastSyncedAt: remoteTimestamp,
364
+ lastSyncedHash: remoteHash
365
+ });
366
+ setLastSyncedAt(remoteTimestamp);
367
+ setPendingChanges(0);
368
+ setStatus("synced");
369
+ } else {
370
+ setStatus("pending");
371
+ }
372
+ } else {
373
+ setDataState(serverData);
374
+ setStoredData(key, {
375
+ data: serverData,
376
+ lastModifiedAt: remoteTimestamp,
377
+ lastSyncedAt: remoteTimestamp,
378
+ lastSyncedHash: remoteHash
379
+ });
380
+ setLastSyncedAt(remoteTimestamp);
381
+ setPendingChanges(0);
382
+ setStatus("synced");
383
+ }
384
+ } catch (error) {
385
+ setStatus("offline");
386
+ if (error instanceof Error) {
387
+ onError?.(error);
388
+ }
389
+ }
390
+ setIsLoaded(true);
391
+ };
392
+ loadInitial();
393
+ }, [key, endpoint, doFetch, onConflict, onError]);
394
+ const saveToServer = useCallback(async (payload) => {
395
+ const dataToSave = payload ?? data;
396
+ if (isSavingRef.current || dataToSave === null) return;
397
+ isSavingRef.current = true;
398
+ try {
399
+ setStatus("pending");
400
+ const serverData = await doSave(endpoint, dataToSave);
401
+ const syncedAt = Date.now();
402
+ const syncedHash = hashData(serverData);
403
+ setDataState(serverData);
404
+ setStoredData(key, {
405
+ data: serverData,
406
+ lastModifiedAt: syncedAt,
407
+ lastSyncedAt: syncedAt,
408
+ lastSyncedHash: syncedHash
409
+ });
410
+ setLastSyncedAt(syncedAt);
411
+ setPendingChanges(0);
412
+ setStatus("synced");
413
+ onSync?.(serverData);
414
+ } catch (error) {
415
+ setStatus("offline");
416
+ if (error instanceof Error) {
417
+ onError?.(error);
418
+ }
419
+ } finally {
420
+ isSavingRef.current = false;
421
+ }
422
+ }, [data, endpoint, key, doSave, onSync, onError]);
423
+ const setData = useCallback(
424
+ (updater) => {
425
+ setDataState((prev) => {
426
+ const newData = typeof updater === "function" ? updater(prev) : updater;
427
+ const previousStored = getStoredData(key);
428
+ const now = Date.now();
429
+ setStoredData(key, {
430
+ data: newData,
431
+ lastModifiedAt: now,
432
+ lastSyncedAt: previousStored?.lastSyncedAt ?? 0,
433
+ lastSyncedHash: previousStored?.lastSyncedHash ?? ""
434
+ });
435
+ setPendingChanges((c) => c + 1);
436
+ setStatus("pending");
437
+ if (debounceTimerRef.current) {
438
+ clearTimeout(debounceTimerRef.current);
439
+ }
440
+ debounceTimerRef.current = setTimeout(() => {
441
+ saveToServer();
442
+ }, debounce);
443
+ return newData;
444
+ });
445
+ },
446
+ [key, debounce, saveToServer]
447
+ );
448
+ const forceSave = useCallback(async () => {
449
+ if (debounceTimerRef.current) {
450
+ clearTimeout(debounceTimerRef.current);
451
+ debounceTimerRef.current = null;
452
+ }
453
+ await saveToServer();
454
+ }, [saveToServer]);
455
+ const refresh = useCallback(async () => {
456
+ try {
457
+ const serverData = await doFetch(endpoint);
458
+ const syncedAt = Date.now();
459
+ const syncedHash = hashData(serverData);
460
+ setDataState(serverData);
461
+ setStoredData(key, {
462
+ data: serverData,
463
+ lastModifiedAt: syncedAt,
464
+ lastSyncedAt: syncedAt,
465
+ lastSyncedHash: syncedHash
466
+ });
467
+ setLastSyncedAt(syncedAt);
468
+ setPendingChanges(0);
469
+ setConflict(null);
470
+ setStatus("synced");
471
+ } catch (error) {
472
+ setStatus("offline");
473
+ if (error instanceof Error) {
474
+ onError?.(error);
475
+ }
476
+ }
477
+ }, [endpoint, key, doFetch, onError]);
478
+ const resolveConflict = useCallback(
479
+ async (resolution) => {
480
+ if (!conflict) return;
481
+ switch (resolution) {
482
+ case "keep_local":
483
+ setDataState(conflict.local);
484
+ setConflict(null);
485
+ setStatus("pending");
486
+ setPendingChanges((c) => Math.max(c, 1));
487
+ await saveToServer(conflict.local);
488
+ break;
489
+ case "use_remote": {
490
+ const remoteHash = hashData(conflict.remote);
491
+ setDataState(conflict.remote);
492
+ setStoredData(key, {
493
+ data: conflict.remote,
494
+ lastModifiedAt: conflict.remoteTimestamp,
495
+ lastSyncedAt: conflict.remoteTimestamp,
496
+ lastSyncedHash: remoteHash
497
+ });
498
+ setLastSyncedAt(conflict.remoteTimestamp);
499
+ setPendingChanges(0);
500
+ setConflict(null);
501
+ setStatus("synced");
502
+ break;
503
+ }
504
+ case "create_copy":
505
+ setDataState(conflict.local);
506
+ setConflict(null);
507
+ setStatus("pending");
508
+ setPendingChanges((c) => Math.max(c, 1));
509
+ await saveToServer(conflict.local);
510
+ break;
511
+ }
512
+ },
513
+ [conflict, key, saveToServer]
514
+ );
515
+ useEffect(() => {
516
+ return () => {
517
+ if (debounceTimerRef.current) {
518
+ clearTimeout(debounceTimerRef.current);
519
+ }
520
+ };
521
+ }, []);
522
+ return {
523
+ data,
524
+ setData,
525
+ status,
526
+ pendingChanges,
527
+ lastSyncedAt,
528
+ conflict,
529
+ resolveConflict,
530
+ forceSave,
531
+ refresh,
532
+ isLoaded
533
+ };
534
+ }
535
+ function SyncDocument({
536
+ documentId,
537
+ endpoint,
538
+ debounce = 1e3,
539
+ initialContent,
540
+ onConflict,
541
+ onError,
542
+ onSave,
543
+ children,
544
+ fetcher,
545
+ saver
546
+ }) {
547
+ const fullEndpoint = `${endpoint}/${documentId}`;
548
+ const {
549
+ data,
550
+ setData,
551
+ status,
552
+ pendingChanges,
553
+ lastSyncedAt,
554
+ conflict,
555
+ resolveConflict,
556
+ forceSave,
557
+ refresh,
558
+ isLoaded
559
+ } = useSync({
560
+ key: `sync-doc:${documentId}`,
561
+ endpoint: fullEndpoint,
562
+ debounce,
563
+ initialData: initialContent,
564
+ fetcher,
565
+ saver,
566
+ onConflict: onConflict ? (c) => {
567
+ } : void 0,
568
+ onError,
569
+ onSync: onSave
570
+ });
571
+ const conflictUI = conflict && onConflict ? onConflict(conflict.local, conflict.remote, resolveConflict) : null;
572
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
573
+ conflictUI,
574
+ children({
575
+ content: data,
576
+ setContent: setData,
577
+ status,
578
+ lastSaved: lastSyncedAt,
579
+ pendingChanges,
580
+ save: forceSave,
581
+ refresh,
582
+ isLoaded
583
+ })
584
+ ] });
585
+ }
586
+ function useAgentRun(options = {}) {
587
+ const { onStart, onComplete, onError, onCancel } = options;
588
+ const { config, addRun, updateRun, getAgent } = useBBContext();
589
+ const [run, setRun] = useState(null);
590
+ const [status, setStatus] = useState("idle");
591
+ const [output, setOutput] = useState(null);
592
+ const [error, setError] = useState(null);
593
+ const [cost, setCost] = useState(null);
594
+ const [latency, setLatency] = useState(null);
595
+ const abortControllerRef = useRef(null);
596
+ const start = useCallback(
597
+ async (agentId, prompt, context) => {
598
+ if (abortControllerRef.current) {
599
+ abortControllerRef.current.abort();
600
+ }
601
+ const controller = new AbortController();
602
+ abortControllerRef.current = controller;
603
+ const runId = `run-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
604
+ const startedAt = Date.now();
605
+ const newRun = {
606
+ id: runId,
607
+ agentId,
608
+ prompt,
609
+ context,
610
+ status: "running",
611
+ startedAt
612
+ };
613
+ setRun(newRun);
614
+ setStatus("running");
615
+ setOutput(null);
616
+ setError(null);
617
+ setCost(null);
618
+ setLatency(null);
619
+ addRun(newRun);
620
+ onStart?.(newRun);
621
+ try {
622
+ const response = await fetch(`${config.apiBaseUrl}/runs`, {
623
+ method: "POST",
624
+ headers: {
625
+ "Content-Type": "application/json",
626
+ ...config.headers
627
+ },
628
+ body: JSON.stringify({
629
+ agentId,
630
+ prompt,
631
+ context
632
+ }),
633
+ signal: controller.signal
634
+ });
635
+ if (!response.ok) {
636
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
637
+ }
638
+ const result = await response.json();
639
+ const completedAt = Date.now();
640
+ const runLatency = completedAt - startedAt;
641
+ const agent = getAgent(agentId);
642
+ const runCost = result.cost ?? agent?.costPerRun ?? 0;
643
+ const completedRun = {
644
+ ...newRun,
645
+ status: "completed",
646
+ output: result.output,
647
+ cost: runCost,
648
+ tokenCount: result.tokenCount,
649
+ latencyMs: runLatency,
650
+ completedAt
651
+ };
652
+ setRun(completedRun);
653
+ setStatus("completed");
654
+ setOutput(result.output);
655
+ setCost(runCost);
656
+ setLatency(runLatency);
657
+ updateRun(runId, completedRun);
658
+ onComplete?.(completedRun);
659
+ } catch (err) {
660
+ if (err instanceof Error && err.name === "AbortError") {
661
+ const cancelledRun = {
662
+ ...newRun,
663
+ status: "cancelled",
664
+ completedAt: Date.now()
665
+ };
666
+ setRun(cancelledRun);
667
+ setStatus("cancelled");
668
+ updateRun(runId, cancelledRun);
669
+ onCancel?.(cancelledRun);
670
+ return;
671
+ }
672
+ const errorMessage = err instanceof Error ? err.message : "Unknown error";
673
+ const failedRun = {
674
+ ...newRun,
675
+ status: "failed",
676
+ error: errorMessage,
677
+ completedAt: Date.now()
678
+ };
679
+ setRun(failedRun);
680
+ setStatus("failed");
681
+ setError(errorMessage);
682
+ updateRun(runId, failedRun);
683
+ onError?.(failedRun, err instanceof Error ? err : new Error(errorMessage));
684
+ } finally {
685
+ if (abortControllerRef.current === controller) {
686
+ abortControllerRef.current = null;
687
+ }
688
+ }
689
+ },
690
+ [config, addRun, updateRun, getAgent, onStart, onComplete, onError, onCancel]
691
+ );
692
+ const cancel = useCallback(() => {
693
+ if (abortControllerRef.current) {
694
+ abortControllerRef.current.abort();
695
+ abortControllerRef.current = null;
696
+ }
697
+ }, []);
698
+ return {
699
+ run,
700
+ status,
701
+ output,
702
+ error,
703
+ cost,
704
+ latency,
705
+ start,
706
+ cancel,
707
+ isRunning: status === "running"
708
+ };
709
+ }
710
+ function AgentPanel({
711
+ context,
712
+ quickPrompts = [],
713
+ onRunStart,
714
+ onRunComplete,
715
+ onRunError,
716
+ showCosts = true,
717
+ showHistory = true,
718
+ maxHistory = 10,
719
+ placeholder = "Enter a prompt...",
720
+ className,
721
+ agentFilter,
722
+ defaultAgent
723
+ }) {
724
+ const { agents, runHistory, totalCost: globalTotalCost } = useBBContext();
725
+ const availableAgents = agentFilter ? agents.filter(agentFilter) : agents;
726
+ const [selectedAgentId, setSelectedAgentId] = useState(
727
+ defaultAgent ?? availableAgents[0]?.id ?? null
728
+ );
729
+ const [prompt, setPrompt] = useState("");
730
+ const selectedAgent = availableAgents.find((a) => a.id === selectedAgentId) ?? null;
731
+ const {
732
+ run: currentRun,
733
+ status,
734
+ isRunning,
735
+ start
736
+ } = useAgentRun({
737
+ onStart: onRunStart,
738
+ onComplete: onRunComplete,
739
+ onError: onRunError
740
+ });
741
+ const panelHistory = runHistory.filter((run) => availableAgents.some((a) => a.id === run.agentId)).slice(0, maxHistory);
742
+ const panelTotalCost = panelHistory.reduce((sum, run) => sum + (run.cost ?? 0), 0);
743
+ const estimatedCost = selectedAgent?.costPerRun ?? null;
744
+ const handleSubmit = useCallback(
745
+ (e) => {
746
+ e?.preventDefault();
747
+ if (!selectedAgentId || !prompt.trim() || isRunning) return;
748
+ start(selectedAgentId, prompt, context);
749
+ setPrompt("");
750
+ },
751
+ [selectedAgentId, prompt, isRunning, start, context]
752
+ );
753
+ const executeQuickPrompt = useCallback(
754
+ (qp) => {
755
+ if (!selectedAgentId || isRunning) return;
756
+ start(selectedAgentId, qp.prompt, context);
757
+ },
758
+ [selectedAgentId, isRunning, start, context]
759
+ );
760
+ const selectAgent = useCallback((agentId) => {
761
+ setSelectedAgentId(agentId);
762
+ }, []);
763
+ return /* @__PURE__ */ jsxs("div", { className: `bb-agent-panel ${className ?? ""}`, "data-bb-state": status, children: [
764
+ /* @__PURE__ */ jsx("div", { className: "bb-agent-panel__agents", children: availableAgents.map((agent) => /* @__PURE__ */ jsxs(
765
+ "button",
766
+ {
767
+ type: "button",
768
+ className: `bb-agent-panel__agent ${agent.id === selectedAgentId ? "bb-agent-panel__agent--selected" : ""}`,
769
+ onClick: () => selectAgent(agent.id),
770
+ disabled: isRunning,
771
+ "data-bb-agent-id": agent.id,
772
+ children: [
773
+ /* @__PURE__ */ jsx("span", { className: "bb-agent-panel__agent-name", children: agent.name }),
774
+ showCosts && agent.costPerRun !== void 0 && /* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__agent-cost", children: [
775
+ "$",
776
+ agent.costPerRun.toFixed(3)
777
+ ] })
778
+ ]
779
+ },
780
+ agent.id
781
+ )) }),
782
+ quickPrompts.length > 0 && /* @__PURE__ */ jsx("div", { className: "bb-agent-panel__quick-prompts", children: quickPrompts.map((qp, idx) => /* @__PURE__ */ jsxs(
783
+ "button",
784
+ {
785
+ type: "button",
786
+ className: "bb-agent-panel__quick-prompt",
787
+ onClick: () => executeQuickPrompt(qp),
788
+ disabled: isRunning || !selectedAgentId,
789
+ children: [
790
+ qp.icon && /* @__PURE__ */ jsx("span", { className: "bb-agent-panel__quick-prompt-icon", children: qp.icon }),
791
+ /* @__PURE__ */ jsx("span", { className: "bb-agent-panel__quick-prompt-label", children: qp.label })
792
+ ]
793
+ },
794
+ idx
795
+ )) }),
796
+ /* @__PURE__ */ jsxs("form", { className: "bb-agent-panel__form", onSubmit: handleSubmit, children: [
797
+ /* @__PURE__ */ jsx(
798
+ "textarea",
799
+ {
800
+ className: "bb-agent-panel__input",
801
+ value: prompt,
802
+ onChange: (e) => setPrompt(e.target.value),
803
+ placeholder,
804
+ disabled: isRunning || !selectedAgentId,
805
+ rows: 3,
806
+ "data-bb-input": "agent-prompt"
807
+ }
808
+ ),
809
+ /* @__PURE__ */ jsxs("div", { className: "bb-agent-panel__form-footer", children: [
810
+ showCosts && estimatedCost !== null && /* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__estimate", children: [
811
+ "Est. $",
812
+ estimatedCost.toFixed(3)
813
+ ] }),
814
+ /* @__PURE__ */ jsx(
815
+ "button",
816
+ {
817
+ type: "submit",
818
+ className: "bb-agent-panel__submit",
819
+ disabled: isRunning || !selectedAgentId || !prompt.trim(),
820
+ "data-bb-action": "submit-prompt",
821
+ children: isRunning ? "Running..." : "Run"
822
+ }
823
+ )
824
+ ] })
825
+ ] }),
826
+ currentRun && /* @__PURE__ */ jsxs(
827
+ "div",
828
+ {
829
+ className: `bb-agent-panel__status bb-agent-panel__status--${currentRun.status}`,
830
+ "data-bb-state": currentRun.status,
831
+ children: [
832
+ /* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__status-label", children: [
833
+ currentRun.status === "running" && "Running...",
834
+ currentRun.status === "completed" && "Completed",
835
+ currentRun.status === "failed" && "Failed",
836
+ currentRun.status === "cancelled" && "Cancelled"
837
+ ] }),
838
+ currentRun.status === "completed" && currentRun.output && /* @__PURE__ */ jsx("div", { className: "bb-agent-panel__output", "data-bb-output": "agent-output", children: currentRun.output }),
839
+ currentRun.status === "failed" && currentRun.error && /* @__PURE__ */ jsx("div", { className: "bb-agent-panel__error", children: currentRun.error })
840
+ ]
841
+ }
842
+ ),
843
+ showHistory && panelHistory.length > 0 && /* @__PURE__ */ jsxs("div", { className: "bb-agent-panel__history", children: [
844
+ /* @__PURE__ */ jsx("h4", { className: "bb-agent-panel__history-title", children: "Recent Runs" }),
845
+ /* @__PURE__ */ jsx("ul", { className: "bb-agent-panel__history-list", children: panelHistory.map((run) => /* @__PURE__ */ jsxs(
846
+ "li",
847
+ {
848
+ className: `bb-agent-panel__history-item bb-agent-panel__history-item--${run.status}`,
849
+ "data-bb-entity": "run",
850
+ "data-bb-entity-id": run.id,
851
+ children: [
852
+ /* @__PURE__ */ jsx("span", { className: "bb-agent-panel__history-agent", "data-bb-field": "agent", children: availableAgents.find((a) => a.id === run.agentId)?.name ?? run.agentId }),
853
+ /* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__history-prompt", "data-bb-field": "prompt", children: [
854
+ run.prompt.slice(0, 50),
855
+ run.prompt.length > 50 && "..."
856
+ ] }),
857
+ showCosts && run.cost !== void 0 && /* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__history-cost", "data-bb-field": "cost", children: [
858
+ "$",
859
+ run.cost.toFixed(3)
860
+ ] })
861
+ ]
862
+ },
863
+ run.id
864
+ )) })
865
+ ] }),
866
+ showCosts && /* @__PURE__ */ jsxs("div", { className: "bb-agent-panel__cost-summary", children: [
867
+ /* @__PURE__ */ jsx("span", { className: "bb-agent-panel__cost-label", children: "Session Total:" }),
868
+ /* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__cost-value", "data-bb-field": "total-cost", children: [
869
+ "$",
870
+ panelTotalCost.toFixed(3)
871
+ ] })
872
+ ] })
873
+ ] });
874
+ }
875
+ function usePlaySession({
876
+ adapter,
877
+ autoConnect = false,
878
+ timeout = 3e4,
879
+ onConnect,
880
+ onDisconnect,
881
+ onRpcResult,
882
+ onError
883
+ }) {
884
+ const { config } = useBBContext();
885
+ const [session, setSession] = useState(null);
886
+ const [status, setStatus] = useState("disconnected");
887
+ const [videoTrack, setVideoTrack] = useState(null);
888
+ const [audioTrack, setAudioTrack] = useState(null);
889
+ const [error, setError] = useState(null);
890
+ const wsRef = useRef(null);
891
+ const rpcIdRef = useRef(0);
892
+ const pendingCallsRef = useRef(/* @__PURE__ */ new Map());
893
+ const connect = useCallback(
894
+ async (options) => {
895
+ if (status === "connecting" || status === "connected") return;
896
+ setStatus("connecting");
897
+ setError(null);
898
+ const connectTimeout = options?.timeout ?? timeout;
899
+ try {
900
+ const response = await fetch(`${config.apiBaseUrl}/play-sessions`, {
901
+ method: "POST",
902
+ headers: {
903
+ "Content-Type": "application/json",
904
+ ...config.headers
905
+ },
906
+ body: JSON.stringify({ adapter })
907
+ });
908
+ if (!response.ok) {
909
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
910
+ }
911
+ const sessionData = await response.json();
912
+ const newSession = {
913
+ id: sessionData.id,
914
+ adapter,
915
+ capabilityToken: sessionData.capabilityToken,
916
+ createdAt: Date.now(),
917
+ expiresAt: sessionData.expiresAt,
918
+ livekitUrl: sessionData.livekitUrl,
919
+ livekitToken: sessionData.livekitToken
920
+ };
921
+ setSession(newSession);
922
+ const wsUrl = sessionData.wsUrl ?? `${config.apiBaseUrl.replace("http", "ws")}/play-sessions/${newSession.id}/ws`;
923
+ const ws = new WebSocket(wsUrl);
924
+ wsRef.current = ws;
925
+ await new Promise((resolve, reject) => {
926
+ const timeoutId = setTimeout(() => {
927
+ ws.close();
928
+ reject(new Error("Connection timeout"));
929
+ }, connectTimeout);
930
+ ws.onopen = () => {
931
+ clearTimeout(timeoutId);
932
+ resolve();
933
+ };
934
+ ws.onerror = () => {
935
+ clearTimeout(timeoutId);
936
+ reject(new Error("WebSocket connection failed"));
937
+ };
938
+ });
939
+ ws.onmessage = (event) => {
940
+ try {
941
+ const message = JSON.parse(event.data);
942
+ if ("id" in message && pendingCallsRef.current.has(message.id)) {
943
+ const pending = pendingCallsRef.current.get(message.id);
944
+ pendingCallsRef.current.delete(message.id);
945
+ pending.resolve(message);
946
+ onRpcResult?.(message);
947
+ }
948
+ } catch {
949
+ }
950
+ };
951
+ ws.onclose = () => {
952
+ setStatus("disconnected");
953
+ setSession(null);
954
+ wsRef.current = null;
955
+ onDisconnect?.();
956
+ };
957
+ ws.onerror = () => {
958
+ setError("WebSocket error");
959
+ onError?.(new Error("WebSocket error"));
960
+ };
961
+ if (newSession.livekitUrl && newSession.livekitToken) {
962
+ }
963
+ setStatus("connected");
964
+ onConnect?.(newSession);
965
+ } catch (err) {
966
+ const errorMessage = err instanceof Error ? err.message : "Connection failed";
967
+ setStatus("error");
968
+ setError(errorMessage);
969
+ onError?.(err instanceof Error ? err : new Error(errorMessage));
970
+ }
971
+ },
972
+ [adapter, config, status, timeout, onConnect, onDisconnect, onRpcResult, onError]
973
+ );
974
+ const disconnect = useCallback(async () => {
975
+ if (wsRef.current) {
976
+ wsRef.current.close();
977
+ wsRef.current = null;
978
+ }
979
+ if (session) {
980
+ try {
981
+ await fetch(`${config.apiBaseUrl}/play-sessions/${session.id}`, {
982
+ method: "DELETE",
983
+ headers: config.headers
984
+ });
985
+ } catch {
986
+ }
987
+ }
988
+ setSession(null);
989
+ setStatus("disconnected");
990
+ setVideoTrack(null);
991
+ setAudioTrack(null);
992
+ onDisconnect?.();
993
+ }, [session, config, onDisconnect]);
994
+ const call = useCallback(
995
+ (method, params) => {
996
+ return new Promise((resolve, reject) => {
997
+ if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {
998
+ reject(new Error("Not connected"));
999
+ return;
1000
+ }
1001
+ const id = ++rpcIdRef.current;
1002
+ const request = {
1003
+ jsonrpc: "2.0",
1004
+ id,
1005
+ method,
1006
+ params: params ?? {}
1007
+ };
1008
+ pendingCallsRef.current.set(id, {
1009
+ resolve,
1010
+ reject
1011
+ });
1012
+ wsRef.current.send(JSON.stringify(request));
1013
+ setTimeout(() => {
1014
+ if (pendingCallsRef.current.has(id)) {
1015
+ pendingCallsRef.current.delete(id);
1016
+ reject(new Error("RPC call timeout"));
1017
+ }
1018
+ }, 3e4);
1019
+ });
1020
+ },
1021
+ []
1022
+ );
1023
+ const observe = useCallback(
1024
+ async (key) => {
1025
+ const response = await call(`observe.${key}`);
1026
+ if (response.error) {
1027
+ throw new Error(response.error.message);
1028
+ }
1029
+ return response.result;
1030
+ },
1031
+ [call]
1032
+ );
1033
+ const act = useCallback(
1034
+ async (action, params) => {
1035
+ const response = await call(`act.${action}`, params);
1036
+ if (response.error) {
1037
+ throw new Error(response.error.message);
1038
+ }
1039
+ return response.result;
1040
+ },
1041
+ [call]
1042
+ );
1043
+ useEffect(() => {
1044
+ if (autoConnect) {
1045
+ connect();
1046
+ }
1047
+ }, [autoConnect]);
1048
+ useEffect(() => {
1049
+ return () => {
1050
+ if (wsRef.current) {
1051
+ wsRef.current.close();
1052
+ }
1053
+ };
1054
+ }, []);
1055
+ return {
1056
+ session,
1057
+ status,
1058
+ videoTrack,
1059
+ audioTrack,
1060
+ call,
1061
+ observe,
1062
+ act,
1063
+ connect,
1064
+ disconnect,
1065
+ isConnected: status === "connected",
1066
+ error
1067
+ };
1068
+ }
1069
+ function PlaySession({
1070
+ adapter,
1071
+ autoConnect = false,
1072
+ timeout,
1073
+ onSessionStart,
1074
+ onSessionEnd,
1075
+ onRpcResult,
1076
+ onError,
1077
+ children,
1078
+ className
1079
+ }) {
1080
+ const videoRef = useRef(null);
1081
+ const {
1082
+ session,
1083
+ status,
1084
+ videoTrack,
1085
+ audioTrack,
1086
+ call,
1087
+ observe,
1088
+ act,
1089
+ connect,
1090
+ disconnect,
1091
+ isConnected,
1092
+ error
1093
+ } = usePlaySession({
1094
+ adapter,
1095
+ autoConnect,
1096
+ timeout,
1097
+ onConnect: onSessionStart,
1098
+ onDisconnect: onSessionEnd,
1099
+ onRpcResult,
1100
+ onError
1101
+ });
1102
+ useEffect(() => {
1103
+ if (videoRef.current && videoTrack) {
1104
+ const stream = new MediaStream([videoTrack]);
1105
+ videoRef.current.srcObject = stream;
1106
+ }
1107
+ }, [videoTrack]);
1108
+ useEffect(() => {
1109
+ if (videoRef.current && audioTrack) {
1110
+ const currentStream = videoRef.current.srcObject;
1111
+ if (currentStream) {
1112
+ currentStream.addTrack(audioTrack);
1113
+ }
1114
+ }
1115
+ }, [audioTrack]);
1116
+ return /* @__PURE__ */ jsx(
1117
+ "div",
1118
+ {
1119
+ className: `bb-play-session ${className ?? ""}`,
1120
+ "data-bb-state": status,
1121
+ "data-bb-adapter": adapter,
1122
+ "data-bb-session-id": session?.id,
1123
+ children: children({
1124
+ session,
1125
+ status,
1126
+ call,
1127
+ observe,
1128
+ act,
1129
+ connect,
1130
+ disconnect,
1131
+ videoRef,
1132
+ isConnected,
1133
+ error
1134
+ })
1135
+ }
1136
+ );
1137
+ }
1138
+
1139
+ // src/components/ClusterHero/config.ts
1140
+ var CLUSTER_DEV_PORTS = {
1141
+ alexandria: 3001,
1142
+ alpha: 3002,
1143
+ opus: 3003,
1144
+ baia: 3004,
1145
+ kdot: 3005,
1146
+ aegis: 3006,
1147
+ providence: 3007
1148
+ };
1149
+ function getClusterDocsUrl(clusterId) {
1150
+ if (typeof window !== "undefined" && window.location.hostname === "localhost") {
1151
+ return `http://localhost:${CLUSTER_DEV_PORTS[clusterId]}`;
1152
+ }
1153
+ return `https://${clusterId}.backbay.io`;
1154
+ }
1155
+ var CLUSTER_CONFIGS = {
1156
+ alexandria: {
1157
+ id: "alexandria",
1158
+ name: "Alexandria",
1159
+ tagline: "Where knowledge compounds",
1160
+ latinMotto: "SEQUERE FILUM",
1161
+ sigilSrc: "/sigils/alexandria.svg",
1162
+ videoSrc: "/videos/clusters/alexandria.mp4",
1163
+ videoPoster: "/videos/clusters/alexandria-poster.jpg",
1164
+ accentColor: "#C9A227",
1165
+ accentColorRGB: "201, 162, 39",
1166
+ atmosphere: {
1167
+ dustMotes: {
1168
+ colors: ["#C9A227", "#E8D5A3", "#8B7355"],
1169
+ density: 0.6,
1170
+ speed: 0.3
1171
+ },
1172
+ light: {
1173
+ type: "godrays",
1174
+ color: "#C9A227",
1175
+ intensity: 0.7,
1176
+ source: { x: 0.8, y: 0.1 }
1177
+ }
1178
+ },
1179
+ buttons: [
1180
+ { label: "Launch", href: "/clusters/alexandria", variant: "primary" },
1181
+ { label: "Docs", href: "https://alexandria.backbay.io", variant: "secondary", external: true },
1182
+ { label: "Governance", href: "/governance/alexandria", variant: "ghost" }
1183
+ ],
1184
+ // Briefing
1185
+ description: "The decentralized knowledge marketplace. Publish, lease, and compound intelligence artifacts.",
1186
+ capabilities: ["PUBLISH", "LEASE", "COMPOUND"],
1187
+ fastPath: { label: "Start a Knowledge Compound", href: "/clusters/alexandria/compound/new" },
1188
+ status: { network: "STABLE", verification: "ON", fees: "2%" },
1189
+ // Live
1190
+ liveModule: "market",
1191
+ liveContent: "3 new blueprints published today",
1192
+ // Metrics
1193
+ metrics: { realms: 847, output24h: "2.4M", rank: 12 }
1194
+ },
1195
+ alpha: {
1196
+ id: "alpha",
1197
+ name: "Alpha",
1198
+ tagline: "Where signals become strategy",
1199
+ latinMotto: "ALPHA IN MOTU",
1200
+ sigilSrc: "/sigils/alpha.svg",
1201
+ videoSrc: "/videos/clusters/alpha.mp4",
1202
+ videoPoster: "/videos/clusters/alpha-poster.jpg",
1203
+ accentColor: "#E8E8E8",
1204
+ accentColorRGB: "232, 232, 232",
1205
+ atmosphere: {
1206
+ fog: {
1207
+ type: "volumetric",
1208
+ color: "#E8E8E8",
1209
+ intensity: 0.5
1210
+ }
1211
+ },
1212
+ buttons: [
1213
+ { label: "Launch", href: "/clusters/alpha", variant: "primary" },
1214
+ { label: "Docs", href: "https://alpha.backbay.io", variant: "secondary", external: true },
1215
+ { label: "Governance", href: "/governance/alpha", variant: "ghost" }
1216
+ ],
1217
+ // Briefing
1218
+ description: "A social exchange for research-grade finance. Models, signals, and playbooks\u2014shared, challenged, and refined in public.",
1219
+ capabilities: ["BACKTEST", "PRICE", "EXECUTE"],
1220
+ fastPath: { label: "Explore strategy marketplace", href: "/clusters/alpha/market" },
1221
+ status: { network: "STABLE", verification: "ON", fees: "1.5%" },
1222
+ // Live
1223
+ liveModule: "live",
1224
+ liveContent: "Live: 218 strategies \u2022 24h volume $3.1B",
1225
+ // Metrics
1226
+ metrics: { realms: 234, output24h: "4.8M", rank: 3 }
1227
+ },
1228
+ opus: {
1229
+ id: "opus",
1230
+ name: "Opus",
1231
+ tagline: "Where care meets code",
1232
+ latinMotto: "SALUS PER MACHINAM",
1233
+ sigilSrc: "/sigils/opus.svg",
1234
+ videoSrc: "/videos/clusters/opus.mp4",
1235
+ videoPoster: "/videos/clusters/opus-poster.jpg",
1236
+ accentColor: "#B87333",
1237
+ accentColorRGB: "184, 115, 51",
1238
+ atmosphere: {
1239
+ dustMotes: {
1240
+ colors: ["#B87333", "#D4956A", "#8B5A2B"],
1241
+ density: 0.8,
1242
+ speed: 0.2
1243
+ },
1244
+ light: {
1245
+ type: "bloom",
1246
+ color: "#B87333",
1247
+ intensity: 0.6
1248
+ }
1249
+ },
1250
+ buttons: [
1251
+ { label: "Launch", href: "/clusters/opus", variant: "primary" },
1252
+ { label: "Docs", href: "https://opus.backbay.io", variant: "secondary", external: true },
1253
+ { label: "Governance", href: "/governance/opus", variant: "ghost" }
1254
+ ],
1255
+ // Briefing
1256
+ description: "The clinic-to-code commons. Practical health systems, shared and iterated together.",
1257
+ capabilities: ["DIAGNOSE", "COORDINATE", "PRODUCE"],
1258
+ fastPath: { label: "Explore the Exchange", href: "/clusters/opus/exchange" },
1259
+ status: { network: "STABLE", verification: "HIPAA", fees: "2%" },
1260
+ // Live
1261
+ liveModule: "live",
1262
+ liveContent: "New: Autonomous diagnostic pipeline \u2022 12 protocols deployed",
1263
+ // Metrics
1264
+ metrics: { realms: 156, output24h: "892K" }
1265
+ },
1266
+ baia: {
1267
+ id: "baia",
1268
+ name: "Baia",
1269
+ tagline: "Where imagination renders",
1270
+ latinMotto: "ARS EX MACHINA",
1271
+ sigilSrc: "/sigils/baia.svg",
1272
+ videoSrc: "/videos/clusters/baia.mp4",
1273
+ videoPoster: "/videos/clusters/baia-poster.jpg",
1274
+ accentColor: "#D4AF37",
1275
+ accentColorRGB: "212, 175, 55",
1276
+ atmosphere: {
1277
+ light: {
1278
+ type: "godrays",
1279
+ color: "#D4AF37",
1280
+ intensity: 0.8,
1281
+ source: { x: 0.5, y: 0 }
1282
+ }
1283
+ },
1284
+ buttons: [
1285
+ { label: "Launch", href: "/clusters/baia", variant: "primary" },
1286
+ { label: "Docs", href: "https://baia.backbay.io", variant: "secondary", external: true },
1287
+ { label: "Governance", href: "/governance/baia", variant: "ghost" }
1288
+ ],
1289
+ // Briefing
1290
+ description: "A social market for generative culture. Artists and builders publish, collaborate, and curate evolving collections.",
1291
+ capabilities: ["GENERATE", "COMPOSE", "RENDER"],
1292
+ fastPath: { label: "Open the Studio", href: "/clusters/baia/studio" },
1293
+ status: { network: "STABLE", verification: "ON", fees: "2.5%" },
1294
+ // Live
1295
+ liveModule: "market",
1296
+ liveContent: "Trending: Neural symphony generator \u2022 847 works minted today",
1297
+ // Metrics
1298
+ metrics: { realms: 89, output24h: "124K", rank: 47 }
1299
+ },
1300
+ kdot: {
1301
+ id: "kdot",
1302
+ name: "KDoT",
1303
+ tagline: "Kernel design of thought",
1304
+ latinMotto: "MENS \u2022 MACHINA \u2022 DEUS",
1305
+ sigilSrc: "/sigils/kdot.svg",
1306
+ videoSrc: "/videos/clusters/kdot.mp4",
1307
+ videoPoster: "/videos/clusters/kdot-poster.jpg",
1308
+ accentColor: "#00D4AA",
1309
+ accentColorRGB: "0, 212, 170",
1310
+ atmosphere: {
1311
+ fog: {
1312
+ type: "mist",
1313
+ color: "#00D4AA",
1314
+ intensity: 0.4
1315
+ }
1316
+ },
1317
+ buttons: [
1318
+ { label: "Launch", href: "/clusters/kdot", variant: "primary" },
1319
+ { label: "Docs", href: "https://kdot.backbay.io", variant: "secondary", external: true },
1320
+ { label: "Status", href: "/status/kdot", variant: "ghost" }
1321
+ ],
1322
+ // Briefing
1323
+ description: "Compile thought into territory. Ship verifiable services. Forge living culture. Spin up economies.\nKernel Design of Thought: where creativity becomes industry.",
1324
+ capabilities: ["DESIGN", "SYNTHESIZE", "ALIGN"],
1325
+ fastPath: { label: "Open the Kernel", href: "/clusters/kdot/topology" },
1326
+ status: { network: "OPTIMAL", verification: "ON", fees: "0.1%" },
1327
+ // Live
1328
+ liveModule: "live",
1329
+ liveContent: "The Cathedral awakens \u2022 12 kernels compiled today",
1330
+ // Metrics
1331
+ metrics: { realms: 1247, output24h: "8.4PB", rank: 1 }
1332
+ },
1333
+ aegis: {
1334
+ id: "aegis",
1335
+ name: "Aegis",
1336
+ tagline: "Shield of the realm",
1337
+ latinMotto: "TUTELA PERPETUA",
1338
+ sigilSrc: "/sigils/aegis.svg",
1339
+ videoSrc: "/videos/clusters/aegis.mp4",
1340
+ videoPoster: "/videos/clusters/aegis-poster.jpg",
1341
+ accentColor: "#4A7BF7",
1342
+ accentColorRGB: "74, 123, 247",
1343
+ atmosphere: {
1344
+ light: {
1345
+ type: "bloom",
1346
+ color: "#4A7BF7",
1347
+ intensity: 0.5
1348
+ }
1349
+ },
1350
+ buttons: [
1351
+ { label: "Launch", href: "/clusters/aegis", variant: "primary" },
1352
+ { label: "Docs", href: "https://aegis.backbay.io", variant: "secondary", external: true },
1353
+ { label: "Audit", href: "/audit/aegis", variant: "ghost" }
1354
+ ],
1355
+ // Briefing
1356
+ description: "The EDR layer for agent economies. Aegis is a trust-minimized distributed security mesh to enable autonomous production at scale.",
1357
+ capabilities: ["PROTECT", "DETECT", "RESPOND"],
1358
+ fastPath: { label: "View threat dashboard", href: "/clusters/aegis/threats" },
1359
+ status: { network: "SECURE", verification: "ENFORCED", fees: "1%" },
1360
+ // Live
1361
+ liveModule: "governance",
1362
+ liveContent: "Security Proposal #7 \u2014 Policy update pending review",
1363
+ // Metrics
1364
+ metrics: { realms: 312, output24h: "2.1B threats blocked", rank: 2 }
1365
+ },
1366
+ providence: {
1367
+ id: "providence",
1368
+ name: "Providence",
1369
+ tagline: "Foresight is defense",
1370
+ latinMotto: "PRAEVIDEO ERGO PROTEGO",
1371
+ sigilSrc: "/sigils/providence.svg",
1372
+ videoSrc: "/videos/clusters/providence.mp4",
1373
+ videoPoster: "/videos/clusters/providence-poster.jpg",
1374
+ accentColor: "#00D4AA",
1375
+ accentColorRGB: "0, 212, 170",
1376
+ atmosphere: {
1377
+ light: {
1378
+ type: "godrays",
1379
+ color: "#00D4AA",
1380
+ intensity: 0.5,
1381
+ source: { x: 0.55, y: 0.05 }
1382
+ },
1383
+ fog: {
1384
+ type: "mist",
1385
+ color: "#00D4AA",
1386
+ intensity: 0.25
1387
+ }
1388
+ },
1389
+ buttons: [
1390
+ { label: "Launch", href: "/clusters/providence", variant: "primary" },
1391
+ { label: "Docs", href: "https://providence.backbay.io", variant: "secondary", external: true },
1392
+ { label: "Threat Intel", href: "/providence/threats", variant: "ghost" }
1393
+ ],
1394
+ description: "The EDR layer for agent economies. Aegis is a trust-minimized security distributed security for autonomous production.",
1395
+ capabilities: ["PREDICT", "RESPOND", "DEFEND"],
1396
+ fastPath: { label: "View threat dashboard", href: "/clusters/providence/threats" },
1397
+ status: { network: "SECURE", verification: "ENFORCED", fees: "1%" },
1398
+ liveModule: "live",
1399
+ liveContent: "24/7 monitoring active \u2022 847K threats analyzed today",
1400
+ metrics: { realms: 96, output24h: "38K", rank: 19 }
1401
+ }
1402
+ };
1403
+ function getClusterConfig(clusterId) {
1404
+ return CLUSTER_CONFIGS[clusterId];
1405
+ }
1406
+ function getClusterConfigWithResolvedUrls(clusterId) {
1407
+ const config = CLUSTER_CONFIGS[clusterId];
1408
+ const docsUrl = getClusterDocsUrl(clusterId);
1409
+ return {
1410
+ ...config,
1411
+ buttons: config.buttons.map(
1412
+ (button) => button.label === "Docs" ? { ...button, href: docsUrl } : button
1413
+ )
1414
+ };
1415
+ }
1416
+ function cn(...inputs) {
1417
+ return twMerge(clsx(inputs));
1418
+ }
1419
+ function prefersReducedMotion() {
1420
+ if (typeof window === "undefined") return false;
1421
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
1422
+ }
1423
+ var UiThemeContext = React3.createContext(null);
1424
+ function useUiTheme() {
1425
+ const context = React3.useContext(UiThemeContext);
1426
+ if (!context) {
1427
+ throw new Error("useUiTheme must be used within a UiThemeProvider");
1428
+ }
1429
+ return context;
1430
+ }
1431
+ function useAmbientTokens() {
1432
+ const { theme } = useUiTheme();
1433
+ return theme.ambient;
1434
+ }
1435
+ function generateMotes(count, colors, sizeRange, speed) {
1436
+ return Array.from({ length: count }, (_, i) => ({
1437
+ id: i,
1438
+ x: Math.random() * 100,
1439
+ y: Math.random() * 100,
1440
+ size: sizeRange[0] + Math.random() * (sizeRange[1] - sizeRange[0]),
1441
+ color: colors[Math.floor(Math.random() * colors.length)],
1442
+ delay: Math.random() * 5,
1443
+ duration: (8 + Math.random() * 8) / speed,
1444
+ driftX: (Math.random() - 0.5) * 30,
1445
+ driftY: -20 - Math.random() * 40
1446
+ // Upward drift
1447
+ }));
1448
+ }
1449
+ var MoteParticle = React3.memo(function MoteParticle2({
1450
+ mote,
1451
+ speedMultiplier
1452
+ }) {
1453
+ const reducedMotion = useReducedMotion();
1454
+ if (reducedMotion) {
1455
+ return /* @__PURE__ */ jsx(
1456
+ "div",
1457
+ {
1458
+ className: "absolute rounded-full",
1459
+ style: {
1460
+ left: `${mote.x}%`,
1461
+ top: `${mote.y}%`,
1462
+ width: mote.size,
1463
+ height: mote.size,
1464
+ backgroundColor: mote.color,
1465
+ opacity: 0.3
1466
+ }
1467
+ }
1468
+ );
1469
+ }
1470
+ return /* @__PURE__ */ jsx(
1471
+ motion.div,
1472
+ {
1473
+ className: "absolute rounded-full will-change-transform",
1474
+ style: {
1475
+ left: `${mote.x}%`,
1476
+ top: `${mote.y}%`,
1477
+ width: mote.size,
1478
+ height: mote.size,
1479
+ backgroundColor: mote.color,
1480
+ filter: `blur(${mote.size > 4 ? 1 : 0}px)`
1481
+ },
1482
+ initial: { opacity: 0, scale: 0.5 },
1483
+ animate: {
1484
+ opacity: [0, 0.6, 0.4, 0.7, 0],
1485
+ scale: [0.5, 1, 0.9, 1.1, 0.8],
1486
+ x: [0, mote.driftX * 0.3, mote.driftX * 0.7, mote.driftX],
1487
+ y: [0, mote.driftY * 0.3, mote.driftY * 0.7, mote.driftY]
1488
+ },
1489
+ transition: {
1490
+ duration: mote.duration / speedMultiplier,
1491
+ delay: mote.delay,
1492
+ repeat: Infinity,
1493
+ ease: "easeInOut"
1494
+ }
1495
+ }
1496
+ );
1497
+ });
1498
+ function DustMotesLayer({
1499
+ colors: propColors,
1500
+ density: propDensity,
1501
+ speed: propSpeed,
1502
+ sizeRange: propSizeRange,
1503
+ className,
1504
+ disabled = false
1505
+ }) {
1506
+ const ambientTokens = useAmbientTokens();
1507
+ const reducedMotion = prefersReducedMotion();
1508
+ const colors = propColors ?? ambientTokens.particleColors;
1509
+ const density = propDensity ?? ambientTokens.particleDensity;
1510
+ const speed = propSpeed ?? ambientTokens.particleSpeed;
1511
+ const sizeRange = propSizeRange ?? ambientTokens.particleSizeRange;
1512
+ const [motes, setMotes] = React3.useState([]);
1513
+ React3.useEffect(() => {
1514
+ if (disabled || reducedMotion) {
1515
+ setMotes([]);
1516
+ return;
1517
+ }
1518
+ const viewportArea = typeof window !== "undefined" ? window.innerWidth * window.innerHeight / 1e4 : 100;
1519
+ const count = Math.floor(viewportArea * density * 2);
1520
+ const clampedCount = Math.min(Math.max(count, 15), 80);
1521
+ setMotes(generateMotes(clampedCount, colors, sizeRange, speed));
1522
+ }, [colors, density, disabled, reducedMotion, sizeRange, speed]);
1523
+ if (disabled || motes.length === 0) {
1524
+ return null;
1525
+ }
1526
+ return /* @__PURE__ */ jsxs(
1527
+ "div",
1528
+ {
1529
+ className: cn("pointer-events-none absolute inset-0 overflow-hidden", className),
1530
+ "aria-hidden": "true",
1531
+ children: [
1532
+ /* @__PURE__ */ jsx(
1533
+ "div",
1534
+ {
1535
+ className: "absolute inset-0",
1536
+ style: {
1537
+ background: ambientTokens.horizonGradient
1538
+ }
1539
+ }
1540
+ ),
1541
+ motes.map((mote) => /* @__PURE__ */ jsx(MoteParticle, { mote, speedMultiplier: speed }, mote.id)),
1542
+ /* @__PURE__ */ jsx(
1543
+ "div",
1544
+ {
1545
+ className: "absolute inset-0 opacity-30",
1546
+ style: {
1547
+ background: `
1548
+ radial-gradient(
1549
+ ellipse 60% 100% at 70% 0%,
1550
+ ${colors[0]}15,
1551
+ transparent 70%
1552
+ )
1553
+ `
1554
+ }
1555
+ }
1556
+ )
1557
+ ]
1558
+ }
1559
+ );
1560
+ }
1561
+
1562
+ // src/primitives/environment/shared/types.ts
1563
+ var PERFORMANCE_PRESETS = {
1564
+ high: { tier: "high", maxParticles: 2e3, useShaders: true, targetFPS: 60 },
1565
+ medium: { tier: "medium", maxParticles: 800, useShaders: true, targetFPS: 60 },
1566
+ low: { tier: "low", maxParticles: 300, useShaders: false, targetFPS: 30 },
1567
+ minimal: { tier: "minimal", maxParticles: 0, useShaders: false, targetFPS: 0 }
1568
+ };
1569
+
1570
+ // src/primitives/environment/shared/performance.ts
1571
+ function detectPerformanceTier() {
1572
+ if (typeof window === "undefined") return "medium";
1573
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
1574
+ return "minimal";
1575
+ }
1576
+ const nav = navigator;
1577
+ if (nav.deviceMemory && nav.deviceMemory < 4) {
1578
+ return "low";
1579
+ }
1580
+ if (navigator.hardwareConcurrency && navigator.hardwareConcurrency < 4) {
1581
+ return "low";
1582
+ }
1583
+ const isMobile = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
1584
+ if (isMobile) return "low";
1585
+ return "medium";
1586
+ }
1587
+ function getPerformanceConfig(tier) {
1588
+ const detected = detectPerformanceTier();
1589
+ return PERFORMANCE_PRESETS[detected];
1590
+ }
1591
+
1592
+ // src/primitives/environment/shared/noise.ts
1593
+ var NOISE_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
1594
+ <filter id="n">
1595
+ <feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="3" seed="2" stitchTiles="stitch" />
1596
+ <feColorMatrix type="saturate" values="0" />
1597
+ </filter>
1598
+ <rect width="200" height="200" filter="url(#n)" opacity="0.55" />
1599
+ </svg>`;
1600
+ var NOISE_DATA_URL = `data:image/svg+xml,${encodeURIComponent(NOISE_SVG)}`;
1601
+
1602
+ // src/primitives/environment/VolumetricLight/types.ts
1603
+ var LIGHT_CONFIGS = {
1604
+ godrays: { defaultColor: "#fffbe6", defaultIntensity: 0.6, animated: true, blendMode: "screen" },
1605
+ shaft: { defaultColor: "#ffffff", defaultIntensity: 0.5, animated: false, blendMode: "screen" },
1606
+ bloom: { defaultColor: "#ffffff", defaultIntensity: 0.4, animated: false, blendMode: "screen" },
1607
+ flare: { defaultColor: "#ffe4b5", defaultIntensity: 0.7, animated: true, blendMode: "screen" },
1608
+ caustics: { defaultColor: "#00d4ff", defaultIntensity: 0.4, animated: true, blendMode: "overlay" },
1609
+ scanner: { defaultColor: "#00ff00", defaultIntensity: 0.6, animated: true, blendMode: "screen" },
1610
+ neon: { defaultColor: "#ff00ff", defaultIntensity: 0.8, animated: true, blendMode: "screen" },
1611
+ spotlight: { defaultColor: "#ffffff", defaultIntensity: 0.7, animated: false, blendMode: "screen" },
1612
+ rim: { defaultColor: "#00f0ff", defaultIntensity: 0.5, animated: false, blendMode: "screen" },
1613
+ laser: { defaultColor: "#ff0000", defaultIntensity: 0.9, animated: true, blendMode: "screen" }
1614
+ };
1615
+ function VolumetricLight({
1616
+ type,
1617
+ source = { x: 0.5, y: 0 },
1618
+ color: propColor,
1619
+ intensity = 0.5,
1620
+ decay = 0.5,
1621
+ angle = 0,
1622
+ width = 0.3,
1623
+ animated: propAnimated,
1624
+ stylePreset = "ui",
1625
+ enabled = true,
1626
+ className,
1627
+ style
1628
+ }) {
1629
+ const reducedMotion = useReducedMotion();
1630
+ const perfConfig = getPerformanceConfig();
1631
+ const [time, setTime] = React3.useState(0);
1632
+ const config = LIGHT_CONFIGS[type];
1633
+ const color = propColor ?? config.defaultColor;
1634
+ const shouldAnimate = (propAnimated ?? config.animated) && !reducedMotion && perfConfig.tier !== "minimal";
1635
+ React3.useEffect(() => {
1636
+ if (!shouldAnimate || !enabled) return;
1637
+ let frame;
1638
+ const animate = () => {
1639
+ setTime((prev) => prev + 0.016);
1640
+ frame = requestAnimationFrame(animate);
1641
+ };
1642
+ frame = requestAnimationFrame(animate);
1643
+ return () => cancelAnimationFrame(frame);
1644
+ }, [shouldAnimate, enabled]);
1645
+ const lightStyle = React3.useMemo(() => {
1646
+ const opacity = intensity * config.defaultIntensity;
1647
+ const d = Math.max(0, Math.min(1, decay));
1648
+ switch (type) {
1649
+ case "godrays":
1650
+ return {
1651
+ background: `conic-gradient(from ${angle}deg at ${source.x * 100}% ${source.y * 100}%,
1652
+ ${color}${Math.round(opacity * 0.4 * 255).toString(16).padStart(2, "0")} 0deg,
1653
+ transparent 15deg,
1654
+ ${color}${Math.round(opacity * 0.3 * 255).toString(16).padStart(2, "0")} 30deg,
1655
+ transparent 45deg,
1656
+ ${color}${Math.round(opacity * 0.35 * 255).toString(16).padStart(2, "0")} 60deg,
1657
+ transparent 75deg,
1658
+ ${color}${Math.round(opacity * 0.25 * 255).toString(16).padStart(2, "0")} 90deg,
1659
+ transparent 105deg
1660
+ )`,
1661
+ mixBlendMode: config.blendMode
1662
+ };
1663
+ case "shaft":
1664
+ return {
1665
+ background: `linear-gradient(${angle}deg,
1666
+ transparent ${(source.x - width / 2) * 100}%,
1667
+ ${color}${Math.round(opacity * 0.5 * 255).toString(16).padStart(2, "0")} ${source.x * 100}%,
1668
+ transparent ${(source.x + width / 2) * 100}%
1669
+ )`,
1670
+ mixBlendMode: config.blendMode
1671
+ };
1672
+ case "bloom": {
1673
+ const bloomInner = 18 + d * 22;
1674
+ const bloomMid = 42 + d * 24;
1675
+ return {
1676
+ background: `radial-gradient(circle at ${source.x * 100}% ${source.y * 100}%,
1677
+ ${color}${Math.round(opacity * 0.6 * 255).toString(16).padStart(2, "0")},
1678
+ ${color}${Math.round(opacity * 0.3 * 255).toString(16).padStart(2, "0")} ${bloomInner}%,
1679
+ transparent ${bloomMid}%
1680
+ )`,
1681
+ mixBlendMode: config.blendMode,
1682
+ filter: "blur(20px)"
1683
+ };
1684
+ }
1685
+ case "flare":
1686
+ const flareOffset = Math.sin(time * 2) * 5;
1687
+ return {
1688
+ background: `
1689
+ radial-gradient(ellipse 20% 5% at ${source.x * 100}% ${source.y * 100 + flareOffset}%, ${color}${Math.round(opacity * 0.8 * 255).toString(16).padStart(2, "0")}, transparent),
1690
+ radial-gradient(ellipse 5% 20% at ${source.x * 100}% ${source.y * 100}%, ${color}${Math.round(opacity * 0.6 * 255).toString(16).padStart(2, "0")}, transparent),
1691
+ radial-gradient(circle at ${source.x * 100}% ${source.y * 100}%, ${color}${Math.round(opacity * 0.4 * 255).toString(16).padStart(2, "0")}, transparent 20%)
1692
+ `,
1693
+ mixBlendMode: config.blendMode
1694
+ };
1695
+ case "caustics":
1696
+ const causticPhase = time * 0.5;
1697
+ return {
1698
+ background: `
1699
+ radial-gradient(ellipse at ${50 + Math.sin(causticPhase) * 20}% ${50 + Math.cos(causticPhase * 1.3) * 20}%, ${color}${Math.round(opacity * 0.3 * 255).toString(16).padStart(2, "0")}, transparent 40%),
1700
+ radial-gradient(ellipse at ${50 + Math.cos(causticPhase * 0.7) * 25}% ${50 + Math.sin(causticPhase * 1.1) * 25}%, ${color}${Math.round(opacity * 0.25 * 255).toString(16).padStart(2, "0")}, transparent 35%)
1701
+ `,
1702
+ mixBlendMode: config.blendMode
1703
+ };
1704
+ case "scanner":
1705
+ const scanAngle = time * 60 % 360;
1706
+ return {
1707
+ background: `conic-gradient(from ${scanAngle}deg at ${source.x * 100}% ${source.y * 100}%,
1708
+ ${color}${Math.round(opacity * 0.6 * 255).toString(16).padStart(2, "0")} 0deg,
1709
+ transparent 30deg,
1710
+ transparent 360deg
1711
+ )`,
1712
+ mixBlendMode: config.blendMode
1713
+ };
1714
+ case "neon":
1715
+ const flickerIntensity = 0.9 + Math.sin(time * 20) * 0.1;
1716
+ return {
1717
+ background: `linear-gradient(${angle}deg, transparent 40%, ${color}${Math.round(opacity * flickerIntensity * 0.8 * 255).toString(16).padStart(2, "0")} 50%, transparent 60%)`,
1718
+ boxShadow: `0 0 30px ${color}${Math.round(opacity * flickerIntensity * 0.5 * 255).toString(16).padStart(2, "0")}, 0 0 60px ${color}${Math.round(opacity * flickerIntensity * 0.3 * 255).toString(16).padStart(2, "0")}`,
1719
+ mixBlendMode: config.blendMode
1720
+ };
1721
+ case "spotlight": {
1722
+ const spotMid = 40 + d * 35;
1723
+ return {
1724
+ background: `radial-gradient(ellipse ${width * 100}% ${width * 150}% at ${source.x * 100}% ${source.y * 100}%,
1725
+ ${color}${Math.round(opacity * 0.7 * 255).toString(16).padStart(2, "0")},
1726
+ ${color}${Math.round(opacity * 0.3 * 255).toString(16).padStart(2, "0")} ${spotMid}%,
1727
+ transparent 100%
1728
+ )`,
1729
+ mixBlendMode: config.blendMode
1730
+ };
1731
+ }
1732
+ case "rim":
1733
+ return {
1734
+ boxShadow: `inset 0 0 ${60 * intensity}px ${color}${Math.round(opacity * 0.6 * 255).toString(16).padStart(2, "0")}`,
1735
+ mixBlendMode: config.blendMode
1736
+ };
1737
+ case "laser":
1738
+ const laserOffset = Math.sin(time * 3) * 10;
1739
+ return {
1740
+ background: `linear-gradient(${angle + laserOffset}deg,
1741
+ transparent 49%,
1742
+ ${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")} 49.5%,
1743
+ ${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")} 50.5%,
1744
+ transparent 51%
1745
+ )`,
1746
+ mixBlendMode: config.blendMode
1747
+ };
1748
+ default:
1749
+ return {};
1750
+ }
1751
+ }, [type, source, color, intensity, decay, angle, width, time, config]);
1752
+ if (!enabled) return null;
1753
+ return /* @__PURE__ */ jsx(
1754
+ "div",
1755
+ {
1756
+ className: cn("pointer-events-none absolute inset-0", className),
1757
+ style: { ...lightStyle, ...style },
1758
+ "aria-hidden": "true",
1759
+ children: stylePreset === "cinematic" && /* @__PURE__ */ jsx(
1760
+ "div",
1761
+ {
1762
+ className: "absolute inset-0",
1763
+ style: {
1764
+ backgroundImage: `url("${NOISE_DATA_URL}")`,
1765
+ backgroundRepeat: "repeat",
1766
+ backgroundSize: "240px 240px",
1767
+ backgroundPosition: `${time * 160}px ${time * 110}px`,
1768
+ opacity: Math.min(0.12, 0.03 + intensity * 0.06),
1769
+ mixBlendMode: "overlay",
1770
+ filter: "blur(0.4px) contrast(1.25)"
1771
+ },
1772
+ "aria-hidden": "true"
1773
+ }
1774
+ )
1775
+ }
1776
+ );
1777
+ }
1778
+
1779
+ // src/primitives/environment/FogLayer/types.ts
1780
+ var FOG_CONFIGS = {
1781
+ depth: {
1782
+ defaultColor: "#0a0a0f",
1783
+ defaultDensity: 0.5,
1784
+ animationSpeed: 0,
1785
+ gradientStops: 2
1786
+ },
1787
+ ground: {
1788
+ defaultColor: "#ffffff",
1789
+ defaultDensity: 0.7,
1790
+ animationSpeed: 0.02,
1791
+ gradientStops: 3
1792
+ },
1793
+ volumetric: {
1794
+ defaultColor: "#e8e8ff",
1795
+ defaultDensity: 0.4,
1796
+ animationSpeed: 0.01,
1797
+ gradientStops: 4
1798
+ },
1799
+ mist: {
1800
+ defaultColor: "#f0f0ff",
1801
+ defaultDensity: 0.3,
1802
+ animationSpeed: 0.015,
1803
+ gradientStops: 5
1804
+ }
1805
+ };
1806
+ function FogLayer({
1807
+ type,
1808
+ density: propDensity,
1809
+ color: propColor,
1810
+ height = 0.4,
1811
+ animated = true,
1812
+ intensity = 1,
1813
+ stylePreset = "ui",
1814
+ enabled = true,
1815
+ className,
1816
+ style
1817
+ }) {
1818
+ const reducedMotion = useReducedMotion();
1819
+ const perfConfig = getPerformanceConfig();
1820
+ const [offset, setOffset] = React3.useState(0);
1821
+ const config = FOG_CONFIGS[type];
1822
+ const density = propDensity ?? config.defaultDensity;
1823
+ const color = propColor ?? config.defaultColor;
1824
+ const shouldAnimate = animated && !reducedMotion && perfConfig.tier !== "minimal";
1825
+ React3.useEffect(() => {
1826
+ if (!shouldAnimate || !enabled || config.animationSpeed === 0) return;
1827
+ let frame;
1828
+ const animate = () => {
1829
+ setOffset((prev) => (prev + config.animationSpeed) % 100);
1830
+ frame = requestAnimationFrame(animate);
1831
+ };
1832
+ frame = requestAnimationFrame(animate);
1833
+ return () => cancelAnimationFrame(frame);
1834
+ }, [shouldAnimate, enabled, config.animationSpeed]);
1835
+ const gradientStyle = React3.useMemo(() => {
1836
+ const opacity = density * intensity;
1837
+ switch (type) {
1838
+ case "depth":
1839
+ return {
1840
+ background: `linear-gradient(to top, ${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")}, transparent)`
1841
+ };
1842
+ case "ground":
1843
+ return {
1844
+ background: `linear-gradient(to top,
1845
+ ${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")} 0%,
1846
+ ${color}${Math.round(opacity * 0.5 * 255).toString(16).padStart(2, "0")} ${height * 50}%,
1847
+ transparent ${height * 100}%)`
1848
+ };
1849
+ case "volumetric":
1850
+ return {
1851
+ background: `
1852
+ radial-gradient(ellipse 120% 60% at 50% ${100 - offset}%, ${color}${Math.round(opacity * 0.6 * 255).toString(16).padStart(2, "0")}, transparent),
1853
+ radial-gradient(ellipse 100% 40% at ${30 + offset * 0.2}% 80%, ${color}${Math.round(opacity * 0.4 * 255).toString(16).padStart(2, "0")}, transparent),
1854
+ radial-gradient(ellipse 80% 50% at ${70 - offset * 0.15}% 90%, ${color}${Math.round(opacity * 0.5 * 255).toString(16).padStart(2, "0")}, transparent)
1855
+ `
1856
+ };
1857
+ case "mist":
1858
+ return {
1859
+ background: `
1860
+ radial-gradient(ellipse 150% 80% at ${40 + Math.sin(offset * 0.1) * 20}% ${60 + Math.cos(offset * 0.08) * 10}%, ${color}${Math.round(opacity * 0.3 * 255).toString(16).padStart(2, "0")}, transparent),
1861
+ radial-gradient(ellipse 120% 60% at ${60 + Math.cos(offset * 0.12) * 15}% ${40 + Math.sin(offset * 0.09) * 15}%, ${color}${Math.round(opacity * 0.25 * 255).toString(16).padStart(2, "0")}, transparent),
1862
+ linear-gradient(to top, ${color}${Math.round(opacity * 0.15 * 255).toString(16).padStart(2, "0")}, transparent 50%)
1863
+ `
1864
+ };
1865
+ default:
1866
+ return {};
1867
+ }
1868
+ }, [type, color, density, intensity, height, offset]);
1869
+ if (!enabled) return null;
1870
+ return /* @__PURE__ */ jsx(
1871
+ "div",
1872
+ {
1873
+ className: cn(
1874
+ "pointer-events-none absolute inset-0",
1875
+ className
1876
+ ),
1877
+ style: {
1878
+ ...gradientStyle,
1879
+ ...style
1880
+ },
1881
+ "aria-hidden": "true",
1882
+ children: stylePreset === "cinematic" && /* @__PURE__ */ jsx(
1883
+ "div",
1884
+ {
1885
+ className: "absolute inset-0",
1886
+ style: {
1887
+ backgroundImage: `url("${NOISE_DATA_URL}")`,
1888
+ backgroundRepeat: "repeat",
1889
+ backgroundSize: `${260 - Math.round(density * 80)}px ${260 - Math.round(density * 80)}px`,
1890
+ backgroundPosition: `${offset * 30}px ${offset * 20}px`,
1891
+ opacity: Math.min(0.18, 0.04 + density * intensity * 0.12),
1892
+ mixBlendMode: "soft-light",
1893
+ filter: "blur(0.6px) contrast(1.2)"
1894
+ },
1895
+ "aria-hidden": "true"
1896
+ }
1897
+ )
1898
+ }
1899
+ );
1900
+ }
1901
+ function ClusterAtmosphere({
1902
+ config,
1903
+ accentColor,
1904
+ className
1905
+ }) {
1906
+ return /* @__PURE__ */ jsxs(
1907
+ "div",
1908
+ {
1909
+ className: cn("pointer-events-none absolute inset-0", className),
1910
+ "aria-hidden": "true",
1911
+ children: [
1912
+ config.dustMotes && /* @__PURE__ */ jsx(
1913
+ DustMotesLayer,
1914
+ {
1915
+ colors: config.dustMotes.colors,
1916
+ density: config.dustMotes.density,
1917
+ speed: config.dustMotes.speed
1918
+ }
1919
+ ),
1920
+ config.fog && /* @__PURE__ */ jsx(
1921
+ FogLayer,
1922
+ {
1923
+ type: config.fog.type,
1924
+ color: config.fog.color,
1925
+ intensity: config.fog.intensity
1926
+ }
1927
+ ),
1928
+ config.light && /* @__PURE__ */ jsx(
1929
+ VolumetricLight,
1930
+ {
1931
+ type: config.light.type,
1932
+ color: config.light.color,
1933
+ intensity: config.light.intensity,
1934
+ source: config.light.source
1935
+ }
1936
+ )
1937
+ ]
1938
+ }
1939
+ );
1940
+ }
1941
+ function GradientVeil({ className, intensity = 1 }) {
1942
+ const a1 = (0.85 * intensity).toFixed(2);
1943
+ const a2 = (0.5 * intensity).toFixed(2);
1944
+ const a3 = (0.2 * intensity).toFixed(2);
1945
+ return /* @__PURE__ */ jsx(
1946
+ "div",
1947
+ {
1948
+ className: cn("absolute inset-0 pointer-events-none", className),
1949
+ style: {
1950
+ background: `linear-gradient(
1951
+ to top,
1952
+ rgba(0, 0, 0, ${a1}) 0%,
1953
+ rgba(0, 0, 0, ${a2}) 30%,
1954
+ rgba(0, 0, 0, ${a3}) 50%,
1955
+ transparent 70%
1956
+ )`
1957
+ }
1958
+ }
1959
+ );
1960
+ }
1961
+ function StructuralElements({
1962
+ accentColor,
1963
+ className
1964
+ }) {
1965
+ return /* @__PURE__ */ jsxs(
1966
+ "div",
1967
+ {
1968
+ className: cn("pointer-events-none absolute inset-0 overflow-hidden", className),
1969
+ "aria-hidden": "true",
1970
+ children: [
1971
+ /* @__PURE__ */ jsx(CornerBrackets, { accentColor }),
1972
+ /* @__PURE__ */ jsx(
1973
+ "div",
1974
+ {
1975
+ className: "absolute inset-0",
1976
+ style: {
1977
+ background: `radial-gradient(ellipse 60% 80% at 85% 50%, ${accentColor}1A 0%, transparent 70%)`
1978
+ }
1979
+ }
1980
+ ),
1981
+ /* @__PURE__ */ jsx(DotGrid, {})
1982
+ ]
1983
+ }
1984
+ );
1985
+ }
1986
+ function CornerBrackets({ accentColor }) {
1987
+ const bracketLength = 40;
1988
+ const thickness = 2;
1989
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1990
+ /* @__PURE__ */ jsxs(
1991
+ motion.div,
1992
+ {
1993
+ className: "absolute top-6 left-6",
1994
+ initial: { opacity: 0 },
1995
+ animate: { opacity: 1 },
1996
+ transition: { duration: 0.8, delay: 0.2 },
1997
+ children: [
1998
+ /* @__PURE__ */ jsx(
1999
+ "div",
2000
+ {
2001
+ className: "absolute top-0 left-0",
2002
+ style: {
2003
+ width: bracketLength,
2004
+ height: thickness,
2005
+ backgroundColor: accentColor
2006
+ }
2007
+ }
2008
+ ),
2009
+ /* @__PURE__ */ jsx(
2010
+ "div",
2011
+ {
2012
+ className: "absolute top-0 left-0",
2013
+ style: {
2014
+ width: thickness,
2015
+ height: bracketLength,
2016
+ backgroundColor: accentColor
2017
+ }
2018
+ }
2019
+ )
2020
+ ]
2021
+ }
2022
+ ),
2023
+ /* @__PURE__ */ jsxs(
2024
+ motion.div,
2025
+ {
2026
+ className: "absolute bottom-6 right-6",
2027
+ initial: { opacity: 0 },
2028
+ animate: { opacity: 1 },
2029
+ transition: { duration: 0.8, delay: 0.3 },
2030
+ children: [
2031
+ /* @__PURE__ */ jsx(
2032
+ "div",
2033
+ {
2034
+ className: "absolute bottom-0 right-0",
2035
+ style: {
2036
+ width: bracketLength,
2037
+ height: thickness,
2038
+ backgroundColor: accentColor
2039
+ }
2040
+ }
2041
+ ),
2042
+ /* @__PURE__ */ jsx(
2043
+ "div",
2044
+ {
2045
+ className: "absolute bottom-0 right-0",
2046
+ style: {
2047
+ width: thickness,
2048
+ height: bracketLength,
2049
+ backgroundColor: accentColor
2050
+ }
2051
+ }
2052
+ )
2053
+ ]
2054
+ }
2055
+ )
2056
+ ] });
2057
+ }
2058
+ function DotGrid() {
2059
+ return /* @__PURE__ */ jsx(
2060
+ "div",
2061
+ {
2062
+ className: "absolute inset-0",
2063
+ style: {
2064
+ opacity: 0.04,
2065
+ backgroundImage: `radial-gradient(circle at center, currentColor 1px, transparent 1px)`,
2066
+ backgroundSize: "24px 24px"
2067
+ }
2068
+ }
2069
+ );
2070
+ }
2071
+ function VideoBackground({
2072
+ videoSrc,
2073
+ webmSrc,
2074
+ posterSrc,
2075
+ fallbackBackground,
2076
+ className,
2077
+ crossfadeDuration = 0.8,
2078
+ preload = true,
2079
+ playbackRate = 0.75,
2080
+ onLoad,
2081
+ onError
2082
+ }) {
2083
+ const [isVideoReady, setIsVideoReady] = useState(false);
2084
+ const [hasError, setHasError] = useState(false);
2085
+ const videoRef = useRef(null);
2086
+ const [prefersReducedMotion2, setPrefersReducedMotion] = useState(false);
2087
+ useEffect(() => {
2088
+ if (typeof window === "undefined") return;
2089
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
2090
+ setPrefersReducedMotion(mediaQuery.matches);
2091
+ const handleChange = (e) => {
2092
+ setPrefersReducedMotion(e.matches);
2093
+ };
2094
+ mediaQuery.addEventListener("change", handleChange);
2095
+ return () => mediaQuery.removeEventListener("change", handleChange);
2096
+ }, []);
2097
+ const handleCanPlayThrough = useCallback(() => {
2098
+ setIsVideoReady(true);
2099
+ onLoad?.();
2100
+ }, [onLoad]);
2101
+ const handleError = useCallback(
2102
+ (e) => {
2103
+ setHasError(true);
2104
+ setIsVideoReady(false);
2105
+ onError?.(e.nativeEvent);
2106
+ },
2107
+ [onError]
2108
+ );
2109
+ useEffect(() => {
2110
+ const video = videoRef.current;
2111
+ if (!video || hasError || prefersReducedMotion2) return;
2112
+ video.playbackRate = playbackRate;
2113
+ const playPromise = video.play();
2114
+ if (playPromise !== void 0) {
2115
+ playPromise.catch(() => {
2116
+ });
2117
+ }
2118
+ }, [hasError, prefersReducedMotion2, playbackRate]);
2119
+ useEffect(() => {
2120
+ if (!preload || typeof document === "undefined") return;
2121
+ const links = [];
2122
+ if (posterSrc) {
2123
+ const posterLink = document.createElement("link");
2124
+ posterLink.rel = "preload";
2125
+ posterLink.as = "image";
2126
+ posterLink.href = posterSrc;
2127
+ document.head.appendChild(posterLink);
2128
+ links.push(posterLink);
2129
+ }
2130
+ if (videoSrc) {
2131
+ const videoLink = document.createElement("link");
2132
+ videoLink.rel = "preload";
2133
+ videoLink.as = "video";
2134
+ videoLink.href = videoSrc;
2135
+ if (videoSrc.endsWith(".mp4")) {
2136
+ videoLink.type = "video/mp4";
2137
+ } else if (videoSrc.endsWith(".webm")) {
2138
+ videoLink.type = "video/webm";
2139
+ }
2140
+ document.head.appendChild(videoLink);
2141
+ links.push(videoLink);
2142
+ }
2143
+ if (webmSrc) {
2144
+ const webmLink = document.createElement("link");
2145
+ webmLink.rel = "preload";
2146
+ webmLink.as = "video";
2147
+ webmLink.href = webmSrc;
2148
+ webmLink.type = "video/webm";
2149
+ document.head.appendChild(webmLink);
2150
+ links.push(webmLink);
2151
+ }
2152
+ return () => {
2153
+ links.forEach((link) => {
2154
+ if (link.parentNode === document.head) {
2155
+ document.head.removeChild(link);
2156
+ }
2157
+ });
2158
+ };
2159
+ }, [preload, videoSrc, webmSrc, posterSrc]);
2160
+ const mediaStyles = cn(
2161
+ "absolute inset-0 w-full h-full object-cover",
2162
+ className
2163
+ );
2164
+ const fallbackBg = fallbackBackground ?? "radial-gradient(1200px 700px at 50% 30%, rgba(255,255,255,0.10), rgba(0,0,0,0) 60%), linear-gradient(180deg, rgba(255,255,255,0.06), rgba(0,0,0,0) 40%), #000";
2165
+ const posterBackgroundImage = posterSrc ? `url(${posterSrc}), ${fallbackBg}` : fallbackBg;
2166
+ const posterBackgroundSize = posterSrc ? "cover, cover" : "cover";
2167
+ const posterBackgroundPosition = posterSrc ? "center, center" : "center";
2168
+ if (prefersReducedMotion2) {
2169
+ return /* @__PURE__ */ jsx(
2170
+ "div",
2171
+ {
2172
+ className: mediaStyles,
2173
+ style: {
2174
+ backgroundImage: posterBackgroundImage,
2175
+ backgroundSize: posterBackgroundSize,
2176
+ backgroundPosition: posterBackgroundPosition
2177
+ },
2178
+ role: "img",
2179
+ "aria-label": "Background image"
2180
+ }
2181
+ );
2182
+ }
2183
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2184
+ /* @__PURE__ */ jsx(
2185
+ "div",
2186
+ {
2187
+ className: cn(mediaStyles, "z-0"),
2188
+ style: {
2189
+ backgroundImage: posterBackgroundImage,
2190
+ backgroundSize: posterBackgroundSize,
2191
+ backgroundPosition: posterBackgroundPosition
2192
+ },
2193
+ role: "img",
2194
+ "aria-hidden": isVideoReady && !hasError
2195
+ }
2196
+ ),
2197
+ /* @__PURE__ */ jsx(AnimatePresence, { children: !hasError && /* @__PURE__ */ jsxs(
2198
+ motion.video,
2199
+ {
2200
+ ref: videoRef,
2201
+ className: cn(mediaStyles, "z-10"),
2202
+ poster: posterSrc,
2203
+ autoPlay: true,
2204
+ muted: true,
2205
+ loop: true,
2206
+ playsInline: true,
2207
+ disablePictureInPicture: true,
2208
+ disableRemotePlayback: true,
2209
+ onCanPlayThrough: handleCanPlayThrough,
2210
+ onError: handleError,
2211
+ initial: { opacity: 0 },
2212
+ animate: { opacity: isVideoReady ? 1 : 0 },
2213
+ exit: { opacity: 0 },
2214
+ transition: {
2215
+ opacity: {
2216
+ duration: crossfadeDuration,
2217
+ ease: [0.4, 0, 0.2, 1]
2218
+ // ease-out cubic
2219
+ }
2220
+ },
2221
+ "aria-hidden": "true",
2222
+ children: [
2223
+ webmSrc && /* @__PURE__ */ jsx("source", { src: webmSrc, type: "video/webm" }),
2224
+ /* @__PURE__ */ jsx("source", { src: videoSrc, type: "video/mp4" })
2225
+ ]
2226
+ },
2227
+ videoSrc
2228
+ ) })
2229
+ ] });
2230
+ }
2231
+ var fadeUpVariants = {
2232
+ hidden: { opacity: 0, y: 20 },
2233
+ visible: { opacity: 1, y: 0 }
2234
+ };
2235
+ var staggerContainer = {
2236
+ hidden: { opacity: 0 },
2237
+ visible: {
2238
+ opacity: 1,
2239
+ transition: {
2240
+ staggerChildren: 0.12,
2241
+ delayChildren: 0.1
2242
+ }
2243
+ }
2244
+ };
2245
+ function ClusterName({ name }) {
2246
+ return /* @__PURE__ */ jsx(
2247
+ motion.h2,
2248
+ {
2249
+ variants: fadeUpVariants,
2250
+ className: "text-4xl md:text-5xl lg:text-6xl font-semibold uppercase text-white",
2251
+ style: {
2252
+ fontVariant: "small-caps",
2253
+ letterSpacing: "0.12em"
2254
+ },
2255
+ children: name
2256
+ }
2257
+ );
2258
+ }
2259
+ function Tagline({ text }) {
2260
+ return /* @__PURE__ */ jsx(
2261
+ motion.p,
2262
+ {
2263
+ variants: fadeUpVariants,
2264
+ className: "text-lg md:text-xl text-white/70 font-light italic leading-relaxed mt-3",
2265
+ children: text
2266
+ }
2267
+ );
2268
+ }
2269
+ function MetricsRow({
2270
+ metrics
2271
+ }) {
2272
+ const formattedRealms = metrics.realms.toLocaleString();
2273
+ return /* @__PURE__ */ jsxs(
2274
+ motion.div,
2275
+ {
2276
+ variants: fadeUpVariants,
2277
+ className: "flex items-center gap-2 font-mono text-xs text-white/50 mt-4 tracking-wide",
2278
+ children: [
2279
+ /* @__PURE__ */ jsxs("span", { children: [
2280
+ formattedRealms,
2281
+ " realms"
2282
+ ] }),
2283
+ /* @__PURE__ */ jsx("span", { className: "text-white/30", children: "\u2022" }),
2284
+ /* @__PURE__ */ jsxs("span", { children: [
2285
+ metrics.output24h,
2286
+ " output"
2287
+ ] }),
2288
+ metrics.rank !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
2289
+ /* @__PURE__ */ jsx("span", { className: "text-white/30", children: "\u2022" }),
2290
+ /* @__PURE__ */ jsxs("span", { children: [
2291
+ "Rank #",
2292
+ metrics.rank
2293
+ ] })
2294
+ ] })
2295
+ ]
2296
+ }
2297
+ );
2298
+ }
2299
+ function RailButton({ button }) {
2300
+ const baseClasses = "w-full px-6 py-3 text-sm font-medium tracking-wider uppercase transition-all duration-300 text-center";
2301
+ const variantClasses = {
2302
+ primary: "text-neutral-900 hover:brightness-110 hover:scale-[1.02]",
2303
+ secondary: "bg-transparent border hover:bg-[var(--cluster-accent)]/10",
2304
+ ghost: "bg-transparent border-none text-white/50 hover:text-white/80"
2305
+ };
2306
+ const variantStyles = {
2307
+ primary: {
2308
+ backgroundColor: "var(--cluster-accent)"
2309
+ },
2310
+ secondary: {
2311
+ borderColor: "var(--cluster-accent)",
2312
+ color: "var(--cluster-accent)"
2313
+ },
2314
+ ghost: {}
2315
+ };
2316
+ return /* @__PURE__ */ jsx(
2317
+ motion.a,
2318
+ {
2319
+ variants: fadeUpVariants,
2320
+ href: button.href,
2321
+ className: cn(baseClasses, variantClasses[button.variant]),
2322
+ style: variantStyles[button.variant],
2323
+ ...button.external && {
2324
+ target: "_blank",
2325
+ rel: "noopener noreferrer"
2326
+ },
2327
+ children: button.label
2328
+ }
2329
+ );
2330
+ }
2331
+ function ButtonStack({ buttons }) {
2332
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3 mt-8 w-full max-w-xs", children: buttons.map((button) => /* @__PURE__ */ jsx(RailButton, { button }, button.label)) });
2333
+ }
2334
+ function ClusterRail({
2335
+ name,
2336
+ tagline,
2337
+ metrics,
2338
+ buttons,
2339
+ accentColor,
2340
+ className
2341
+ }) {
2342
+ return /* @__PURE__ */ jsxs(
2343
+ motion.aside,
2344
+ {
2345
+ variants: staggerContainer,
2346
+ initial: "hidden",
2347
+ animate: "visible",
2348
+ className: cn("flex flex-col items-start", className),
2349
+ style: {
2350
+ "--cluster-accent": accentColor
2351
+ },
2352
+ children: [
2353
+ /* @__PURE__ */ jsx(ClusterName, { name }),
2354
+ /* @__PURE__ */ jsx(Tagline, { text: tagline }),
2355
+ /* @__PURE__ */ jsx(MetricsRow, { metrics }),
2356
+ /* @__PURE__ */ jsx(ButtonStack, { buttons })
2357
+ ]
2358
+ }
2359
+ );
2360
+ }
2361
+ var containerVariants = {
2362
+ hidden: { opacity: 0 },
2363
+ visible: {
2364
+ opacity: 1,
2365
+ transition: {
2366
+ staggerChildren: 0.12,
2367
+ delayChildren: 0.1
2368
+ }
2369
+ }
2370
+ };
2371
+ var itemVariants = {
2372
+ hidden: { opacity: 0, y: 12 },
2373
+ visible: {
2374
+ opacity: 1,
2375
+ y: 0,
2376
+ transition: {
2377
+ duration: 0.5,
2378
+ ease: [0.22, 1, 0.36, 1]
2379
+ }
2380
+ }
2381
+ };
2382
+ function Description({ text }) {
2383
+ return /* @__PURE__ */ jsx(
2384
+ motion.p,
2385
+ {
2386
+ variants: itemVariants,
2387
+ className: "text-sm text-white/70 leading-relaxed max-w-xs whitespace-pre-line",
2388
+ children: text
2389
+ }
2390
+ );
2391
+ }
2392
+ function CapabilityChips({
2393
+ capabilities,
2394
+ accentColor
2395
+ }) {
2396
+ return /* @__PURE__ */ jsx(motion.div, { variants: itemVariants, className: "flex flex-wrap gap-2", children: capabilities.map((capability) => /* @__PURE__ */ jsx(
2397
+ "span",
2398
+ {
2399
+ className: "px-2.5 py-1 text-[10px] uppercase tracking-widest text-white/80 rounded-sm",
2400
+ style: {
2401
+ backgroundColor: `color-mix(in srgb, ${accentColor} 15%, transparent)`
2402
+ },
2403
+ children: capability
2404
+ },
2405
+ capability
2406
+ )) });
2407
+ }
2408
+ function FastPath({
2409
+ fastPath,
2410
+ accentColor
2411
+ }) {
2412
+ return /* @__PURE__ */ jsxs(
2413
+ motion.a,
2414
+ {
2415
+ variants: itemVariants,
2416
+ href: fastPath.href,
2417
+ className: "group inline-flex items-center gap-2 text-sm transition-colors duration-200 hover:brightness-125",
2418
+ style: { color: accentColor },
2419
+ children: [
2420
+ /* @__PURE__ */ jsx("span", { children: fastPath.label }),
2421
+ /* @__PURE__ */ jsx(
2422
+ "svg",
2423
+ {
2424
+ width: "16",
2425
+ height: "16",
2426
+ viewBox: "0 0 16 16",
2427
+ fill: "none",
2428
+ className: "transition-transform duration-200 group-hover:translate-x-1",
2429
+ children: /* @__PURE__ */ jsx(
2430
+ "path",
2431
+ {
2432
+ d: "M6 4L10 8L6 12",
2433
+ stroke: "currentColor",
2434
+ strokeWidth: "1.5",
2435
+ strokeLinecap: "round",
2436
+ strokeLinejoin: "round"
2437
+ }
2438
+ )
2439
+ }
2440
+ )
2441
+ ]
2442
+ }
2443
+ );
2444
+ }
2445
+ function StatusLine({
2446
+ status
2447
+ }) {
2448
+ return /* @__PURE__ */ jsxs(
2449
+ motion.div,
2450
+ {
2451
+ variants: itemVariants,
2452
+ className: "font-mono text-[10px] text-white/50 tracking-wide",
2453
+ children: [
2454
+ "Network: ",
2455
+ status.network,
2456
+ /* @__PURE__ */ jsx("span", { className: "mx-2", children: "\u2022" }),
2457
+ "Verification: ",
2458
+ status.verification,
2459
+ /* @__PURE__ */ jsx("span", { className: "mx-2", children: "\u2022" }),
2460
+ "Fees: ",
2461
+ status.fees
2462
+ ]
2463
+ }
2464
+ );
2465
+ }
2466
+ function BriefingPanel({
2467
+ description,
2468
+ capabilities,
2469
+ fastPath,
2470
+ status,
2471
+ accentColor,
2472
+ className
2473
+ }) {
2474
+ return /* @__PURE__ */ jsxs(
2475
+ motion.div,
2476
+ {
2477
+ variants: containerVariants,
2478
+ initial: "hidden",
2479
+ animate: "visible",
2480
+ className: cn("flex flex-col gap-4 rounded-xl p-4 backdrop-blur-xl", className),
2481
+ style: {
2482
+ background: "rgba(2,4,10,0.6)",
2483
+ border: "1px solid rgba(255,255,255,0.06)"
2484
+ },
2485
+ children: [
2486
+ /* @__PURE__ */ jsx(Description, { text: description }),
2487
+ /* @__PURE__ */ jsx(CapabilityChips, { capabilities, accentColor }),
2488
+ /* @__PURE__ */ jsx(FastPath, { fastPath, accentColor }),
2489
+ /* @__PURE__ */ jsx(StatusLine, { status })
2490
+ ]
2491
+ }
2492
+ );
2493
+ }
2494
+ function SigilMonument({
2495
+ name,
2496
+ tagline,
2497
+ latinMotto,
2498
+ sigilSrc,
2499
+ accentColor,
2500
+ className
2501
+ }) {
2502
+ const containerRef = useRef(null);
2503
+ const styleId = useId();
2504
+ const [sigilFailed, setSigilFailed] = useState(false);
2505
+ const initials = useMemo(() => {
2506
+ const parts = name.trim().split(/\s+/).filter(Boolean);
2507
+ const letters = parts.map((p) => p[0] ?? "").join("");
2508
+ return letters.slice(0, 2).toUpperCase() || name.slice(0, 2).toUpperCase();
2509
+ }, [name]);
2510
+ useEffect(() => {
2511
+ setSigilFailed(false);
2512
+ }, [sigilSrc]);
2513
+ const mouseX = useMotionValue(0);
2514
+ const mouseY = useMotionValue(0);
2515
+ const springConfig = { damping: 25, stiffness: 150 };
2516
+ const parallaxX = useSpring(
2517
+ useTransform(mouseX, [-1, 1], [-4, 4]),
2518
+ springConfig
2519
+ );
2520
+ const parallaxY = useSpring(
2521
+ useTransform(mouseY, [-1, 1], [-4, 4]),
2522
+ springConfig
2523
+ );
2524
+ const handleMouseMove = (e) => {
2525
+ if (!containerRef.current) return;
2526
+ const rect = containerRef.current.getBoundingClientRect();
2527
+ const centerX = rect.left + rect.width / 2;
2528
+ const centerY = rect.top + rect.height / 2;
2529
+ const normalizedX = (e.clientX - centerX) / (rect.width / 2);
2530
+ const normalizedY = (e.clientY - centerY) / (rect.height / 2);
2531
+ mouseX.set(Math.max(-1, Math.min(1, normalizedX)));
2532
+ mouseY.set(Math.max(-1, Math.min(1, normalizedY)));
2533
+ };
2534
+ const handleMouseLeave = () => {
2535
+ mouseX.set(0);
2536
+ mouseY.set(0);
2537
+ };
2538
+ const shimmerClass = `sigil-shimmer-${styleId.replace(/:/g, "")}`;
2539
+ return /* @__PURE__ */ jsxs(
2540
+ "div",
2541
+ {
2542
+ ref: containerRef,
2543
+ onMouseMove: handleMouseMove,
2544
+ onMouseLeave: handleMouseLeave,
2545
+ className: cn(
2546
+ "relative flex flex-col items-center justify-center",
2547
+ className
2548
+ ),
2549
+ style: { "--sigil-accent": accentColor },
2550
+ children: [
2551
+ /* @__PURE__ */ jsx(
2552
+ "style",
2553
+ {
2554
+ dangerouslySetInnerHTML: {
2555
+ __html: `
2556
+ @keyframes ${shimmerClass}-anim {
2557
+ 0% { background-position: 200% 0; }
2558
+ 100% { background-position: -200% 0; }
2559
+ }
2560
+ .${shimmerClass} {
2561
+ animation: ${shimmerClass}-anim 10s ease-in-out infinite;
2562
+ }
2563
+ `
2564
+ }
2565
+ }
2566
+ ),
2567
+ /* @__PURE__ */ jsxs(
2568
+ motion.div,
2569
+ {
2570
+ className: "relative",
2571
+ style: {
2572
+ x: parallaxX,
2573
+ y: parallaxY
2574
+ },
2575
+ children: [
2576
+ /* @__PURE__ */ jsx(
2577
+ "div",
2578
+ {
2579
+ className: "absolute inset-0 pointer-events-none overflow-hidden",
2580
+ "aria-hidden": "true",
2581
+ children: /* @__PURE__ */ jsx(
2582
+ "div",
2583
+ {
2584
+ className: `absolute inset-0 ${shimmerClass}`,
2585
+ style: {
2586
+ background: `linear-gradient(
2587
+ 105deg,
2588
+ transparent 40%,
2589
+ ${accentColor}15 45%,
2590
+ ${accentColor}25 50%,
2591
+ ${accentColor}15 55%,
2592
+ transparent 60%
2593
+ )`,
2594
+ backgroundSize: "200% 100%"
2595
+ }
2596
+ }
2597
+ )
2598
+ }
2599
+ ),
2600
+ !sigilFailed && sigilSrc ? /* @__PURE__ */ jsx(
2601
+ "img",
2602
+ {
2603
+ src: sigilSrc,
2604
+ alt: `${name} sigil`,
2605
+ className: "h-[35vh] min-h-[280px] max-h-[45vh] w-auto object-contain drop-shadow-2xl",
2606
+ style: {
2607
+ filter: `drop-shadow(0 0 60px ${accentColor}40)`
2608
+ },
2609
+ onError: () => setSigilFailed(true)
2610
+ }
2611
+ ) : /* @__PURE__ */ jsx(
2612
+ "div",
2613
+ {
2614
+ className: "h-[35vh] min-h-[280px] max-h-[45vh] aspect-square rounded-full flex items-center justify-center",
2615
+ style: {
2616
+ background: `radial-gradient(circle at 30% 30%, ${accentColor}35, transparent 65%), radial-gradient(circle at 70% 80%, ${accentColor}18, transparent 60%), rgba(255,255,255,0.02)`,
2617
+ border: `1px solid ${accentColor}40`,
2618
+ boxShadow: `0 0 60px ${accentColor}30, inset 0 0 40px rgba(255,255,255,0.08)`,
2619
+ filter: `drop-shadow(0 0 60px ${accentColor}40)`
2620
+ },
2621
+ "aria-hidden": "true",
2622
+ children: /* @__PURE__ */ jsx(
2623
+ "div",
2624
+ {
2625
+ className: "font-serif text-6xl text-white/70 tracking-[0.18em]",
2626
+ style: { textShadow: `0 0 30px ${accentColor}30` },
2627
+ children: initials
2628
+ }
2629
+ )
2630
+ }
2631
+ )
2632
+ ]
2633
+ }
2634
+ ),
2635
+ /* @__PURE__ */ jsxs("div", { className: "mt-10 text-center", children: [
2636
+ /* @__PURE__ */ jsx(
2637
+ "h2",
2638
+ {
2639
+ className: "font-serif text-3xl md:text-4xl text-white/95 mb-3",
2640
+ style: {
2641
+ fontVariant: "small-caps",
2642
+ letterSpacing: "0.12em"
2643
+ },
2644
+ children: name
2645
+ }
2646
+ ),
2647
+ /* @__PURE__ */ jsx("p", { className: "font-serif text-lg md:text-xl text-white/60 italic max-w-md leading-relaxed", children: tagline }),
2648
+ latinMotto && /* @__PURE__ */ jsx(
2649
+ "p",
2650
+ {
2651
+ className: "mt-4 font-mono text-[10px] uppercase tracking-[0.2em] text-white/30",
2652
+ "aria-label": "Latin motto",
2653
+ children: latinMotto
2654
+ }
2655
+ )
2656
+ ] })
2657
+ ]
2658
+ }
2659
+ );
2660
+ }
2661
+ var DEFAULT_CONTENT = {
2662
+ market: "3 new blueprints published today",
2663
+ live: "24 active workflows running",
2664
+ governance: "Proposal #18 \u2014 Voting ends in 6h",
2665
+ progress: "You minted 4 verified artifacts this week"
2666
+ };
2667
+ var MODULE_ICONS = {
2668
+ market: FileText,
2669
+ live: Zap,
2670
+ governance: Vote,
2671
+ progress: Trophy
2672
+ };
2673
+ function LiveStrip({
2674
+ moduleType,
2675
+ content,
2676
+ accentColor,
2677
+ className
2678
+ }) {
2679
+ const Icon = MODULE_ICONS[moduleType];
2680
+ const displayContent = content ?? DEFAULT_CONTENT[moduleType];
2681
+ return /* @__PURE__ */ jsxs(
2682
+ "div",
2683
+ {
2684
+ className: cn(
2685
+ "group flex items-center gap-3 px-4 py-2.5 rounded-lg bg-white/[0.05] backdrop-blur-sm",
2686
+ "transition-colors duration-200 hover:bg-white/[0.10] cursor-pointer",
2687
+ className
2688
+ ),
2689
+ children: [
2690
+ /* @__PURE__ */ jsx(
2691
+ Icon,
2692
+ {
2693
+ className: "w-4 h-4 shrink-0 transition-colors duration-200",
2694
+ style: { color: accentColor }
2695
+ }
2696
+ ),
2697
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-white/80 font-normal flex-1 truncate", children: displayContent }),
2698
+ /* @__PURE__ */ jsx(
2699
+ ArrowRight,
2700
+ {
2701
+ className: cn(
2702
+ "w-4 h-4 shrink-0 text-white/40",
2703
+ "transition-all duration-200 ease-out",
2704
+ "group-hover:translate-x-1 group-hover:text-white/60"
2705
+ )
2706
+ }
2707
+ )
2708
+ ]
2709
+ }
2710
+ );
2711
+ }
2712
+ function useVideoPreload({
2713
+ videoSrc,
2714
+ posterSrc,
2715
+ enabled = true
2716
+ }) {
2717
+ const [isPreloaded, setIsPreloaded] = useState(false);
2718
+ useEffect(() => {
2719
+ if (!enabled || typeof document === "undefined") {
2720
+ return;
2721
+ }
2722
+ const links = [];
2723
+ if (posterSrc) {
2724
+ const posterLink = document.createElement("link");
2725
+ posterLink.rel = "preload";
2726
+ posterLink.as = "image";
2727
+ posterLink.href = posterSrc;
2728
+ document.head.appendChild(posterLink);
2729
+ links.push(posterLink);
2730
+ }
2731
+ if (videoSrc) {
2732
+ const videoLink = document.createElement("link");
2733
+ videoLink.rel = "preload";
2734
+ videoLink.as = "video";
2735
+ videoLink.href = videoSrc;
2736
+ if (videoSrc.endsWith(".webm")) {
2737
+ videoLink.type = "video/webm";
2738
+ } else if (videoSrc.endsWith(".mp4")) {
2739
+ videoLink.type = "video/mp4";
2740
+ }
2741
+ document.head.appendChild(videoLink);
2742
+ links.push(videoLink);
2743
+ }
2744
+ setIsPreloaded(true);
2745
+ return () => {
2746
+ links.forEach((link) => {
2747
+ if (link.parentNode === document.head) {
2748
+ document.head.removeChild(link);
2749
+ }
2750
+ });
2751
+ };
2752
+ }, [videoSrc, posterSrc, enabled]);
2753
+ return { isPreloaded };
2754
+ }
2755
+ function ClusterHero({ cluster, className }) {
2756
+ const config = getClusterConfigWithResolvedUrls(cluster);
2757
+ const fallbackBackground = `radial-gradient(900px 600px at 65% 25%, rgba(${config.accentColorRGB}, 0.22), rgba(0,0,0,0) 62%), radial-gradient(700px 520px at 25% 78%, rgba(${config.accentColorRGB}, 0.10), rgba(0,0,0,0) 58%), #000`;
2758
+ useVideoPreload({
2759
+ videoSrc: config.videoSrc,
2760
+ posterSrc: config.videoPoster
2761
+ });
2762
+ return /* @__PURE__ */ jsxs(
2763
+ "section",
2764
+ {
2765
+ className: cn(
2766
+ "relative min-h-screen h-full w-full overflow-hidden bg-black",
2767
+ className
2768
+ ),
2769
+ style: { "--cluster-accent": config.accentColor },
2770
+ children: [
2771
+ /* @__PURE__ */ jsx(
2772
+ VideoBackground,
2773
+ {
2774
+ videoSrc: config.videoSrc,
2775
+ posterSrc: config.videoPoster,
2776
+ preload: true,
2777
+ fallbackBackground,
2778
+ className: "z-0"
2779
+ }
2780
+ ),
2781
+ /* @__PURE__ */ jsx(
2782
+ StructuralElements,
2783
+ {
2784
+ accentColor: config.accentColor,
2785
+ className: "z-[5]"
2786
+ }
2787
+ ),
2788
+ /* @__PURE__ */ jsx(
2789
+ ClusterAtmosphere,
2790
+ {
2791
+ config: config.atmosphere,
2792
+ accentColor: config.accentColor,
2793
+ className: "z-10"
2794
+ }
2795
+ ),
2796
+ /* @__PURE__ */ jsx(GradientVeil, { className: "z-20" }),
2797
+ /* @__PURE__ */ jsx(
2798
+ "div",
2799
+ {
2800
+ className: "absolute z-30",
2801
+ style: { top: "80px", left: "48px", maxWidth: "380px" },
2802
+ children: /* @__PURE__ */ jsx(
2803
+ BriefingPanel,
2804
+ {
2805
+ description: config.description,
2806
+ capabilities: config.capabilities,
2807
+ fastPath: config.fastPath,
2808
+ status: config.status,
2809
+ accentColor: config.accentColor
2810
+ }
2811
+ )
2812
+ }
2813
+ ),
2814
+ /* @__PURE__ */ jsx(
2815
+ "div",
2816
+ {
2817
+ className: "absolute z-30",
2818
+ style: { top: "50%", right: "80px", transform: "translateY(-50%)" },
2819
+ children: /* @__PURE__ */ jsx(
2820
+ SigilMonument,
2821
+ {
2822
+ name: config.name,
2823
+ tagline: config.tagline,
2824
+ latinMotto: config.latinMotto,
2825
+ sigilSrc: config.sigilSrc,
2826
+ accentColor: config.accentColor
2827
+ }
2828
+ )
2829
+ }
2830
+ ),
2831
+ /* @__PURE__ */ jsx(
2832
+ "div",
2833
+ {
2834
+ className: "absolute z-30",
2835
+ style: { bottom: "80px", left: "50%", transform: "translateX(-50%)", maxWidth: "600px", width: "100%" },
2836
+ children: /* @__PURE__ */ jsx(
2837
+ LiveStrip,
2838
+ {
2839
+ moduleType: config.liveModule,
2840
+ content: config.liveContent,
2841
+ accentColor: config.accentColor
2842
+ }
2843
+ )
2844
+ }
2845
+ ),
2846
+ /* @__PURE__ */ jsx(
2847
+ "div",
2848
+ {
2849
+ className: "absolute z-40",
2850
+ style: { bottom: "32px", left: "48px", maxWidth: "280px" },
2851
+ children: /* @__PURE__ */ jsx(
2852
+ ClusterRail,
2853
+ {
2854
+ name: config.name,
2855
+ tagline: config.tagline,
2856
+ metrics: config.metrics,
2857
+ buttons: config.buttons,
2858
+ accentColor: config.accentColor
2859
+ }
2860
+ )
2861
+ }
2862
+ )
2863
+ ]
2864
+ }
2865
+ );
2866
+ }
2867
+ var FEATURE_DATA = {
2868
+ alexandria: [
2869
+ { title: "Knowledge Graph", description: "Interconnected data structures that compound understanding over time", icon: "book" },
2870
+ { title: "Semantic Search", description: "Query across documents with natural language understanding", icon: "search" },
2871
+ { title: "Version History", description: "Every edit preserved, every branch trackable", icon: "history" }
2872
+ ],
2873
+ alpha: [
2874
+ { title: "Genesis Protocol", description: "The foundational layer from which all clusters derive", icon: "origin" },
2875
+ { title: "Core APIs", description: "Stable interfaces that power the entire ecosystem", icon: "api" },
2876
+ { title: "Identity Layer", description: "Sovereign authentication across all surfaces", icon: "key" }
2877
+ ],
2878
+ opus: [
2879
+ { title: "Diagnostic Engines", description: "AI-powered analysis pipelines for medical imaging and patient data", icon: "scan" },
2880
+ { title: "Care Protocols", description: "Autonomous coordination of treatment workflows and provider networks", icon: "workflow" },
2881
+ { title: "Compliance Layer", description: "Built-in HIPAA, SOC2, and regulatory framework adherence", icon: "shield" }
2882
+ ],
2883
+ baia: [
2884
+ { title: "Neural Canvas", description: "Generative models that transform prompts into visual masterpieces", icon: "palette" },
2885
+ { title: "Sound Synthesis", description: "AI composition engines for music, ambience, and audio design", icon: "waveform" },
2886
+ { title: "Style Transfer", description: "Cross-modal translation between artistic mediums and formats", icon: "layers" }
2887
+ ],
2888
+ kdot: [
2889
+ { title: "Mesh Network", description: "Distributed connectivity that routes around failures", icon: "network" },
2890
+ { title: "Protocol Layer", description: "Universal translation between disparate systems", icon: "protocol" },
2891
+ { title: "Node Discovery", description: "Automatic peer detection and topology mapping", icon: "discovery" }
2892
+ ],
2893
+ aegis: [
2894
+ { title: "Threat Detection", description: "Real-time monitoring for anomalous patterns", icon: "shield" },
2895
+ { title: "Access Control", description: "Fine-grained permissions and authentication flows", icon: "lock" },
2896
+ { title: "Audit Trail", description: "Immutable logs of every action and decision", icon: "log" }
2897
+ ],
2898
+ providence: [
2899
+ { title: "Threat Intelligence", description: "Predictive analysis and proactive defense postures", icon: "radar" },
2900
+ { title: "Incident Response", description: "Automated containment and remediation workflows", icon: "alert" },
2901
+ { title: "Compliance Engine", description: "Continuous verification against security frameworks", icon: "certificate" }
2902
+ ]
2903
+ };
2904
+ function FeatureCard({
2905
+ title,
2906
+ description,
2907
+ accentColor,
2908
+ index
2909
+ }) {
2910
+ return /* @__PURE__ */ jsxs(
2911
+ motion.article,
2912
+ {
2913
+ initial: { opacity: 0, y: 40 },
2914
+ whileInView: { opacity: 1, y: 0 },
2915
+ viewport: { once: true, margin: "-100px" },
2916
+ transition: {
2917
+ duration: 0.6,
2918
+ delay: index * 0.15,
2919
+ ease: [0.22, 1, 0.36, 1]
2920
+ },
2921
+ className: "group relative p-8 bg-zinc-900/80 backdrop-blur-sm border border-zinc-800 hover:border-zinc-700 transition-colors duration-300",
2922
+ children: [
2923
+ /* @__PURE__ */ jsx(
2924
+ "div",
2925
+ {
2926
+ className: "absolute top-0 left-0 w-1 h-0 group-hover:h-full transition-all duration-500",
2927
+ style: { backgroundColor: accentColor }
2928
+ }
2929
+ ),
2930
+ /* @__PURE__ */ jsx("h3", { className: "font-serif text-2xl text-white mb-3 tracking-wide", children: title }),
2931
+ /* @__PURE__ */ jsx("p", { className: "text-neutral-400 leading-relaxed", children: description })
2932
+ ]
2933
+ }
2934
+ );
2935
+ }
2936
+ function FeatureCardsSection({ clusterId, config }) {
2937
+ const features = FEATURE_DATA[clusterId];
2938
+ return /* @__PURE__ */ jsx("section", { className: "relative z-10 bg-zinc-950 py-32 px-16", children: /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto", children: [
2939
+ /* @__PURE__ */ jsxs(
2940
+ motion.header,
2941
+ {
2942
+ initial: { opacity: 0, y: 20 },
2943
+ whileInView: { opacity: 1, y: 0 },
2944
+ viewport: { once: true },
2945
+ transition: { duration: 0.6 },
2946
+ className: "mb-16",
2947
+ children: [
2948
+ /* @__PURE__ */ jsx(
2949
+ "span",
2950
+ {
2951
+ className: "font-mono text-xs uppercase tracking-[0.2em]",
2952
+ style: { color: config.accentColor },
2953
+ children: "Capabilities"
2954
+ }
2955
+ ),
2956
+ /* @__PURE__ */ jsxs("h2", { className: "font-serif text-5xl text-white mt-4 tracking-wide", children: [
2957
+ "What defines ",
2958
+ config.name
2959
+ ] })
2960
+ ]
2961
+ }
2962
+ ),
2963
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-6", children: features.map((feature, index) => /* @__PURE__ */ jsx(
2964
+ FeatureCard,
2965
+ {
2966
+ title: feature.title,
2967
+ description: feature.description,
2968
+ accentColor: config.accentColor,
2969
+ index
2970
+ },
2971
+ feature.title
2972
+ )) })
2973
+ ] }) });
2974
+ }
2975
+ var STATS_DATA = {
2976
+ alexandria: [
2977
+ { value: "2.4M", label: "Documents Indexed" },
2978
+ { value: "847K", label: "Active Queries/Day" },
2979
+ { value: "99.97%", label: "Uptime" },
2980
+ { value: "12ms", label: "Avg Response" }
2981
+ ],
2982
+ alpha: [
2983
+ { value: "1.0", label: "Protocol Version" },
2984
+ { value: "\u221E", label: "Scalability" },
2985
+ { value: "100%", label: "Backwards Compatible" },
2986
+ { value: "0", label: "Breaking Changes" }
2987
+ ],
2988
+ opus: [
2989
+ { value: "2.4M", label: "Diagnostics Processed" },
2990
+ { value: "847", label: "Active Protocols" },
2991
+ { value: "99.97%", label: "Compliance Rate" },
2992
+ { value: "< 2s", label: "Analysis Latency" }
2993
+ ],
2994
+ baia: [
2995
+ { value: "4.2M", label: "Works Generated" },
2996
+ { value: "156K", label: "Active Artists" },
2997
+ { value: "847K", label: "Daily Renders" },
2998
+ { value: "12TB", label: "Media Produced" }
2999
+ ],
3000
+ kdot: [
3001
+ { value: "1.2M", label: "Connected Nodes" },
3002
+ { value: "47ms", label: "Avg Latency" },
3003
+ { value: "99.99%", label: "Uptime" },
3004
+ { value: "8.4PB", label: "Daily Throughput" }
3005
+ ],
3006
+ aegis: [
3007
+ { value: "0", label: "Breaches" },
3008
+ { value: "2.1B", label: "Threats Blocked" },
3009
+ { value: "99.97%", label: "Detection Rate" },
3010
+ { value: "< 1s", label: "Response Time" }
3011
+ ],
3012
+ providence: [
3013
+ { value: "24/7", label: "Monitoring" },
3014
+ { value: "847K", label: "Threats Analyzed" },
3015
+ { value: "99.99%", label: "Uptime" },
3016
+ { value: "< 50ms", label: "Alert Latency" }
3017
+ ]
3018
+ };
3019
+ function StatBlock({
3020
+ value,
3021
+ label,
3022
+ accentColor,
3023
+ index
3024
+ }) {
3025
+ return /* @__PURE__ */ jsxs(
3026
+ motion.div,
3027
+ {
3028
+ initial: { opacity: 0, scale: 0.9 },
3029
+ whileInView: { opacity: 1, scale: 1 },
3030
+ viewport: { once: true, margin: "-50px" },
3031
+ transition: {
3032
+ duration: 0.5,
3033
+ delay: index * 0.1,
3034
+ ease: [0.22, 1, 0.36, 1]
3035
+ },
3036
+ className: "text-center p-8",
3037
+ children: [
3038
+ /* @__PURE__ */ jsx(
3039
+ "div",
3040
+ {
3041
+ className: "font-mono text-5xl md:text-6xl font-light mb-3",
3042
+ style: { color: accentColor },
3043
+ children: value
3044
+ }
3045
+ ),
3046
+ /* @__PURE__ */ jsx("div", { className: "text-neutral-400 uppercase tracking-[0.15em] text-sm", children: label })
3047
+ ]
3048
+ }
3049
+ );
3050
+ }
3051
+ function ClusterStatsSection({ clusterId, config }) {
3052
+ const stats = STATS_DATA[clusterId];
3053
+ return /* @__PURE__ */ jsx("section", { className: "relative z-10 bg-black py-32 px-16", children: /* @__PURE__ */ jsxs("div", { className: "max-w-6xl mx-auto", children: [
3054
+ /* @__PURE__ */ jsx(
3055
+ motion.div,
3056
+ {
3057
+ initial: { scaleX: 0 },
3058
+ whileInView: { scaleX: 1 },
3059
+ viewport: { once: true },
3060
+ transition: { duration: 1, ease: [0.22, 1, 0.36, 1] },
3061
+ className: "h-px mb-16 origin-left",
3062
+ style: { backgroundColor: config.accentColor }
3063
+ }
3064
+ ),
3065
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-8", children: stats.map((stat, index) => /* @__PURE__ */ jsx(
3066
+ StatBlock,
3067
+ {
3068
+ value: stat.value,
3069
+ label: stat.label,
3070
+ accentColor: config.accentColor,
3071
+ index
3072
+ },
3073
+ stat.label
3074
+ )) }),
3075
+ /* @__PURE__ */ jsx(
3076
+ motion.div,
3077
+ {
3078
+ initial: { scaleX: 0 },
3079
+ whileInView: { scaleX: 1 },
3080
+ viewport: { once: true },
3081
+ transition: { duration: 1, ease: [0.22, 1, 0.36, 1] },
3082
+ className: "h-px mt-16 origin-right",
3083
+ style: { backgroundColor: config.accentColor }
3084
+ }
3085
+ )
3086
+ ] }) });
3087
+ }
3088
+ var CTA_DATA = {
3089
+ alexandria: {
3090
+ headline: "Begin your research",
3091
+ subtext: "Join thousands of scholars building the world's knowledge commons",
3092
+ buttonLabel: "Enter Alexandria"
3093
+ },
3094
+ alpha: {
3095
+ headline: "Start from the source",
3096
+ subtext: "Everything begins here. Every journey starts with Alpha.",
3097
+ buttonLabel: "Initialize"
3098
+ },
3099
+ opus: {
3100
+ headline: "Healthcare, autonomous",
3101
+ subtext: "Diagnostic pipelines and care protocols that run themselves.",
3102
+ buttonLabel: "Enter Opus"
3103
+ },
3104
+ baia: {
3105
+ headline: "Art from the machine",
3106
+ subtext: "Generative works that blur the line between human and artificial creativity.",
3107
+ buttonLabel: "Open Studio"
3108
+ },
3109
+ kdot: {
3110
+ headline: "Join the mesh",
3111
+ subtext: "Connect to the network that never sleeps.",
3112
+ buttonLabel: "Connect Now"
3113
+ },
3114
+ aegis: {
3115
+ headline: "Secure your realm",
3116
+ subtext: "Protection that scales with your ambition.",
3117
+ buttonLabel: "Activate Shield"
3118
+ },
3119
+ providence: {
3120
+ headline: "Foresee. Prevent. Prevail.",
3121
+ subtext: "Security through foresight. Protection before the threat arrives.",
3122
+ buttonLabel: "Enter Providence"
3123
+ }
3124
+ };
3125
+ function CTASection({ clusterId, config }) {
3126
+ const cta = CTA_DATA[clusterId];
3127
+ return /* @__PURE__ */ jsx("section", { className: "relative z-10 bg-zinc-950 py-48 px-16", children: /* @__PURE__ */ jsxs(
3128
+ motion.div,
3129
+ {
3130
+ initial: { opacity: 0, y: 60 },
3131
+ whileInView: { opacity: 1, y: 0 },
3132
+ viewport: { once: true, margin: "-100px" },
3133
+ transition: { duration: 0.8, ease: [0.22, 1, 0.36, 1] },
3134
+ className: "max-w-4xl mx-auto text-center",
3135
+ children: [
3136
+ /* @__PURE__ */ jsx("h2", { className: "font-serif text-6xl md:text-7xl text-white tracking-wide mb-8 leading-[1.1]", children: cta.headline }),
3137
+ /* @__PURE__ */ jsx("p", { className: "text-xl text-neutral-400 mb-12 max-w-2xl mx-auto leading-relaxed", children: cta.subtext }),
3138
+ /* @__PURE__ */ jsx(
3139
+ "a",
3140
+ {
3141
+ href: `/clusters/${clusterId}`,
3142
+ className: "inline-block px-12 py-5 text-lg font-medium tracking-wider uppercase text-neutral-900 transition-all duration-300 hover:brightness-110 hover:scale-105",
3143
+ style: { backgroundColor: config.accentColor },
3144
+ children: cta.buttonLabel
3145
+ }
3146
+ )
3147
+ ]
3148
+ }
3149
+ ) });
3150
+ }
3151
+ function ClusterHeroPage({ clusterId, className }) {
3152
+ const containerRef = useRef(null);
3153
+ const config = getClusterConfigWithResolvedUrls(clusterId);
3154
+ const { scrollYProgress } = useScroll({
3155
+ target: containerRef,
3156
+ offset: ["start start", "end start"]
3157
+ });
3158
+ const heroOpacity = useTransform(scrollYProgress, [0, 0.15], [1, 0.3]);
3159
+ const heroY = useTransform(scrollYProgress, [0, 0.3], [0, -100]);
3160
+ return /* @__PURE__ */ jsxs(
3161
+ "main",
3162
+ {
3163
+ ref: containerRef,
3164
+ className: cn(
3165
+ "relative scroll-smooth",
3166
+ className
3167
+ ),
3168
+ children: [
3169
+ /* @__PURE__ */ jsx(
3170
+ motion.div,
3171
+ {
3172
+ className: "sticky top-0 h-screen overflow-hidden",
3173
+ style: { opacity: heroOpacity },
3174
+ children: /* @__PURE__ */ jsx(motion.div, { style: { y: heroY }, className: "h-full", children: /* @__PURE__ */ jsx(ClusterHero, { cluster: clusterId, className: "h-full" }) })
3175
+ }
3176
+ ),
3177
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3178
+ /* @__PURE__ */ jsx(FeatureCardsSection, { clusterId, config }),
3179
+ /* @__PURE__ */ jsx(ClusterStatsSection, { clusterId, config }),
3180
+ /* @__PURE__ */ jsx(CTASection, { clusterId, config })
3181
+ ] })
3182
+ ]
3183
+ }
3184
+ );
3185
+ }
3186
+
3187
+ export { AgentPanel, BBProvider, CLUSTER_CONFIGS, ClusterHero, ClusterHeroPage, PlaySession, SyncDocument, getClusterConfig, useBBContext, useBBContextOptional };
11
3188
  //# sourceMappingURL=index.js.map
12
3189
  //# sourceMappingURL=index.js.map