@zendir/ui 0.1.7 → 0.1.9

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 (79) hide show
  1. package/dist/index.js +0 -137
  2. package/dist/index.js.map +1 -1
  3. package/dist/react/context/DisplaySettingsContext.js +0 -12
  4. package/dist/react/context/DisplaySettingsContext.js.map +1 -1
  5. package/dist/react/index.d.ts +0 -30
  6. package/dist/react/utils/index.js +0 -8
  7. package/dist/react/utils/index.js.map +1 -1
  8. package/dist/react.js +0 -137
  9. package/dist/react.js.map +1 -1
  10. package/package.json +2 -2
  11. package/dist/react/3d/EarthViewer.js +0 -836
  12. package/dist/react/3d/EarthViewer.js.map +0 -1
  13. package/dist/react/3d/SolarSystemViewer.js +0 -372
  14. package/dist/react/3d/SolarSystemViewer.js.map +0 -1
  15. package/dist/react/3d/ZenSpace3D.js +0 -1253
  16. package/dist/react/3d/ZenSpace3D.js.map +0 -1
  17. package/dist/react/3d/ZenSpace3DCesium.js +0 -186
  18. package/dist/react/3d/ZenSpace3DCesium.js.map +0 -1
  19. package/dist/react/3d/ZenSpace3DShaders.js +0 -94
  20. package/dist/react/3d/ZenSpace3DShaders.js.map +0 -1
  21. package/dist/react/3d/ZenSpace3DUtils.js +0 -213
  22. package/dist/react/3d/ZenSpace3DUtils.js.map +0 -1
  23. package/dist/react/3d/threeLoader.js +0 -18
  24. package/dist/react/3d/threeLoader.js.map +0 -1
  25. package/dist/react/cards/AccessCard.js +0 -410
  26. package/dist/react/cards/AccessCard.js.map +0 -1
  27. package/dist/react/cards/OrbitCard.js +0 -372
  28. package/dist/react/cards/OrbitCard.js.map +0 -1
  29. package/dist/react/cards/SpacecraftCard.js +0 -941
  30. package/dist/react/cards/SpacecraftCard.js.map +0 -1
  31. package/dist/react/cards/TelemetryCard.js +0 -742
  32. package/dist/react/cards/TelemetryCard.js.map +0 -1
  33. package/dist/react/cards/TelemetryStreamCard.js +0 -309
  34. package/dist/react/cards/TelemetryStreamCard.js.map +0 -1
  35. package/dist/react/charts/GroundTrackMap.js +0 -1123
  36. package/dist/react/charts/GroundTrackMap.js.map +0 -1
  37. package/dist/react/charts/GroundTrackMapLeaflet.js +0 -571
  38. package/dist/react/charts/GroundTrackMapLeaflet.js.map +0 -1
  39. package/dist/react/charts/groundTrackMapLeafletTiles.js +0 -11
  40. package/dist/react/charts/groundTrackMapLeafletTiles.js.map +0 -1
  41. package/dist/react/charts/groundTrackMapLeafletUtils.js +0 -109
  42. package/dist/react/charts/groundTrackMapLeafletUtils.js.map +0 -1
  43. package/dist/react/charts/unified/AstroChart.js +0 -1405
  44. package/dist/react/charts/unified/AstroChart.js.map +0 -1
  45. package/dist/react/charts/unified/PowerOverviewChart.js +0 -488
  46. package/dist/react/charts/unified/PowerOverviewChart.js.map +0 -1
  47. package/dist/react/charts/unified/domain.js +0 -3168
  48. package/dist/react/charts/unified/domain.js.map +0 -1
  49. package/dist/react/charts/unified/generators.js +0 -518
  50. package/dist/react/charts/unified/generators.js.map +0 -1
  51. package/dist/react/charts/unified/presets.js +0 -999
  52. package/dist/react/charts/unified/presets.js.map +0 -1
  53. package/dist/react/charts/unified/sync.js +0 -219
  54. package/dist/react/charts/unified/sync.js.map +0 -1
  55. package/dist/react/charts/unified/theme.js +0 -562
  56. package/dist/react/charts/unified/theme.js.map +0 -1
  57. package/dist/react/charts/unified/useChartStream.js +0 -226
  58. package/dist/react/charts/unified/useChartStream.js.map +0 -1
  59. package/dist/react/visualizations/EclipseTimerCard.js +0 -250
  60. package/dist/react/visualizations/EclipseTimerCard.js.map +0 -1
  61. package/dist/react/visualizations/LinkBudgetCard.js +0 -444
  62. package/dist/react/visualizations/LinkBudgetCard.js.map +0 -1
  63. package/dist/react/visualizations/NavBallCard.js +0 -243
  64. package/dist/react/visualizations/NavBallCard.js.map +0 -1
  65. package/dist/react/visualizations/PropulsionCard.js +0 -298
  66. package/dist/react/visualizations/PropulsionCard.js.map +0 -1
  67. package/dist/react/visualizations/SensorFootprintCard.js +0 -326
  68. package/dist/react/visualizations/SensorFootprintCard.js.map +0 -1
  69. package/dist/react/visualizations/ThermalHeatmapCard.js +0 -372
  70. package/dist/react/visualizations/ThermalHeatmapCard.js.map +0 -1
  71. package/dist/shaders/atmosphere.frag.js +0 -5
  72. package/dist/shaders/atmosphere.frag.js.map +0 -1
  73. package/dist/shaders/atmosphere.vert.js +0 -5
  74. package/dist/shaders/atmosphere.vert.js.map +0 -1
  75. package/dist/shaders/stars.frag.js +0 -5
  76. package/dist/shaders/stars.frag.js.map +0 -1
  77. package/dist/shaders/stars.vert.js +0 -5
  78. package/dist/shaders/stars.vert.js.map +0 -1
  79. package/dist/style.css +0 -143
@@ -1,444 +0,0 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
2
- import { memo, useMemo } from "react";
3
- import { classNames, safeNumber, formatDataRate } from "../utils/index.js";
4
- import { useTheme } from "../theme/ThemeProvider.js";
5
- function formatDb(value, showSign = true, suffix = "dB") {
6
- if (value === void 0 || value === null || !Number.isFinite(value)) {
7
- return `-- ${suffix}`;
8
- }
9
- const sign = showSign && value >= 0 ? "+" : "";
10
- return `${sign}${value.toFixed(1)} ${suffix}`;
11
- }
12
- function dbmToWatts(dbm) {
13
- if (dbm === void 0 || !Number.isFinite(dbm)) return "-- W";
14
- const watts = Math.pow(10, (dbm - 30) / 10);
15
- if (watts >= 1e3) return `${(watts / 1e3).toFixed(1)} kW`;
16
- if (watts >= 1) return `${watts.toFixed(1)} W`;
17
- if (watts >= 1e-3) return `${(watts * 1e3).toFixed(1)} mW`;
18
- return `${(watts * 1e6).toFixed(1)} µW`;
19
- }
20
- function getMarginStatus(margin) {
21
- if (margin === void 0 || !Number.isFinite(margin)) return "off";
22
- if (margin >= 6) return "normal";
23
- if (margin >= 3) return "standby";
24
- if (margin >= 0) return "caution";
25
- return "critical";
26
- }
27
- const LinkBudgetCard = memo(function LinkBudgetCard2({
28
- linkBudget,
29
- groundStationName = "Ground Station",
30
- compact = false,
31
- loading = false,
32
- className = ""
33
- }) {
34
- const { tokens, theme, prefersReducedMotion } = useTheme();
35
- const isTransparentTheme = theme === "transparent" || theme === "transparent-bold" || theme === "transparent-minimal";
36
- const cardBg = isTransparentTheme ? "transparent" : tokens.colors.background.surface;
37
- const cardGlass = isTransparentTheme ? {
38
- backdropFilter: "blur(12px)",
39
- WebkitBackdropFilter: "blur(12px)"
40
- } : {};
41
- const marginDb = useMemo(() => {
42
- if (!linkBudget) return void 0;
43
- const rx = linkBudget.rxPowerDbm;
44
- const sens = linkBudget.rxSensitivityDbm;
45
- if (!Number.isFinite(rx) || !Number.isFinite(sens)) return void 0;
46
- return rx - sens;
47
- }, [linkBudget == null ? void 0 : linkBudget.rxPowerDbm, linkBudget == null ? void 0 : linkBudget.rxSensitivityDbm]);
48
- const marginStatus = getMarginStatus(marginDb);
49
- const transitionDuration = prefersReducedMotion ? "0ms" : "300ms";
50
- const SOFT_STATUS_COLORS = {
51
- normal: "#6ed86e",
52
- caution: "#ffd54f",
53
- serious: "#ffa726",
54
- critical: "#e57373",
55
- off: "#90a4ae",
56
- standby: "#4fc3f7"
57
- };
58
- if (loading) {
59
- return /* @__PURE__ */ jsxs(
60
- "div",
61
- {
62
- className: classNames("zendir-link-budget-card", "loading", className),
63
- role: "article",
64
- "aria-busy": "true",
65
- "aria-label": "Loading link budget",
66
- style: {
67
- backgroundColor: cardBg,
68
- ...cardGlass,
69
- border: "none",
70
- borderRadius: tokens.borderRadius.lg,
71
- padding: tokens.spacing.md,
72
- minHeight: 280
73
- },
74
- children: [
75
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 16 }, children: [
76
- /* @__PURE__ */ jsx("div", { style: { height: 24, width: "40%", backgroundColor: "rgba(255,255,255,0.1)", borderRadius: 4 } }),
77
- /* @__PURE__ */ jsx("div", { style: { height: 24, width: 60, backgroundColor: "rgba(255,255,255,0.1)", borderRadius: 4 } })
78
- ] }),
79
- [1, 2, 3, 4, 5].map((i) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 12 }, children: [
80
- /* @__PURE__ */ jsx("div", { style: { width: 16, height: 16, borderRadius: "50%", backgroundColor: "rgba(255,255,255,0.1)" } }),
81
- /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 16, backgroundColor: "rgba(255,255,255,0.06)", borderRadius: 4 } })
82
- ] }, i))
83
- ]
84
- }
85
- );
86
- }
87
- if (!linkBudget) {
88
- return /* @__PURE__ */ jsxs(
89
- "div",
90
- {
91
- className: classNames("zendir-link-budget-card", "empty", className),
92
- role: "article",
93
- "aria-label": "No link budget data",
94
- style: {
95
- backgroundColor: cardBg,
96
- ...cardGlass,
97
- border: "none",
98
- borderRadius: tokens.borderRadius.lg,
99
- padding: tokens.spacing.lg,
100
- textAlign: "center",
101
- color: tokens.colors.text.tertiary
102
- },
103
- children: [
104
- /* @__PURE__ */ jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "currentColor", style: { opacity: 0.5, marginBottom: 8 }, children: /* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z" }) }),
105
- /* @__PURE__ */ jsxs("p", { style: { margin: 0, fontSize: tokens.typography.body[2].fontSize }, children: [
106
- groundStationName,
107
- ": No link budget data"
108
- ] })
109
- ]
110
- }
111
- );
112
- }
113
- const isLinkClosed = linkBudget.isLinkClosed ?? false;
114
- const statusColor = isLinkClosed ? SOFT_STATUS_COLORS.normal : SOFT_STATUS_COLORS.off;
115
- const marginColor = SOFT_STATUS_COLORS[marginStatus] ?? SOFT_STATUS_COLORS.off;
116
- const chainItemStyle = {
117
- position: "relative",
118
- paddingLeft: 36,
119
- marginBottom: tokens.spacing.md
120
- };
121
- const dotStyle = (color) => ({
122
- position: "absolute",
123
- left: 8,
124
- top: 6,
125
- width: 16,
126
- height: 16,
127
- backgroundColor: color,
128
- borderRadius: "50%",
129
- border: `2px solid ${tokens.colors.background.surface}`,
130
- zIndex: 10
131
- });
132
- return /* @__PURE__ */ jsxs(
133
- "article",
134
- {
135
- className: classNames("zendir-link-budget-card", className),
136
- "aria-label": `Link budget for ${groundStationName}`,
137
- style: {
138
- backgroundColor: cardBg,
139
- ...cardGlass,
140
- border: "none",
141
- borderRadius: tokens.borderRadius.lg,
142
- padding: tokens.spacing.md,
143
- fontFamily: tokens.typography.fontFamily.primary,
144
- color: tokens.colors.text.primary
145
- },
146
- children: [
147
- !compact && /* @__PURE__ */ jsxs(
148
- "header",
149
- {
150
- style: {
151
- display: "flex",
152
- justifyContent: "space-between",
153
- alignItems: "flex-start",
154
- marginBottom: tokens.spacing.md
155
- },
156
- children: [
157
- /* @__PURE__ */ jsxs("div", { children: [
158
- /* @__PURE__ */ jsx(
159
- "h3",
160
- {
161
- style: {
162
- margin: 0,
163
- fontSize: tokens.typography.fontSize.md,
164
- fontWeight: tokens.typography.fontWeight.semibold
165
- },
166
- children: "Link Budget"
167
- }
168
- ),
169
- /* @__PURE__ */ jsx(
170
- "p",
171
- {
172
- style: {
173
- margin: "2px 0 0 0",
174
- fontSize: tokens.typography.fontSize.xs,
175
- color: tokens.colors.text.tertiary
176
- },
177
- children: groundStationName
178
- }
179
- )
180
- ] }),
181
- /* @__PURE__ */ jsx(
182
- "span",
183
- {
184
- role: "status",
185
- style: {
186
- padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`,
187
- borderRadius: tokens.borderRadius.sm,
188
- fontSize: tokens.typography.fontSize.xxs,
189
- // 0.625rem / 10px (AstroUXDS compact)
190
- fontWeight: tokens.typography.fontWeight.bold,
191
- backgroundColor: `${statusColor}20`,
192
- color: statusColor
193
- },
194
- children: isLinkClosed ? "Link Closed" : "No Link"
195
- }
196
- )
197
- ]
198
- }
199
- ),
200
- /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
201
- /* @__PURE__ */ jsx(
202
- "div",
203
- {
204
- style: {
205
- position: "absolute",
206
- left: 14,
207
- top: 24,
208
- bottom: 24,
209
- width: 2,
210
- backgroundColor: tokens.colors.border.muted
211
- }
212
- }
213
- ),
214
- /* @__PURE__ */ jsx(
215
- ChainItem,
216
- {
217
- label: "Tx Power",
218
- value: formatDb(linkBudget.txPowerDbm, false, "dBm"),
219
- subtext: dbmToWatts(linkBudget.txPowerDbm),
220
- color: tokens.colors.accent.primary,
221
- dotStyle,
222
- chainItemStyle,
223
- tokens
224
- }
225
- ),
226
- /* @__PURE__ */ jsx(
227
- ChainItem,
228
- {
229
- label: "Antenna Gain",
230
- value: formatDb(linkBudget.txAntennaGainDbi, true, "dBi"),
231
- color: SOFT_STATUS_COLORS.normal,
232
- dotStyle,
233
- chainItemStyle,
234
- tokens
235
- }
236
- ),
237
- /* @__PURE__ */ jsx(
238
- ChainItem,
239
- {
240
- label: "Path Loss",
241
- value: formatDb(linkBudget.pathLossDb, true, "dB"),
242
- subtext: `Range: ${safeNumber(linkBudget.rangeKm, 0, "--")} km`,
243
- color: SOFT_STATUS_COLORS.critical,
244
- dotStyle,
245
- chainItemStyle,
246
- tokens
247
- }
248
- ),
249
- (linkBudget.atmosphericLossDb || linkBudget.pointingLossDb) && /* @__PURE__ */ jsx(
250
- ChainItem,
251
- {
252
- label: "Other Losses",
253
- value: formatDb((linkBudget.atmosphericLossDb ?? 0) + (linkBudget.pointingLossDb ?? 0), true, "dB"),
254
- color: SOFT_STATUS_COLORS.caution,
255
- dotStyle,
256
- chainItemStyle,
257
- tokens
258
- }
259
- ),
260
- /* @__PURE__ */ jsx(
261
- ChainItem,
262
- {
263
- label: "Rx Gain",
264
- value: formatDb(linkBudget.rxAntennaGainDbi, true, "dBi"),
265
- color: SOFT_STATUS_COLORS.normal,
266
- dotStyle,
267
- chainItemStyle,
268
- tokens
269
- }
270
- ),
271
- /* @__PURE__ */ jsx(
272
- "div",
273
- {
274
- style: {
275
- height: 1,
276
- backgroundColor: tokens.colors.border.muted,
277
- marginLeft: 36,
278
- marginBottom: tokens.spacing.sm
279
- }
280
- }
281
- ),
282
- /* @__PURE__ */ jsx(
283
- ChainItem,
284
- {
285
- label: "Rx Power",
286
- value: formatDb(linkBudget.rxPowerDbm, false, "dBm"),
287
- color: isLinkClosed ? tokens.colors.text.primary : SOFT_STATUS_COLORS.off,
288
- glow: isLinkClosed,
289
- dotStyle,
290
- chainItemStyle,
291
- tokens,
292
- bold: true
293
- }
294
- )
295
- ] }),
296
- /* @__PURE__ */ jsxs(
297
- "div",
298
- {
299
- style: {
300
- marginTop: tokens.spacing.md,
301
- paddingTop: tokens.spacing.md,
302
- borderTop: `1px solid ${tokens.colors.border.muted}`
303
- },
304
- children: [
305
- /* @__PURE__ */ jsxs(
306
- "div",
307
- {
308
- style: {
309
- display: "flex",
310
- justifyContent: "space-between",
311
- alignItems: "center",
312
- fontSize: tokens.typography.fontSize.sm
313
- },
314
- children: [
315
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "Link Margin" }),
316
- /* @__PURE__ */ jsx(
317
- "span",
318
- {
319
- style: {
320
- fontFamily: tokens.typography.fontFamily.mono,
321
- fontWeight: tokens.typography.fontWeight.bold,
322
- fontVariantNumeric: "tabular-nums",
323
- color: marginColor
324
- },
325
- children: formatDb(marginDb, true, "dB")
326
- }
327
- )
328
- ]
329
- }
330
- ),
331
- /* @__PURE__ */ jsx(
332
- "div",
333
- {
334
- style: {
335
- marginTop: tokens.spacing.sm,
336
- height: 8,
337
- backgroundColor: tokens.colors.border.muted,
338
- borderRadius: 4,
339
- overflow: "hidden"
340
- },
341
- children: /* @__PURE__ */ jsx(
342
- "div",
343
- {
344
- role: "progressbar",
345
- "aria-valuenow": marginDb ?? 0,
346
- "aria-label": "Link margin",
347
- style: {
348
- height: "100%",
349
- borderRadius: 4,
350
- transition: `width ${transitionDuration} ease`,
351
- backgroundColor: marginColor,
352
- width: `${Math.min(100, Math.max(0, ((marginDb ?? 0) + 10) * 5))}%`
353
- }
354
- }
355
- )
356
- }
357
- ),
358
- linkBudget.dataRateBps !== void 0 && /* @__PURE__ */ jsxs(
359
- "div",
360
- {
361
- style: {
362
- display: "flex",
363
- justifyContent: "space-between",
364
- alignItems: "center",
365
- fontSize: tokens.typography.fontSize.xs,
366
- marginTop: tokens.spacing.sm
367
- },
368
- children: [
369
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "Data Rate" }),
370
- /* @__PURE__ */ jsx(
371
- "span",
372
- {
373
- style: {
374
- fontFamily: tokens.typography.fontFamily.mono,
375
- color: SOFT_STATUS_COLORS.standby,
376
- fontVariantNumeric: "tabular-nums"
377
- },
378
- children: formatDataRate(linkBudget.dataRateBps)
379
- }
380
- )
381
- ]
382
- }
383
- )
384
- ]
385
- }
386
- )
387
- ]
388
- }
389
- );
390
- });
391
- const ChainItem = memo(function ChainItem2({
392
- label,
393
- value,
394
- subtext,
395
- color,
396
- glow = false,
397
- bold = false,
398
- dotStyle,
399
- chainItemStyle,
400
- tokens
401
- }) {
402
- return /* @__PURE__ */ jsxs("div", { style: chainItemStyle, children: [
403
- /* @__PURE__ */ jsx(
404
- "div",
405
- {
406
- style: {
407
- ...dotStyle(color),
408
- boxShadow: glow ? `0 0 8px ${color}` : "none"
409
- }
410
- }
411
- ),
412
- /* @__PURE__ */ jsxs(
413
- "div",
414
- {
415
- style: {
416
- display: "flex",
417
- justifyContent: "space-between",
418
- alignItems: "center",
419
- fontSize: tokens.typography.fontSize.sm,
420
- fontWeight: bold ? tokens.typography.fontWeight.semibold : tokens.typography.fontWeight.normal
421
- },
422
- children: [
423
- /* @__PURE__ */ jsx("span", { style: { color: bold ? tokens.colors.text.primary : tokens.colors.text.secondary }, children: label }),
424
- /* @__PURE__ */ jsx(
425
- "span",
426
- {
427
- style: {
428
- fontFamily: tokens.typography.fontFamily.mono,
429
- color: bold ? tokens.colors.text.primary : color,
430
- fontVariantNumeric: "tabular-nums"
431
- },
432
- children: value
433
- }
434
- )
435
- ]
436
- }
437
- ),
438
- subtext && /* @__PURE__ */ jsx("div", { style: { fontSize: tokens.typography.fontSize.xxs, color: tokens.colors.text.tertiary }, children: subtext })
439
- ] });
440
- });
441
- export {
442
- LinkBudgetCard
443
- };
444
- //# sourceMappingURL=LinkBudgetCard.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LinkBudgetCard.js","sources":["../../../src/react/visualizations/LinkBudgetCard.tsx"],"sourcesContent":["/**\n * @zendir/ui - LinkBudgetCard Component\n * \n * RF Signal Chain Visualization showing complete link budget equation.\n * Tx Power → Antenna Gains → Path Loss → Rx Power = Margin\n * \n * AstroUXDS Compliance:\n * - Uses status colors for semantic meaning (gains=green, losses=red)\n * - Tx Power uses Zendir accent color (brand identity)\n * - Margin indicator uses status colors based on link quality\n * - Typography follows minimum size requirements (14pt)\n * \n * Features:\n * - Full null-safety with graceful fallbacks\n * - Visual signal chain diagram\n * - Link margin indicator with progress bar\n * - Loading and empty states\n */\n\nimport React, { memo, useMemo } from 'react';\nimport { useTheme } from '../theme';\nimport {\n safeNumber,\n formatDataRate,\n classNames,\n type StatusLevel,\n} from '../utils';\n\nexport interface LinkBudgetData {\n /** Transmitter power in dBm */\n txPowerDbm: number;\n /** Transmitter antenna gain in dBi */\n txAntennaGainDbi: number;\n /** Receiver antenna gain in dBi */\n rxAntennaGainDbi: number;\n /** Free space path loss in dB (negative value) */\n pathLossDb: number;\n /** Atmospheric losses in dB (negative value) */\n atmosphericLossDb?: number;\n /** Pointing losses in dB (negative value) */\n pointingLossDb?: number;\n /** Received power in dBm */\n rxPowerDbm: number;\n /** Receiver sensitivity threshold in dBm */\n rxSensitivityDbm: number;\n /** Current range in km */\n rangeKm: number;\n /** Data rate in bps */\n dataRateBps?: number;\n /** Link status */\n isLinkClosed: boolean;\n}\n\nexport interface LinkBudgetCardProps {\n /** Link budget data */\n linkBudget?: LinkBudgetData;\n /** Ground station name */\n groundStationName?: string;\n /** Compact mode */\n compact?: boolean;\n /** Loading state */\n loading?: boolean;\n /** Custom class name */\n className?: string;\n}\n\n/**\n * Format dB value with sign\n */\nfunction formatDb(value: number | undefined, showSign = true, suffix = 'dB'): string {\n if (value === undefined || value === null || !Number.isFinite(value)) {\n return `-- ${suffix}`;\n }\n const sign = showSign && value >= 0 ? '+' : '';\n return `${sign}${value.toFixed(1)} ${suffix}`;\n}\n\n/**\n * Calculate power in watts from dBm\n */\nfunction dbmToWatts(dbm: number | undefined): string {\n if (dbm === undefined || !Number.isFinite(dbm)) return '-- W';\n const watts = Math.pow(10, (dbm - 30) / 10);\n if (watts >= 1000) return `${(watts / 1000).toFixed(1)} kW`;\n if (watts >= 1) return `${watts.toFixed(1)} W`;\n if (watts >= 0.001) return `${(watts * 1000).toFixed(1)} mW`;\n return `${(watts * 1000000).toFixed(1)} µW`;\n}\n\n/**\n * Get margin status level\n */\nfunction getMarginStatus(margin: number | undefined): StatusLevel {\n if (margin === undefined || !Number.isFinite(margin)) return 'off';\n if (margin >= 6) return 'normal';\n if (margin >= 3) return 'standby';\n if (margin >= 0) return 'caution';\n return 'critical';\n}\n\n/**\n * LinkBudgetCard - Visualizes RF link budget\n * \n * @example\n * ```tsx\n * <LinkBudgetCard\n * linkBudget={linkBudgetData}\n * groundStationName=\"Goldstone\"\n * />\n * ```\n */\nexport const LinkBudgetCard = memo(function LinkBudgetCard({\n linkBudget,\n groundStationName = 'Ground Station',\n compact = false,\n loading = false,\n className = '',\n}: LinkBudgetCardProps): React.ReactElement {\n const { tokens, theme, prefersReducedMotion } = useTheme();\n const isTransparentTheme = theme === 'transparent' || theme === 'transparent-bold' || theme === 'transparent-minimal';\n // Use transparent background with blur for transparent themes (matching Timeline)\n const cardBg = isTransparentTheme ? 'transparent' : tokens.colors.background.surface;\n const cardGlass = isTransparentTheme ? { \n backdropFilter: 'blur(12px)' as const, \n WebkitBackdropFilter: 'blur(12px)' as const,\n } : {};\n\n // Calculate margin\n const marginDb = useMemo(() => {\n if (!linkBudget) return undefined;\n const rx = linkBudget.rxPowerDbm;\n const sens = linkBudget.rxSensitivityDbm;\n if (!Number.isFinite(rx) || !Number.isFinite(sens)) return undefined;\n return rx - sens;\n }, [linkBudget?.rxPowerDbm, linkBudget?.rxSensitivityDbm]);\n\n const marginStatus = getMarginStatus(marginDb);\n const transitionDuration = prefersReducedMotion ? '0ms' : '300ms';\n\n // Medium-soft status colors (readable, not too pale)\n const SOFT_STATUS_COLORS: Record<StatusLevel, string> = {\n normal: '#6ed86e',\n caution: '#ffd54f',\n serious: '#ffa726',\n critical: '#e57373',\n off: '#90a4ae',\n standby: '#4fc3f7',\n };\n\n // Loading state\n if (loading) {\n return (\n <div\n className={classNames('zendir-link-budget-card', 'loading', className)}\n role=\"article\"\n aria-busy=\"true\"\n aria-label=\"Loading link budget\"\n style={{\n backgroundColor: cardBg,\n ...cardGlass,\n border: 'none',\n borderRadius: tokens.borderRadius.lg,\n padding: tokens.spacing.md,\n minHeight: 280,\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>\n <div style={{ height: 24, width: '40%', backgroundColor: 'rgba(255,255,255,0.1)', borderRadius: 4 }} />\n <div style={{ height: 24, width: 60, backgroundColor: 'rgba(255,255,255,0.1)', borderRadius: 4 }} />\n </div>\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>\n <div style={{ width: 16, height: 16, borderRadius: '50%', backgroundColor: 'rgba(255,255,255,0.1)' }} />\n <div style={{ flex: 1, height: 16, backgroundColor: 'rgba(255,255,255,0.06)', borderRadius: 4 }} />\n </div>\n ))}\n </div>\n );\n }\n\n // Empty state\n if (!linkBudget) {\n return (\n <div\n className={classNames('zendir-link-budget-card', 'empty', className)}\n role=\"article\"\n aria-label=\"No link budget data\"\n style={{\n backgroundColor: cardBg,\n ...cardGlass,\n border: 'none',\n borderRadius: tokens.borderRadius.lg,\n padding: tokens.spacing.lg,\n textAlign: 'center',\n color: tokens.colors.text.tertiary,\n }}\n >\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style={{ opacity: 0.5, marginBottom: 8 }}>\n <path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z\" />\n </svg>\n <p style={{ margin: 0, fontSize: tokens.typography.body[2].fontSize }}>{groundStationName}: No link budget data</p>\n </div>\n );\n }\n\n const isLinkClosed = linkBudget.isLinkClosed ?? false;\n const statusColor = isLinkClosed ? SOFT_STATUS_COLORS.normal : SOFT_STATUS_COLORS.off;\n const marginColor = SOFT_STATUS_COLORS[marginStatus] ?? SOFT_STATUS_COLORS.off;\n\n const chainItemStyle: React.CSSProperties = {\n position: 'relative',\n paddingLeft: 36,\n marginBottom: tokens.spacing.md,\n };\n\n const dotStyle = (color: string): React.CSSProperties => ({\n position: 'absolute',\n left: 8,\n top: 6,\n width: 16,\n height: 16,\n backgroundColor: color,\n borderRadius: '50%',\n border: `2px solid ${tokens.colors.background.surface}`,\n zIndex: 10,\n });\n\n return (\n <article\n className={classNames('zendir-link-budget-card', className)}\n aria-label={`Link budget for ${groundStationName}`}\n style={{\n backgroundColor: cardBg,\n ...cardGlass,\n border: 'none',\n borderRadius: tokens.borderRadius.lg,\n padding: tokens.spacing.md,\n fontFamily: tokens.typography.fontFamily.primary,\n color: tokens.colors.text.primary,\n }}\n >\n {/* Header */}\n {!compact && (\n <header\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'flex-start',\n marginBottom: tokens.spacing.md,\n }}\n >\n <div>\n <h3\n style={{\n margin: 0,\n fontSize: tokens.typography.fontSize.md,\n fontWeight: tokens.typography.fontWeight.semibold,\n }}\n >\n Link Budget\n </h3>\n <p\n style={{\n margin: '2px 0 0 0',\n fontSize: tokens.typography.fontSize.xs,\n color: tokens.colors.text.tertiary,\n }}\n >\n {groundStationName}\n </p>\n </div>\n <span\n role=\"status\"\n style={{\n padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`,\n borderRadius: tokens.borderRadius.sm,\n fontSize: tokens.typography.fontSize.xxs, // 0.625rem / 10px (AstroUXDS compact)\n fontWeight: tokens.typography.fontWeight.bold,\n backgroundColor: `${statusColor}20`,\n color: statusColor,\n }}\n >\n {isLinkClosed ? 'Link Closed' : 'No Link'}\n </span>\n </header>\n )}\n\n {/* Signal Chain */}\n <div style={{ position: 'relative' }}>\n {/* Vertical line */}\n <div\n style={{\n position: 'absolute',\n left: 14,\n top: 24,\n bottom: 24,\n width: 2,\n backgroundColor: tokens.colors.border.muted,\n }}\n />\n\n {/* Tx Power */}\n <ChainItem\n label=\"Tx Power\"\n value={formatDb(linkBudget.txPowerDbm, false, 'dBm')}\n subtext={dbmToWatts(linkBudget.txPowerDbm)}\n color={tokens.colors.accent.primary}\n dotStyle={dotStyle}\n chainItemStyle={chainItemStyle}\n tokens={tokens}\n />\n\n {/* Tx Antenna Gain */}\n <ChainItem\n label=\"Antenna Gain\"\n value={formatDb(linkBudget.txAntennaGainDbi, true, 'dBi')}\n color={SOFT_STATUS_COLORS.normal}\n dotStyle={dotStyle}\n chainItemStyle={chainItemStyle}\n tokens={tokens}\n />\n\n {/* Path Loss */}\n <ChainItem\n label=\"Path Loss\"\n value={formatDb(linkBudget.pathLossDb, true, 'dB')}\n subtext={`Range: ${safeNumber(linkBudget.rangeKm, 0, '--')} km`}\n color={SOFT_STATUS_COLORS.critical}\n dotStyle={dotStyle}\n chainItemStyle={chainItemStyle}\n tokens={tokens}\n />\n\n {/* Additional losses */}\n {(linkBudget.atmosphericLossDb || linkBudget.pointingLossDb) && (\n <ChainItem\n label=\"Other Losses\"\n value={formatDb((linkBudget.atmosphericLossDb ?? 0) + (linkBudget.pointingLossDb ?? 0), true, 'dB')}\n color={SOFT_STATUS_COLORS.caution}\n dotStyle={dotStyle}\n chainItemStyle={chainItemStyle}\n tokens={tokens}\n />\n )}\n\n {/* Rx Antenna Gain */}\n <ChainItem\n label=\"Rx Gain\"\n value={formatDb(linkBudget.rxAntennaGainDbi, true, 'dBi')}\n color={SOFT_STATUS_COLORS.normal}\n dotStyle={dotStyle}\n chainItemStyle={chainItemStyle}\n tokens={tokens}\n />\n\n {/* Divider */}\n <div\n style={{\n height: 1,\n backgroundColor: tokens.colors.border.muted,\n marginLeft: 36,\n marginBottom: tokens.spacing.sm,\n }}\n />\n\n {/* Rx Power Result */}\n <ChainItem\n label=\"Rx Power\"\n value={formatDb(linkBudget.rxPowerDbm, false, 'dBm')}\n color={isLinkClosed ? tokens.colors.text.primary : SOFT_STATUS_COLORS.off}\n glow={isLinkClosed}\n dotStyle={dotStyle}\n chainItemStyle={chainItemStyle}\n tokens={tokens}\n bold\n />\n </div>\n\n {/* Margin Indicator */}\n <div\n style={{\n marginTop: tokens.spacing.md,\n paddingTop: tokens.spacing.md,\n borderTop: `1px solid ${tokens.colors.border.muted}`,\n }}\n >\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n fontSize: tokens.typography.fontSize.sm,\n }}\n >\n <span style={{ color: tokens.colors.text.tertiary }}>Link Margin</span>\n <span\n style={{\n fontFamily: tokens.typography.fontFamily.mono,\n fontWeight: tokens.typography.fontWeight.bold,\n fontVariantNumeric: 'tabular-nums',\n color: marginColor,\n }}\n >\n {formatDb(marginDb, true, 'dB')}\n </span>\n </div>\n\n {/* Visual margin bar */}\n <div\n style={{\n marginTop: tokens.spacing.sm,\n height: 8,\n backgroundColor: tokens.colors.border.muted,\n borderRadius: 4,\n overflow: 'hidden',\n }}\n >\n <div\n role=\"progressbar\"\n aria-valuenow={marginDb ?? 0}\n aria-label=\"Link margin\"\n style={{\n height: '100%',\n borderRadius: 4,\n transition: `width ${transitionDuration} ease`,\n backgroundColor: marginColor,\n width: `${Math.min(100, Math.max(0, ((marginDb ?? 0) + 10) * 5))}%`,\n }}\n />\n </div>\n\n {/* Data rate */}\n {linkBudget.dataRateBps !== undefined && (\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n fontSize: tokens.typography.fontSize.xs,\n marginTop: tokens.spacing.sm,\n }}\n >\n <span style={{ color: tokens.colors.text.tertiary }}>Data Rate</span>\n <span\n style={{\n fontFamily: tokens.typography.fontFamily.mono,\n color: SOFT_STATUS_COLORS.standby,\n fontVariantNumeric: 'tabular-nums',\n }}\n >\n {formatDataRate(linkBudget.dataRateBps)}\n </span>\n </div>\n )}\n </div>\n </article>\n );\n});\n\n// ============================================================================\n// Helper Component\n// ============================================================================\n\ninterface ChainItemProps {\n label: string;\n value: string;\n subtext?: string;\n color: string;\n glow?: boolean;\n bold?: boolean;\n dotStyle: (color: string) => React.CSSProperties;\n chainItemStyle: React.CSSProperties;\n tokens: ReturnType<typeof useTheme>['tokens'];\n}\n\nconst ChainItem = memo(function ChainItem({\n label,\n value,\n subtext,\n color,\n glow = false,\n bold = false,\n dotStyle,\n chainItemStyle,\n tokens,\n}: ChainItemProps): React.ReactElement {\n return (\n <div style={chainItemStyle}>\n <div\n style={{\n ...dotStyle(color),\n boxShadow: glow ? `0 0 8px ${color}` : 'none',\n }}\n />\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n fontSize: tokens.typography.fontSize.sm,\n fontWeight: bold ? tokens.typography.fontWeight.semibold : tokens.typography.fontWeight.normal,\n }}\n >\n <span style={{ color: bold ? tokens.colors.text.primary : tokens.colors.text.secondary }}>{label}</span>\n <span\n style={{\n fontFamily: tokens.typography.fontFamily.mono,\n color: bold ? tokens.colors.text.primary : color,\n fontVariantNumeric: 'tabular-nums',\n }}\n >\n {value}\n </span>\n </div>\n {subtext && (\n <div style={{ fontSize: tokens.typography.fontSize.xxs, color: tokens.colors.text.tertiary }}>{subtext}</div>\n )}\n </div>\n );\n});\n"],"names":["LinkBudgetCard","ChainItem"],"mappings":";;;;AAqEA,SAAS,SAAS,OAA2B,WAAW,MAAM,SAAS,MAAc;AACnF,MAAI,UAAU,UAAa,UAAU,QAAQ,CAAC,OAAO,SAAS,KAAK,GAAG;AACpE,WAAO,MAAM,MAAM;AAAA,EACrB;AACA,QAAM,OAAO,YAAY,SAAS,IAAI,MAAM;AAC5C,SAAO,GAAG,IAAI,GAAG,MAAM,QAAQ,CAAC,CAAC,IAAI,MAAM;AAC7C;AAKA,SAAS,WAAW,KAAiC;AACnD,MAAI,QAAQ,UAAa,CAAC,OAAO,SAAS,GAAG,EAAG,QAAO;AACvD,QAAM,QAAQ,KAAK,IAAI,KAAK,MAAM,MAAM,EAAE;AAC1C,MAAI,SAAS,IAAM,QAAO,IAAI,QAAQ,KAAM,QAAQ,CAAC,CAAC;AACtD,MAAI,SAAS,EAAG,QAAO,GAAG,MAAM,QAAQ,CAAC,CAAC;AAC1C,MAAI,SAAS,KAAO,QAAO,IAAI,QAAQ,KAAM,QAAQ,CAAC,CAAC;AACvD,SAAO,IAAI,QAAQ,KAAS,QAAQ,CAAC,CAAC;AACxC;AAKA,SAAS,gBAAgB,QAAyC;AAChE,MAAI,WAAW,UAAa,CAAC,OAAO,SAAS,MAAM,EAAG,QAAO;AAC7D,MAAI,UAAU,EAAG,QAAO;AACxB,MAAI,UAAU,EAAG,QAAO;AACxB,MAAI,UAAU,EAAG,QAAO;AACxB,SAAO;AACT;AAaO,MAAM,iBAAiB,KAAK,SAASA,gBAAe;AAAA,EACzD;AAAA,EACA,oBAAoB;AAAA,EACpB,UAAU;AAAA,EACV,UAAU;AAAA,EACV,YAAY;AACd,GAA4C;AAC1C,QAAM,EAAE,QAAQ,OAAO,qBAAA,IAAyB,SAAA;AAChD,QAAM,qBAAqB,UAAU,iBAAiB,UAAU,sBAAsB,UAAU;AAEhG,QAAM,SAAS,qBAAqB,gBAAgB,OAAO,OAAO,WAAW;AAC7E,QAAM,YAAY,qBAAqB;AAAA,IACrC,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,EAAA,IACpB,CAAA;AAGJ,QAAM,WAAW,QAAQ,MAAM;AAC7B,QAAI,CAAC,WAAY,QAAO;AACxB,UAAM,KAAK,WAAW;AACtB,UAAM,OAAO,WAAW;AACxB,QAAI,CAAC,OAAO,SAAS,EAAE,KAAK,CAAC,OAAO,SAAS,IAAI,EAAG,QAAO;AAC3D,WAAO,KAAK;AAAA,EACd,GAAG,CAAC,yCAAY,YAAY,yCAAY,gBAAgB,CAAC;AAEzD,QAAM,eAAe,gBAAgB,QAAQ;AAC7C,QAAM,qBAAqB,uBAAuB,QAAQ;AAG1D,QAAM,qBAAkD;AAAA,IACtD,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU;AAAA,IACV,KAAK;AAAA,IACL,SAAS;AAAA,EAAA;AAIX,MAAI,SAAS;AACX,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW,WAAW,2BAA2B,WAAW,SAAS;AAAA,QACrE,MAAK;AAAA,QACL,aAAU;AAAA,QACV,cAAW;AAAA,QACX,OAAO;AAAA,UACL,iBAAiB;AAAA,UACjB,GAAG;AAAA,UACH,QAAQ;AAAA,UACR,cAAc,OAAO,aAAa;AAAA,UAClC,SAAS,OAAO,QAAQ;AAAA,UACxB,WAAW;AAAA,QAAA;AAAA,QAGb,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,iBAAiB,cAAc,GAAA,GAC5E,UAAA;AAAA,YAAA,oBAAC,OAAA,EAAI,OAAO,EAAE,QAAQ,IAAI,OAAO,OAAO,iBAAiB,yBAAyB,cAAc,EAAA,EAAE,CAAG;AAAA,YACrG,oBAAC,OAAA,EAAI,OAAO,EAAE,QAAQ,IAAI,OAAO,IAAI,iBAAiB,yBAAyB,cAAc,EAAA,EAAE,CAAG;AAAA,UAAA,GACpG;AAAA,UACC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACpB,qBAAC,SAAY,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,GAAG,cAAc,GAAA,GACjF,UAAA;AAAA,YAAA,oBAAC,OAAA,EAAI,OAAO,EAAE,OAAO,IAAI,QAAQ,IAAI,cAAc,OAAO,iBAAiB,wBAAA,EAAwB,CAAG;AAAA,YACtG,oBAAC,OAAA,EAAI,OAAO,EAAE,MAAM,GAAG,QAAQ,IAAI,iBAAiB,0BAA0B,cAAc,EAAA,EAAE,CAAG;AAAA,UAAA,EAAA,GAFzF,CAGV,CACD;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AAGA,MAAI,CAAC,YAAY;AACf,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW,WAAW,2BAA2B,SAAS,SAAS;AAAA,QACnE,MAAK;AAAA,QACL,cAAW;AAAA,QACX,OAAO;AAAA,UACL,iBAAiB;AAAA,UACjB,GAAG;AAAA,UACH,QAAQ;AAAA,UACR,cAAc,OAAO,aAAa;AAAA,UAClC,SAAS,OAAO,QAAQ;AAAA,UACxB,WAAW;AAAA,UACX,OAAO,OAAO,OAAO,KAAK;AAAA,QAAA;AAAA,QAG5B,UAAA;AAAA,UAAA,oBAAC,OAAA,EAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,gBAAe,OAAO,EAAE,SAAS,KAAK,cAAc,EAAA,GACvG,8BAAC,QAAA,EAAK,GAAE,uOAAsO,EAAA,CAChP;AAAA,UACA,qBAAC,KAAA,EAAE,OAAO,EAAE,QAAQ,GAAG,UAAU,OAAO,WAAW,KAAK,CAAC,EAAE,YAAa,UAAA;AAAA,YAAA;AAAA,YAAkB;AAAA,UAAA,EAAA,CAAqB;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGrH;AAEA,QAAM,eAAe,WAAW,gBAAgB;AAChD,QAAM,cAAc,eAAe,mBAAmB,SAAS,mBAAmB;AAClF,QAAM,cAAc,mBAAmB,YAAY,KAAK,mBAAmB;AAE3E,QAAM,iBAAsC;AAAA,IAC1C,UAAU;AAAA,IACV,aAAa;AAAA,IACb,cAAc,OAAO,QAAQ;AAAA,EAAA;AAG/B,QAAM,WAAW,CAAC,WAAwC;AAAA,IACxD,UAAU;AAAA,IACV,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,QAAQ,aAAa,OAAO,OAAO,WAAW,OAAO;AAAA,IACrD,QAAQ;AAAA,EAAA;AAGV,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,WAAW,2BAA2B,SAAS;AAAA,MAC1D,cAAY,mBAAmB,iBAAiB;AAAA,MAChD,OAAO;AAAA,QACL,iBAAiB;AAAA,QACjB,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,cAAc,OAAO,aAAa;AAAA,QAClC,SAAS,OAAO,QAAQ;AAAA,QACxB,YAAY,OAAO,WAAW,WAAW;AAAA,QACzC,OAAO,OAAO,OAAO,KAAK;AAAA,MAAA;AAAA,MAI3B,UAAA;AAAA,QAAA,CAAC,WACA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,OAAO;AAAA,cACL,SAAS;AAAA,cACT,gBAAgB;AAAA,cAChB,YAAY;AAAA,cACZ,cAAc,OAAO,QAAQ;AAAA,YAAA;AAAA,YAG/B,UAAA;AAAA,cAAA,qBAAC,OAAA,EACC,UAAA;AAAA,gBAAA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,OAAO;AAAA,sBACL,QAAQ;AAAA,sBACR,UAAU,OAAO,WAAW,SAAS;AAAA,sBACrC,YAAY,OAAO,WAAW,WAAW;AAAA,oBAAA;AAAA,oBAE5C,UAAA;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAGD;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,OAAO;AAAA,sBACL,QAAQ;AAAA,sBACR,UAAU,OAAO,WAAW,SAAS;AAAA,sBACrC,OAAO,OAAO,OAAO,KAAK;AAAA,oBAAA;AAAA,oBAG3B,UAAA;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACH,GACF;AAAA,cACA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAO;AAAA,oBACL,SAAS,GAAG,OAAO,QAAQ,EAAE,IAAI,OAAO,QAAQ,EAAE;AAAA,oBAClD,cAAc,OAAO,aAAa;AAAA,oBAClC,UAAU,OAAO,WAAW,SAAS;AAAA;AAAA,oBACrC,YAAY,OAAO,WAAW,WAAW;AAAA,oBACzC,iBAAiB,GAAG,WAAW;AAAA,oBAC/B,OAAO;AAAA,kBAAA;AAAA,kBAGR,yBAAe,gBAAgB;AAAA,gBAAA;AAAA,cAAA;AAAA,YAClC;AAAA,UAAA;AAAA,QAAA;AAAA,6BAKH,OAAA,EAAI,OAAO,EAAE,UAAU,cAEtB,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,MAAM;AAAA,gBACN,KAAK;AAAA,gBACL,QAAQ;AAAA,gBACR,OAAO;AAAA,gBACP,iBAAiB,OAAO,OAAO,OAAO;AAAA,cAAA;AAAA,YACxC;AAAA,UAAA;AAAA,UAIF;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAM;AAAA,cACN,OAAO,SAAS,WAAW,YAAY,OAAO,KAAK;AAAA,cACnD,SAAS,WAAW,WAAW,UAAU;AAAA,cACzC,OAAO,OAAO,OAAO,OAAO;AAAA,cAC5B;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAAA,UAAA;AAAA,UAIF;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAM;AAAA,cACN,OAAO,SAAS,WAAW,kBAAkB,MAAM,KAAK;AAAA,cACxD,OAAO,mBAAmB;AAAA,cAC1B;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAAA,UAAA;AAAA,UAIF;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAM;AAAA,cACN,OAAO,SAAS,WAAW,YAAY,MAAM,IAAI;AAAA,cACjD,SAAS,UAAU,WAAW,WAAW,SAAS,GAAG,IAAI,CAAC;AAAA,cAC1D,OAAO,mBAAmB;AAAA,cAC1B;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAAA,UAAA;AAAA,WAIA,WAAW,qBAAqB,WAAW,mBAC3C;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAM;AAAA,cACN,OAAO,UAAU,WAAW,qBAAqB,MAAM,WAAW,kBAAkB,IAAI,MAAM,IAAI;AAAA,cAClG,OAAO,mBAAmB;AAAA,cAC1B;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAAA,UAAA;AAAA,UAKJ;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAM;AAAA,cACN,OAAO,SAAS,WAAW,kBAAkB,MAAM,KAAK;AAAA,cACxD,OAAO,mBAAmB;AAAA,cAC1B;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAAA,UAAA;AAAA,UAIF;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO;AAAA,gBACL,QAAQ;AAAA,gBACR,iBAAiB,OAAO,OAAO,OAAO;AAAA,gBACtC,YAAY;AAAA,gBACZ,cAAc,OAAO,QAAQ;AAAA,cAAA;AAAA,YAC/B;AAAA,UAAA;AAAA,UAIF;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAM;AAAA,cACN,OAAO,SAAS,WAAW,YAAY,OAAO,KAAK;AAAA,cACnD,OAAO,eAAe,OAAO,OAAO,KAAK,UAAU,mBAAmB;AAAA,cACtE,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA;AAAA,cACA,MAAI;AAAA,YAAA;AAAA,UAAA;AAAA,QACN,GACF;AAAA,QAGA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,OAAO;AAAA,cACL,WAAW,OAAO,QAAQ;AAAA,cAC1B,YAAY,OAAO,QAAQ;AAAA,cAC3B,WAAW,aAAa,OAAO,OAAO,OAAO,KAAK;AAAA,YAAA;AAAA,YAGpD,UAAA;AAAA,cAAA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,OAAO;AAAA,oBACL,SAAS;AAAA,oBACT,gBAAgB;AAAA,oBAChB,YAAY;AAAA,oBACZ,UAAU,OAAO,WAAW,SAAS;AAAA,kBAAA;AAAA,kBAGvC,UAAA;AAAA,oBAAA,oBAAC,QAAA,EAAK,OAAO,EAAE,OAAO,OAAO,OAAO,KAAK,SAAA,GAAY,UAAA,cAAA,CAAW;AAAA,oBAChE;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACC,OAAO;AAAA,0BACL,YAAY,OAAO,WAAW,WAAW;AAAA,0BACzC,YAAY,OAAO,WAAW,WAAW;AAAA,0BACzC,oBAAoB;AAAA,0BACpB,OAAO;AAAA,wBAAA;AAAA,wBAGR,UAAA,SAAS,UAAU,MAAM,IAAI;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBAChC;AAAA,gBAAA;AAAA,cAAA;AAAA,cAIF;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,OAAO;AAAA,oBACL,WAAW,OAAO,QAAQ;AAAA,oBAC1B,QAAQ;AAAA,oBACR,iBAAiB,OAAO,OAAO,OAAO;AAAA,oBACtC,cAAc;AAAA,oBACd,UAAU;AAAA,kBAAA;AAAA,kBAGZ,UAAA;AAAA,oBAAC;AAAA,oBAAA;AAAA,sBACC,MAAK;AAAA,sBACL,iBAAe,YAAY;AAAA,sBAC3B,cAAW;AAAA,sBACX,OAAO;AAAA,wBACL,QAAQ;AAAA,wBACR,cAAc;AAAA,wBACd,YAAY,SAAS,kBAAkB;AAAA,wBACvC,iBAAiB;AAAA,wBACjB,OAAO,GAAG,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,YAAY,KAAK,MAAM,CAAC,CAAC,CAAC;AAAA,sBAAA;AAAA,oBAClE;AAAA,kBAAA;AAAA,gBACF;AAAA,cAAA;AAAA,cAID,WAAW,gBAAgB,UAC1B;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,OAAO;AAAA,oBACL,SAAS;AAAA,oBACT,gBAAgB;AAAA,oBAChB,YAAY;AAAA,oBACZ,UAAU,OAAO,WAAW,SAAS;AAAA,oBACrC,WAAW,OAAO,QAAQ;AAAA,kBAAA;AAAA,kBAG5B,UAAA;AAAA,oBAAA,oBAAC,QAAA,EAAK,OAAO,EAAE,OAAO,OAAO,OAAO,KAAK,SAAA,GAAY,UAAA,YAAA,CAAS;AAAA,oBAC9D;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACC,OAAO;AAAA,0BACL,YAAY,OAAO,WAAW,WAAW;AAAA,0BACzC,OAAO,mBAAmB;AAAA,0BAC1B,oBAAoB;AAAA,wBAAA;AAAA,wBAGrB,UAAA,eAAe,WAAW,WAAW;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBACxC;AAAA,gBAAA;AAAA,cAAA;AAAA,YACF;AAAA,UAAA;AAAA,QAAA;AAAA,MAEJ;AAAA,IAAA;AAAA,EAAA;AAGN,CAAC;AAkBD,MAAM,YAAY,KAAK,SAASC,WAAU;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AACF,GAAuC;AACrC,SACE,qBAAC,OAAA,EAAI,OAAO,gBACV,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACL,GAAG,SAAS,KAAK;AAAA,UACjB,WAAW,OAAO,WAAW,KAAK,KAAK;AAAA,QAAA;AAAA,MACzC;AAAA,IAAA;AAAA,IAEF;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACL,SAAS;AAAA,UACT,gBAAgB;AAAA,UAChB,YAAY;AAAA,UACZ,UAAU,OAAO,WAAW,SAAS;AAAA,UACrC,YAAY,OAAO,OAAO,WAAW,WAAW,WAAW,OAAO,WAAW,WAAW;AAAA,QAAA;AAAA,QAG1F,UAAA;AAAA,UAAA,oBAAC,QAAA,EAAK,OAAO,EAAE,OAAO,OAAO,OAAO,OAAO,KAAK,UAAU,OAAO,OAAO,KAAK,aAAc,UAAA,OAAM;AAAA,UACjG;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO;AAAA,gBACL,YAAY,OAAO,WAAW,WAAW;AAAA,gBACzC,OAAO,OAAO,OAAO,OAAO,KAAK,UAAU;AAAA,gBAC3C,oBAAoB;AAAA,cAAA;AAAA,cAGrB,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACH;AAAA,MAAA;AAAA,IAAA;AAAA,IAED,WACC,oBAAC,OAAA,EAAI,OAAO,EAAE,UAAU,OAAO,WAAW,SAAS,KAAK,OAAO,OAAO,OAAO,KAAK,SAAA,GAAa,UAAA,QAAA,CAAQ;AAAA,EAAA,GAE3G;AAEJ,CAAC;"}