@almadar/ui 5.49.0 → 5.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,16 @@
1
- import * as React83 from 'react';
2
- import React83__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState, useLayoutEffect, lazy, useId, useSyncExternalStore, forwardRef, useImperativeHandle, Component } from 'react';
1
+ import * as React82 from 'react';
2
+ import React82__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState, useLayoutEffect, lazy, useId, useSyncExternalStore, forwardRef, useImperativeHandle, Component } from 'react';
3
+ import { EventBusContext, useTraitScope, TraitScopeProvider } from '@almadar/ui/providers';
3
4
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
4
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
- import { EventBusContext, useTraitScope, TraitScopeProvider } from '@almadar/ui/providers';
6
6
  import { clsx } from 'clsx';
7
7
  import { twMerge } from 'tailwind-merge';
8
8
  import * as LucideIcons2 from 'lucide-react';
9
9
  import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ZoomOut, ZoomIn, Download, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, ArrowLeft, HelpCircle, PauseCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, Bug, Send, ChevronUp, ChevronDown, Wrench, Tag, User, DollarSign, Zap, Sword, Move, Heart, Shield } from 'lucide-react';
10
10
  import { createPortal } from 'react-dom';
11
11
  import { useTranslate } from '@almadar/ui/hooks';
12
+ import { useUISlots, ThemeProvider, useTheme } from '@almadar/ui/context';
12
13
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
13
- import { useUISlots } from '@almadar/ui/context';
14
14
  import { Link, Outlet, useLocation } from 'react-router-dom';
15
15
  import ELK from 'elkjs/lib/elk.bundled.js';
16
16
  import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light.js';
@@ -41,12 +41,12 @@ import { DndContext, pointerWithin, rectIntersection, closestCorners, useSensors
41
41
  import { useSortable, arrayMove, sortableKeyboardCoordinates, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
42
42
  import { CSS } from '@dnd-kit/utilities';
43
43
  import { useNodeId, ReactFlowProvider, Handle, Position } from '@xyflow/react';
44
- import * as THREE from 'three';
44
+ import * as THREE3 from 'three';
45
45
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
46
46
  import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
47
47
  import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
48
- import { Canvas, useThree } from '@react-three/fiber';
49
- import { Grid as Grid$1, OrbitControls } from '@react-three/drei';
48
+ import { Canvas, useLoader, useFrame, useThree } from '@react-three/fiber';
49
+ import { Billboard, Grid as Grid$1, OrbitControls } from '@react-three/drei';
50
50
  import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
51
51
 
52
52
  var __defProp = Object.defineProperty;
@@ -71,312 +71,6 @@ var __copyProps = (to, from, except, desc) => {
71
71
  };
72
72
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
73
73
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
74
- function getSystemMode() {
75
- if (typeof window === "undefined") return "light";
76
- return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
77
- }
78
- function resolveMode(mode) {
79
- if (mode === "system") {
80
- return getSystemMode();
81
- }
82
- return mode;
83
- }
84
- function useTheme() {
85
- const context = useContext(ThemeContext);
86
- if (context === void 0) {
87
- return {
88
- theme: "wireframe",
89
- mode: "light",
90
- resolvedMode: "light",
91
- setTheme: () => {
92
- },
93
- setMode: () => {
94
- },
95
- toggleMode: () => {
96
- },
97
- availableThemes: BUILT_IN_THEMES,
98
- appliedTheme: "wireframe-light"
99
- };
100
- }
101
- return context;
102
- }
103
- var log, BUILT_IN_THEMES, ThemeContext, THEME_STORAGE_KEY, MODE_STORAGE_KEY, ThemeProvider;
104
- var init_ThemeContext = __esm({
105
- "context/ThemeContext.tsx"() {
106
- "use client";
107
- log = createLogger("almadar:ui:theme");
108
- BUILT_IN_THEMES = [
109
- {
110
- name: "wireframe",
111
- displayName: "Wireframe",
112
- hasLightMode: true,
113
- hasDarkMode: true
114
- },
115
- {
116
- name: "minimalist",
117
- displayName: "Minimalist",
118
- hasLightMode: true,
119
- hasDarkMode: true
120
- },
121
- {
122
- name: "almadar",
123
- displayName: "Almadar",
124
- hasLightMode: true,
125
- hasDarkMode: true
126
- },
127
- {
128
- name: "trait-wars",
129
- displayName: "Trait Wars",
130
- hasLightMode: false,
131
- hasDarkMode: true
132
- },
133
- // Extended themes
134
- {
135
- name: "ocean",
136
- displayName: "Ocean",
137
- hasLightMode: true,
138
- hasDarkMode: true
139
- },
140
- {
141
- name: "forest",
142
- displayName: "Forest",
143
- hasLightMode: true,
144
- hasDarkMode: true
145
- },
146
- {
147
- name: "sunset",
148
- displayName: "Sunset",
149
- hasLightMode: true,
150
- hasDarkMode: true
151
- },
152
- {
153
- name: "lavender",
154
- displayName: "Lavender",
155
- hasLightMode: true,
156
- hasDarkMode: true
157
- },
158
- {
159
- name: "rose",
160
- displayName: "Rose",
161
- hasLightMode: true,
162
- hasDarkMode: true
163
- },
164
- {
165
- name: "slate",
166
- displayName: "Slate",
167
- hasLightMode: true,
168
- hasDarkMode: true
169
- },
170
- {
171
- name: "ember",
172
- displayName: "Ember",
173
- hasLightMode: true,
174
- hasDarkMode: true
175
- },
176
- {
177
- name: "midnight",
178
- displayName: "Midnight",
179
- hasLightMode: true,
180
- hasDarkMode: true
181
- },
182
- {
183
- name: "sand",
184
- displayName: "Sand",
185
- hasLightMode: true,
186
- hasDarkMode: true
187
- },
188
- {
189
- name: "neon",
190
- displayName: "Neon",
191
- hasLightMode: true,
192
- hasDarkMode: true
193
- },
194
- {
195
- name: "arctic",
196
- displayName: "Arctic",
197
- hasLightMode: true,
198
- hasDarkMode: true
199
- },
200
- {
201
- name: "copper",
202
- displayName: "Copper",
203
- hasLightMode: true,
204
- hasDarkMode: true
205
- },
206
- // Layer 1 skin axes — truly-unique themes (compact tech / editorial / brutalist dense / display-heavy / touch-first)
207
- {
208
- name: "prism",
209
- displayName: "Prism",
210
- hasLightMode: true,
211
- hasDarkMode: true
212
- },
213
- {
214
- name: "gazette",
215
- displayName: "Gazette",
216
- hasLightMode: true,
217
- hasDarkMode: true
218
- },
219
- {
220
- name: "terminal",
221
- displayName: "Terminal",
222
- hasLightMode: true,
223
- hasDarkMode: true
224
- },
225
- {
226
- name: "atelier",
227
- displayName: "Atelier",
228
- hasLightMode: true,
229
- hasDarkMode: true
230
- },
231
- {
232
- name: "kiosk",
233
- displayName: "Kiosk",
234
- hasLightMode: true,
235
- hasDarkMode: true
236
- },
237
- {
238
- name: "linear-clean",
239
- displayName: "Linear Clean",
240
- hasLightMode: true,
241
- hasDarkMode: true
242
- },
243
- {
244
- name: "notion-editorial",
245
- displayName: "Notion Editorial",
246
- hasLightMode: true,
247
- hasDarkMode: true
248
- },
249
- {
250
- name: "bloomberg-dense",
251
- displayName: "Bloomberg Dense",
252
- hasLightMode: true,
253
- hasDarkMode: true
254
- }
255
- ];
256
- ThemeContext = createContext(void 0);
257
- THEME_STORAGE_KEY = "theme";
258
- MODE_STORAGE_KEY = "theme-mode";
259
- ThemeProvider = ({
260
- children,
261
- themes = [],
262
- defaultTheme = "wireframe",
263
- defaultMode = "system",
264
- targetRef
265
- }) => {
266
- const availableThemes = useMemo(() => {
267
- const themeMap = /* @__PURE__ */ new Map();
268
- BUILT_IN_THEMES.forEach((t) => themeMap.set(t.name, t));
269
- themes.forEach((t) => themeMap.set(t.name, t));
270
- return Array.from(themeMap.values());
271
- }, [themes]);
272
- const isScoped = !!targetRef;
273
- const [theme, setThemeState] = useState(() => {
274
- if (isScoped || typeof window === "undefined") return defaultTheme;
275
- const stored = localStorage.getItem(THEME_STORAGE_KEY);
276
- const validThemes = [
277
- ...BUILT_IN_THEMES.map((t) => t.name),
278
- ...themes.map((t) => t.name)
279
- ];
280
- if (stored && validThemes.includes(stored)) {
281
- return stored;
282
- }
283
- return defaultTheme;
284
- });
285
- const [mode, setModeState] = useState(() => {
286
- if (isScoped || typeof window === "undefined") return defaultMode;
287
- const stored = localStorage.getItem(MODE_STORAGE_KEY);
288
- if (stored === "light" || stored === "dark" || stored === "system") {
289
- return stored;
290
- }
291
- return defaultMode;
292
- });
293
- const [resolvedMode, setResolvedMode] = useState(
294
- () => resolveMode(mode)
295
- );
296
- const appliedTheme = useMemo(
297
- () => `${theme}-${resolvedMode}`,
298
- [theme, resolvedMode]
299
- );
300
- useEffect(() => {
301
- const updateResolved = () => {
302
- setResolvedMode(resolveMode(mode));
303
- };
304
- updateResolved();
305
- if (mode === "system") {
306
- const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
307
- const handleChange = () => updateResolved();
308
- mediaQuery.addEventListener("change", handleChange);
309
- return () => mediaQuery.removeEventListener("change", handleChange);
310
- }
311
- return void 0;
312
- }, [mode]);
313
- useEffect(() => {
314
- if (isScoped) {
315
- if (targetRef?.current) {
316
- targetRef.current.setAttribute("data-theme", appliedTheme);
317
- targetRef.current.classList.remove("light", "dark");
318
- targetRef.current.classList.add(resolvedMode);
319
- }
320
- return;
321
- }
322
- const root = document.documentElement;
323
- root.setAttribute("data-theme", appliedTheme);
324
- root.classList.remove("light", "dark");
325
- root.classList.add(resolvedMode);
326
- }, [appliedTheme, resolvedMode, targetRef, isScoped]);
327
- const setTheme = useCallback(
328
- (newTheme) => {
329
- const validTheme = availableThemes.find((t) => t.name === newTheme);
330
- if (validTheme) {
331
- setThemeState(newTheme);
332
- if (!isScoped && typeof window !== "undefined") {
333
- localStorage.setItem(THEME_STORAGE_KEY, newTheme);
334
- }
335
- } else {
336
- log.warn("Theme not found", {
337
- theme: newTheme,
338
- available: availableThemes.map((t) => t.name)
339
- });
340
- }
341
- },
342
- [availableThemes]
343
- );
344
- const setMode = useCallback((newMode) => {
345
- setModeState(newMode);
346
- if (!isScoped && typeof window !== "undefined") {
347
- localStorage.setItem(MODE_STORAGE_KEY, newMode);
348
- }
349
- }, []);
350
- const toggleMode = useCallback(() => {
351
- const newMode = resolvedMode === "dark" ? "light" : "dark";
352
- setMode(newMode);
353
- }, [resolvedMode, setMode]);
354
- const contextValue = useMemo(
355
- () => ({
356
- theme,
357
- mode,
358
- resolvedMode,
359
- setTheme,
360
- setMode,
361
- toggleMode,
362
- availableThemes,
363
- appliedTheme
364
- }),
365
- [
366
- theme,
367
- mode,
368
- resolvedMode,
369
- setTheme,
370
- setMode,
371
- toggleMode,
372
- availableThemes,
373
- appliedTheme
374
- ]
375
- );
376
- return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: contextValue, children });
377
- };
378
- }
379
- });
380
74
 
381
75
  // hooks/useEventBus.ts
382
76
  var useEventBus_exports = {};
@@ -461,11 +155,11 @@ function useEmitEvent() {
461
155
  [eventBus]
462
156
  );
463
157
  }
464
- var log2, subLog, scopeLog, fallbackListeners, fallbackAnyListeners, fallbackEventBus, useEventSubscription, useEventBus_default;
158
+ var log, subLog, scopeLog, fallbackListeners, fallbackAnyListeners, fallbackEventBus, useEventSubscription, useEventBus_default;
465
159
  var init_useEventBus = __esm({
466
160
  "hooks/useEventBus.ts"() {
467
161
  "use client";
468
- log2 = createLogger("almadar:eventbus");
162
+ log = createLogger("almadar:eventbus");
469
163
  subLog = createLogger("almadar:eventbus:subscribe");
470
164
  scopeLog = createLogger("almadar:ui:trait-scope");
471
165
  fallbackListeners = /* @__PURE__ */ new Map();
@@ -479,13 +173,13 @@ var init_useEventBus = __esm({
479
173
  source
480
174
  };
481
175
  const handlers = fallbackListeners.get(type);
482
- log2.debug("emit", { type, payloadKeys: payload ? Object.keys(payload).length : 0, listenerCount: (handlers?.size ?? 0) + fallbackAnyListeners.size });
176
+ log.debug("emit", { type, payloadKeys: payload ? Object.keys(payload).length : 0, listenerCount: (handlers?.size ?? 0) + fallbackAnyListeners.size });
483
177
  if (handlers) {
484
178
  handlers.forEach((handler) => {
485
179
  try {
486
180
  handler(event);
487
181
  } catch (error) {
488
- log2.error("Error in listener", { type, error: error instanceof Error ? error : String(error) });
182
+ log.error("Error in listener", { type, error: error instanceof Error ? error : String(error) });
489
183
  }
490
184
  });
491
185
  }
@@ -493,7 +187,7 @@ var init_useEventBus = __esm({
493
187
  try {
494
188
  handler(event);
495
189
  } catch (error) {
496
- log2.error("Error in onAny listener", { type, error: error instanceof Error ? error : String(error) });
190
+ log.error("Error in onAny listener", { type, error: error instanceof Error ? error : String(error) });
497
191
  }
498
192
  });
499
193
  },
@@ -660,7 +354,7 @@ var init_Box = __esm({
660
354
  fixed: "fixed",
661
355
  sticky: "sticky"
662
356
  };
663
- Box = React83__default.forwardRef(
357
+ Box = React82__default.forwardRef(
664
358
  ({
665
359
  padding,
666
360
  paddingX,
@@ -710,7 +404,7 @@ var init_Box = __esm({
710
404
  onMouseLeave?.(e);
711
405
  }, [hoverEvent, eventBus, onMouseLeave]);
712
406
  const isClickable = action || onClick;
713
- return React83__default.createElement(
407
+ return React82__default.createElement(
714
408
  Component2,
715
409
  {
716
410
  ref,
@@ -805,7 +499,7 @@ function loadLib(key, importer) {
805
499
  return p2;
806
500
  }
807
501
  function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
808
- const Lazy = React83__default.lazy(async () => {
502
+ const Lazy = React82__default.lazy(async () => {
809
503
  const lib = await loadLib(libKey, importer);
810
504
  const Comp = pick(lib);
811
505
  if (!Comp) {
@@ -815,7 +509,7 @@ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
815
509
  return { default: Comp };
816
510
  });
817
511
  const Wrapped = (props) => /* @__PURE__ */ jsx(
818
- React83__default.Suspense,
512
+ React82__default.Suspense,
819
513
  {
820
514
  fallback: /* @__PURE__ */ jsx(
821
515
  "span",
@@ -1541,7 +1235,7 @@ var init_Icon = __esm({
1541
1235
  const directIcon = typeof icon === "string" ? void 0 : icon;
1542
1236
  const effectiveName = typeof icon === "string" ? icon : name;
1543
1237
  const family = useIconFamily();
1544
- const RenderedComponent = React83__default.useMemo(() => {
1238
+ const RenderedComponent = React82__default.useMemo(() => {
1545
1239
  if (directIcon) return null;
1546
1240
  return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
1547
1241
  }, [directIcon, effectiveName, family]);
@@ -1600,7 +1294,7 @@ function resolveIconProp(value, sizeClass) {
1600
1294
  const IconComp = value;
1601
1295
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
1602
1296
  }
1603
- if (React83__default.isValidElement(value)) {
1297
+ if (React82__default.isValidElement(value)) {
1604
1298
  return value;
1605
1299
  }
1606
1300
  if (typeof value === "object" && value !== null && "render" in value) {
@@ -1676,7 +1370,7 @@ var init_Button = __esm({
1676
1370
  md: "h-icon-default w-icon-default",
1677
1371
  lg: "h-icon-default w-icon-default"
1678
1372
  };
1679
- Button = React83__default.forwardRef(
1373
+ Button = React82__default.forwardRef(
1680
1374
  ({
1681
1375
  className,
1682
1376
  variant = "primary",
@@ -1741,7 +1435,7 @@ var Dialog;
1741
1435
  var init_Dialog = __esm({
1742
1436
  "components/core/atoms/Dialog.tsx"() {
1743
1437
  init_cn();
1744
- Dialog = React83__default.forwardRef(
1438
+ Dialog = React82__default.forwardRef(
1745
1439
  ({
1746
1440
  role = "dialog",
1747
1441
  "aria-modal": ariaModal = true,
@@ -2355,7 +2049,7 @@ var init_Badge = __esm({
2355
2049
  md: "px-2.5 py-1 text-sm",
2356
2050
  lg: "px-3 py-1.5 text-base"
2357
2051
  };
2358
- Badge = React83__default.forwardRef(
2052
+ Badge = React82__default.forwardRef(
2359
2053
  ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
2360
2054
  const iconSizes3 = {
2361
2055
  sm: "h-icon-default w-icon-default",
@@ -2691,7 +2385,7 @@ var init_SvgFlow = __esm({
2691
2385
  width = 100,
2692
2386
  height = 100
2693
2387
  }) => {
2694
- const markerId = React83__default.useMemo(() => {
2388
+ const markerId = React82__default.useMemo(() => {
2695
2389
  flowIdCounter += 1;
2696
2390
  return `almadar-flow-arrow-${flowIdCounter}`;
2697
2391
  }, []);
@@ -3284,7 +2978,7 @@ var init_SvgRing = __esm({
3284
2978
  width = 100,
3285
2979
  height = 100
3286
2980
  }) => {
3287
- const gradientId = React83__default.useMemo(() => {
2981
+ const gradientId = React82__default.useMemo(() => {
3288
2982
  ringIdCounter += 1;
3289
2983
  return `almadar-ring-glow-${ringIdCounter}`;
3290
2984
  }, []);
@@ -3465,7 +3159,7 @@ var init_Input = __esm({
3465
3159
  init_cn();
3466
3160
  init_Icon();
3467
3161
  init_useEventBus();
3468
- Input = React83__default.forwardRef(
3162
+ Input = React82__default.forwardRef(
3469
3163
  ({
3470
3164
  className,
3471
3165
  inputType,
@@ -3625,7 +3319,7 @@ var Label;
3625
3319
  var init_Label = __esm({
3626
3320
  "components/core/atoms/Label.tsx"() {
3627
3321
  init_cn();
3628
- Label = React83__default.forwardRef(
3322
+ Label = React82__default.forwardRef(
3629
3323
  ({ className, required, children, ...props }, ref) => {
3630
3324
  return /* @__PURE__ */ jsxs(
3631
3325
  "label",
@@ -3652,7 +3346,7 @@ var init_Textarea = __esm({
3652
3346
  "components/core/atoms/Textarea.tsx"() {
3653
3347
  init_cn();
3654
3348
  init_useEventBus();
3655
- Textarea = React83__default.forwardRef(
3349
+ Textarea = React82__default.forwardRef(
3656
3350
  ({ className, error, onChange, ...props }, ref) => {
3657
3351
  const eventBus = useEventBus();
3658
3352
  const handleChange = (e) => {
@@ -3891,7 +3585,7 @@ var init_Select = __esm({
3891
3585
  init_cn();
3892
3586
  init_Icon();
3893
3587
  init_useEventBus();
3894
- Select = React83__default.forwardRef(
3588
+ Select = React82__default.forwardRef(
3895
3589
  (props, _ref) => {
3896
3590
  const { multiple, searchable, clearable } = props;
3897
3591
  if (multiple || searchable || clearable) {
@@ -3908,7 +3602,7 @@ var init_Checkbox = __esm({
3908
3602
  "components/core/atoms/Checkbox.tsx"() {
3909
3603
  init_cn();
3910
3604
  init_useEventBus();
3911
- Checkbox = React83__default.forwardRef(
3605
+ Checkbox = React82__default.forwardRef(
3912
3606
  ({ className, label, id, onChange, ...props }, ref) => {
3913
3607
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
3914
3608
  const eventBus = useEventBus();
@@ -3962,7 +3656,7 @@ var init_Spinner = __esm({
3962
3656
  md: "h-6 w-6",
3963
3657
  lg: "h-8 w-8"
3964
3658
  };
3965
- Spinner = React83__default.forwardRef(
3659
+ Spinner = React82__default.forwardRef(
3966
3660
  ({ className, size = "md", overlay, ...props }, ref) => {
3967
3661
  if (overlay) {
3968
3662
  return /* @__PURE__ */ jsx(
@@ -4052,7 +3746,7 @@ var init_Card = __esm({
4052
3746
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
4053
3747
  "tile-image-first": "p-0 overflow-hidden"
4054
3748
  };
4055
- Card = React83__default.forwardRef(
3749
+ Card = React82__default.forwardRef(
4056
3750
  ({
4057
3751
  className,
4058
3752
  variant = "bordered",
@@ -4100,9 +3794,9 @@ var init_Card = __esm({
4100
3794
  }
4101
3795
  );
4102
3796
  Card.displayName = "Card";
4103
- CardHeader = React83__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
3797
+ CardHeader = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
4104
3798
  CardHeader.displayName = "CardHeader";
4105
- CardTitle = React83__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3799
+ CardTitle = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4106
3800
  "h3",
4107
3801
  {
4108
3802
  ref,
@@ -4115,11 +3809,11 @@ var init_Card = __esm({
4115
3809
  }
4116
3810
  ));
4117
3811
  CardTitle.displayName = "CardTitle";
4118
- CardContent = React83__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
3812
+ CardContent = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
4119
3813
  CardContent.displayName = "CardContent";
4120
3814
  CardBody = CardContent;
4121
3815
  CardBody.displayName = "CardBody";
4122
- CardFooter = React83__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3816
+ CardFooter = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4123
3817
  "div",
4124
3818
  {
4125
3819
  ref,
@@ -4174,7 +3868,7 @@ var init_FilterPill = __esm({
4174
3868
  md: "w-3.5 h-3.5",
4175
3869
  lg: "w-4 h-4"
4176
3870
  };
4177
- FilterPill = React83__default.forwardRef(
3871
+ FilterPill = React82__default.forwardRef(
4178
3872
  ({
4179
3873
  className,
4180
3874
  variant = "default",
@@ -4303,8 +3997,8 @@ var init_Avatar = __esm({
4303
3997
  actionPayload
4304
3998
  }) => {
4305
3999
  const eventBus = useEventBus();
4306
- const [imgFailed, setImgFailed] = React83__default.useState(false);
4307
- React83__default.useEffect(() => {
4000
+ const [imgFailed, setImgFailed] = React82__default.useState(false);
4001
+ React82__default.useEffect(() => {
4308
4002
  setImgFailed(false);
4309
4003
  }, [src]);
4310
4004
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -4689,7 +4383,7 @@ var init_Radio = __esm({
4689
4383
  md: "w-2.5 h-2.5",
4690
4384
  lg: "w-3 h-3"
4691
4385
  };
4692
- Radio = React83__default.forwardRef(
4386
+ Radio = React82__default.forwardRef(
4693
4387
  ({
4694
4388
  label,
4695
4389
  helperText,
@@ -4706,12 +4400,12 @@ var init_Radio = __esm({
4706
4400
  onChange,
4707
4401
  ...props
4708
4402
  }, ref) => {
4709
- const reactId = React83__default.useId();
4403
+ const reactId = React82__default.useId();
4710
4404
  const baseId = id || `radio-${reactId}`;
4711
4405
  const hasError = !!error;
4712
4406
  const eventBus = useEventBus();
4713
- const [selected, setSelected] = React83__default.useState(value);
4714
- React83__default.useEffect(() => {
4407
+ const [selected, setSelected] = React82__default.useState(value);
4408
+ React82__default.useEffect(() => {
4715
4409
  if (value !== void 0) setSelected(value);
4716
4410
  }, [value]);
4717
4411
  const pick = (next, e) => {
@@ -4893,7 +4587,7 @@ var init_Switch = __esm({
4893
4587
  "components/core/atoms/Switch.tsx"() {
4894
4588
  "use client";
4895
4589
  init_cn();
4896
- Switch = React83.forwardRef(
4590
+ Switch = React82.forwardRef(
4897
4591
  ({
4898
4592
  checked,
4899
4593
  defaultChecked = false,
@@ -4904,10 +4598,10 @@ var init_Switch = __esm({
4904
4598
  name,
4905
4599
  className
4906
4600
  }, ref) => {
4907
- const [isChecked, setIsChecked] = React83.useState(
4601
+ const [isChecked, setIsChecked] = React82.useState(
4908
4602
  checked !== void 0 ? checked : defaultChecked
4909
4603
  );
4910
- React83.useEffect(() => {
4604
+ React82.useEffect(() => {
4911
4605
  if (checked !== void 0) {
4912
4606
  setIsChecked(checked);
4913
4607
  }
@@ -5168,7 +4862,6 @@ var init_ThemeToggle = __esm({
5168
4862
  "use client";
5169
4863
  init_Icon();
5170
4864
  init_cn();
5171
- init_ThemeContext();
5172
4865
  sizeClasses5 = {
5173
4866
  sm: "p-1.5",
5174
4867
  md: "p-2",
@@ -5263,7 +4956,7 @@ var Aside;
5263
4956
  var init_Aside = __esm({
5264
4957
  "components/core/atoms/Aside.tsx"() {
5265
4958
  init_cn();
5266
- Aside = React83__default.forwardRef(
4959
+ Aside = React82__default.forwardRef(
5267
4960
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
5268
4961
  );
5269
4962
  Aside.displayName = "Aside";
@@ -5341,8 +5034,8 @@ var init_LawReferenceTooltip = __esm({
5341
5034
  className
5342
5035
  }) => {
5343
5036
  const { t } = useTranslate();
5344
- const [isVisible, setIsVisible] = React83__default.useState(false);
5345
- const timeoutRef = React83__default.useRef(null);
5037
+ const [isVisible, setIsVisible] = React82__default.useState(false);
5038
+ const timeoutRef = React82__default.useRef(null);
5346
5039
  const handleMouseEnter = () => {
5347
5040
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
5348
5041
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -5351,7 +5044,7 @@ var init_LawReferenceTooltip = __esm({
5351
5044
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
5352
5045
  setIsVisible(false);
5353
5046
  };
5354
- React83__default.useEffect(() => {
5047
+ React82__default.useEffect(() => {
5355
5048
  return () => {
5356
5049
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
5357
5050
  };
@@ -5561,7 +5254,7 @@ var init_StatusDot = __esm({
5561
5254
  md: "w-2.5 h-2.5",
5562
5255
  lg: "w-3 h-3"
5563
5256
  };
5564
- StatusDot = React83__default.forwardRef(
5257
+ StatusDot = React82__default.forwardRef(
5565
5258
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
5566
5259
  return /* @__PURE__ */ jsx(
5567
5260
  "span",
@@ -5615,7 +5308,7 @@ var init_TrendIndicator = __esm({
5615
5308
  down: "trending-down",
5616
5309
  flat: "arrow-right"
5617
5310
  };
5618
- TrendIndicator = React83__default.forwardRef(
5311
+ TrendIndicator = React82__default.forwardRef(
5619
5312
  ({
5620
5313
  className,
5621
5314
  value,
@@ -5682,7 +5375,7 @@ var init_RangeSlider = __esm({
5682
5375
  md: "w-4 h-4",
5683
5376
  lg: "w-5 h-5"
5684
5377
  };
5685
- RangeSlider = React83__default.forwardRef(
5378
+ RangeSlider = React82__default.forwardRef(
5686
5379
  ({
5687
5380
  className,
5688
5381
  min = 0,
@@ -6190,7 +5883,7 @@ var init_ContentSection = __esm({
6190
5883
  md: "py-16",
6191
5884
  lg: "py-24"
6192
5885
  };
6193
- ContentSection = React83__default.forwardRef(
5886
+ ContentSection = React82__default.forwardRef(
6194
5887
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
6195
5888
  return /* @__PURE__ */ jsx(
6196
5889
  Box,
@@ -6724,7 +6417,7 @@ var init_AnimatedReveal = __esm({
6724
6417
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
6725
6418
  "none": {}
6726
6419
  };
6727
- AnimatedReveal = React83__default.forwardRef(
6420
+ AnimatedReveal = React82__default.forwardRef(
6728
6421
  ({
6729
6422
  trigger = "scroll",
6730
6423
  animation = "fade-up",
@@ -6884,7 +6577,7 @@ var init_AnimatedGraphic = __esm({
6884
6577
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
6885
6578
  "use client";
6886
6579
  init_cn();
6887
- AnimatedGraphic = React83__default.forwardRef(
6580
+ AnimatedGraphic = React82__default.forwardRef(
6888
6581
  ({
6889
6582
  src,
6890
6583
  svgContent,
@@ -6907,7 +6600,7 @@ var init_AnimatedGraphic = __esm({
6907
6600
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
6908
6601
  const resolvedSvg = svgContent ?? fetchedSvg;
6909
6602
  const prevAnimateRef = useRef(animate);
6910
- const setRef = React83__default.useCallback(
6603
+ const setRef = React82__default.useCallback(
6911
6604
  (node) => {
6912
6605
  containerRef.current = node;
6913
6606
  if (typeof ref === "function") ref(node);
@@ -7133,9 +6826,9 @@ function ScoreDisplay({
7133
6826
  ...rest
7134
6827
  }) {
7135
6828
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof rest.score === "number" && !Number.isNaN(rest.score) ? rest.score : 0;
7136
- const [displayValue, setDisplayValue] = React83.useState(resolvedValue);
7137
- const [isAnimating, setIsAnimating] = React83.useState(false);
7138
- React83.useEffect(() => {
6829
+ const [displayValue, setDisplayValue] = React82.useState(resolvedValue);
6830
+ const [isAnimating, setIsAnimating] = React82.useState(false);
6831
+ React82.useEffect(() => {
7139
6832
  if (!animated || displayValue === resolvedValue) {
7140
6833
  setDisplayValue(resolvedValue);
7141
6834
  return;
@@ -7218,9 +6911,9 @@ function ControlButton({
7218
6911
  className
7219
6912
  }) {
7220
6913
  const eventBus = useEventBus();
7221
- const [isPressed, setIsPressed] = React83.useState(false);
6914
+ const [isPressed, setIsPressed] = React82.useState(false);
7222
6915
  const actualPressed = pressed ?? isPressed;
7223
- const handlePointerDown = React83.useCallback(
6916
+ const handlePointerDown = React82.useCallback(
7224
6917
  (e) => {
7225
6918
  e.preventDefault();
7226
6919
  if (disabled) return;
@@ -7230,7 +6923,7 @@ function ControlButton({
7230
6923
  },
7231
6924
  [disabled, pressEvent, eventBus, onPress]
7232
6925
  );
7233
- const handlePointerUp = React83.useCallback(
6926
+ const handlePointerUp = React82.useCallback(
7234
6927
  (e) => {
7235
6928
  e.preventDefault();
7236
6929
  if (disabled) return;
@@ -7240,7 +6933,7 @@ function ControlButton({
7240
6933
  },
7241
6934
  [disabled, releaseEvent, eventBus, onRelease]
7242
6935
  );
7243
- const handlePointerLeave = React83.useCallback(
6936
+ const handlePointerLeave = React82.useCallback(
7244
6937
  (e) => {
7245
6938
  if (isPressed) {
7246
6939
  setIsPressed(false);
@@ -7318,6 +7011,52 @@ var init_ControlButton = __esm({
7318
7011
  ControlButton.displayName = "ControlButton";
7319
7012
  }
7320
7013
  });
7014
+
7015
+ // components/game/organisms/utils/spriteAnimation.ts
7016
+ function inferDirection(dx, dy) {
7017
+ if (dx === 0 && dy === 0) return "se";
7018
+ if (dx >= 0 && dy >= 0) return "se";
7019
+ if (dx <= 0 && dy >= 0) return "sw";
7020
+ if (dx >= 0 && dy <= 0) return "ne";
7021
+ return "nw";
7022
+ }
7023
+ function resolveSheetDirection(facing) {
7024
+ switch (facing) {
7025
+ case "se":
7026
+ return { sheetDir: "se", flipX: false };
7027
+ case "sw":
7028
+ return { sheetDir: "sw", flipX: false };
7029
+ case "ne":
7030
+ return { sheetDir: "sw", flipX: true };
7031
+ case "nw":
7032
+ return { sheetDir: "se", flipX: true };
7033
+ }
7034
+ }
7035
+ function frameRect(frame, row, columns, frameWidth, frameHeight) {
7036
+ return {
7037
+ sx: frame % columns * frameWidth,
7038
+ sy: row * frameHeight,
7039
+ sw: frameWidth,
7040
+ sh: frameHeight
7041
+ };
7042
+ }
7043
+ function getCurrentFrameFromDef(def, elapsed) {
7044
+ const frameDuration = 1e3 / def.frameRate;
7045
+ const totalDuration = def.frames * frameDuration;
7046
+ if (def.loop) {
7047
+ const frame2 = Math.floor(elapsed % totalDuration / frameDuration);
7048
+ return { frame: frame2, finished: false };
7049
+ }
7050
+ if (elapsed >= totalDuration) {
7051
+ return { frame: def.frames - 1, finished: true };
7052
+ }
7053
+ const frame = Math.floor(elapsed / frameDuration);
7054
+ return { frame, finished: false };
7055
+ }
7056
+ var init_spriteAnimation = __esm({
7057
+ "components/game/organisms/utils/spriteAnimation.ts"() {
7058
+ }
7059
+ });
7321
7060
  function Sprite({
7322
7061
  spritesheet = "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
7323
7062
  frameWidth = 64,
@@ -7338,12 +7077,8 @@ function Sprite({
7338
7077
  }) {
7339
7078
  const eventBus = useEventBus();
7340
7079
  const sourcePosition = useMemo(() => {
7341
- const frameX = frame % columns;
7342
- const frameY = Math.floor(frame / columns);
7343
- return {
7344
- x: frameX * frameWidth,
7345
- y: frameY * frameHeight
7346
- };
7080
+ const { sx, sy } = frameRect(frame, Math.floor(frame / columns), columns, frameWidth, frameHeight);
7081
+ return { x: sx, y: sy };
7347
7082
  }, [frame, columns, frameWidth, frameHeight]);
7348
7083
  const transform = useMemo(() => {
7349
7084
  const transforms = [
@@ -7391,6 +7126,7 @@ var init_Sprite = __esm({
7391
7126
  "components/game/atoms/Sprite.tsx"() {
7392
7127
  "use client";
7393
7128
  init_useEventBus();
7129
+ init_spriteAnimation();
7394
7130
  }
7395
7131
  });
7396
7132
  function StateIndicator({
@@ -7818,8 +7554,8 @@ function XPBar({
7818
7554
  }) {
7819
7555
  const sizes = sizeMap9[size];
7820
7556
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
7821
- const [fillWidth, setFillWidth] = React83.useState(animated ? 0 : percentage);
7822
- React83.useEffect(() => {
7557
+ const [fillWidth, setFillWidth] = React82.useState(animated ? 0 : percentage);
7558
+ React82.useEffect(() => {
7823
7559
  if (!animated) {
7824
7560
  setFillWidth(percentage);
7825
7561
  return;
@@ -8307,9 +8043,9 @@ function MiniMap({
8307
8043
  viewportRect = DEFAULT_VIEWPORT,
8308
8044
  className
8309
8045
  }) {
8310
- const canvasRef = React83.useRef(null);
8311
- const frameRef = React83.useRef(0);
8312
- React83.useEffect(() => {
8046
+ const canvasRef = React82.useRef(null);
8047
+ const frameRef = React82.useRef(0);
8048
+ React82.useEffect(() => {
8313
8049
  const canvas = canvasRef.current;
8314
8050
  if (!canvas) return;
8315
8051
  const ctx = canvas.getContext("2d");
@@ -8498,7 +8234,7 @@ var init_ErrorBoundary = __esm({
8498
8234
  }
8499
8235
  );
8500
8236
  };
8501
- ErrorBoundary = class extends React83__default.Component {
8237
+ ErrorBoundary = class extends React82__default.Component {
8502
8238
  constructor(props) {
8503
8239
  super(props);
8504
8240
  __publicField(this, "reset", () => {
@@ -8651,7 +8387,7 @@ function executeClientEffects(effects, config) {
8651
8387
  try {
8652
8388
  executeEffect(effect, config);
8653
8389
  } catch (error) {
8654
- log4.error("Error executing effect", () => ({
8390
+ log3.error("Error executing effect", () => ({
8655
8391
  effect: JSON.stringify(effect),
8656
8392
  error: error instanceof Error ? error : String(error)
8657
8393
  }));
@@ -8683,7 +8419,7 @@ function executeEffect(effect, config) {
8683
8419
  break;
8684
8420
  }
8685
8421
  default:
8686
- log4.warn("Unknown effect type", { effectType: String(effectType) });
8422
+ log3.warn("Unknown effect type", { effectType: String(effectType) });
8687
8423
  }
8688
8424
  }
8689
8425
  function executeRenderUI(slot, patternConfig, config) {
@@ -8698,10 +8434,10 @@ function executeNotify(message, options, config) {
8698
8434
  function executeEmit(event, payload, config) {
8699
8435
  config.eventBus.emit(event, payload);
8700
8436
  }
8701
- var log4;
8437
+ var log3;
8702
8438
  var init_client_effect_executor = __esm({
8703
8439
  "renderer/client-effect-executor.ts"() {
8704
- log4 = createLogger("almadar:ui:effects:client");
8440
+ log3 = createLogger("almadar:ui:effects:client");
8705
8441
  }
8706
8442
  });
8707
8443
 
@@ -8862,12 +8598,12 @@ function useOfflineExecutor(options) {
8862
8598
  clearQueue
8863
8599
  };
8864
8600
  }
8865
- var log5, effectIdCounter, OfflineExecutor;
8601
+ var log4, effectIdCounter, OfflineExecutor;
8866
8602
  var init_offline_executor = __esm({
8867
8603
  "renderer/offline-executor.ts"() {
8868
8604
  "use client";
8869
8605
  init_client_effect_executor();
8870
- log5 = createLogger("almadar:ui:effects:offline");
8606
+ log4 = createLogger("almadar:ui:effects:offline");
8871
8607
  effectIdCounter = 0;
8872
8608
  OfflineExecutor = class {
8873
8609
  constructor(config) {
@@ -8921,7 +8657,7 @@ var init_offline_executor = __esm({
8921
8657
  this.state.syncQueue = JSON.parse(stored);
8922
8658
  }
8923
8659
  } catch (error) {
8924
- log5.warn("Failed to load sync queue", { error: error instanceof Error ? error : String(error) });
8660
+ log4.warn("Failed to load sync queue", { error: error instanceof Error ? error : String(error) });
8925
8661
  }
8926
8662
  }
8927
8663
  /**
@@ -8932,7 +8668,7 @@ var init_offline_executor = __esm({
8932
8668
  try {
8933
8669
  this.storage.setItem("orbital-offline-queue", JSON.stringify(this.state.syncQueue));
8934
8670
  } catch (error) {
8935
- log5.warn("Failed to save sync queue", { error: error instanceof Error ? error : String(error) });
8671
+ log4.warn("Failed to save sync queue", { error: error instanceof Error ? error : String(error) });
8936
8672
  }
8937
8673
  }
8938
8674
  /**
@@ -9002,7 +8738,7 @@ var init_offline_executor = __esm({
9002
8738
  this.queueForSync(type, { args, event, payload });
9003
8739
  break;
9004
8740
  default:
9005
- log5.warn("Unknown effect type", { type });
8741
+ log4.warn("Unknown effect type", { type });
9006
8742
  }
9007
8743
  }
9008
8744
  }
@@ -9889,8 +9625,8 @@ function ActionButtons({
9889
9625
  disabled
9890
9626
  }) {
9891
9627
  const eventBus = useEventBus();
9892
- const [activeButtons, setActiveButtons] = React83.useState(/* @__PURE__ */ new Set());
9893
- const handlePress = React83.useCallback(
9628
+ const [activeButtons, setActiveButtons] = React82.useState(/* @__PURE__ */ new Set());
9629
+ const handlePress = React82.useCallback(
9894
9630
  (id) => {
9895
9631
  setActiveButtons((prev) => new Set(prev).add(id));
9896
9632
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -9898,7 +9634,7 @@ function ActionButtons({
9898
9634
  },
9899
9635
  [actionEvent, eventBus, onAction]
9900
9636
  );
9901
- const handleRelease = React83.useCallback(
9637
+ const handleRelease = React82.useCallback(
9902
9638
  (id) => {
9903
9639
  setActiveButtons((prev) => {
9904
9640
  const next = new Set(prev);
@@ -10810,7 +10546,7 @@ function recordTransition(trace) {
10810
10546
  ...trace,
10811
10547
  id: `t-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
10812
10548
  };
10813
- log6.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
10549
+ log5.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
10814
10550
  getState().transitions.push(entry);
10815
10551
  if (getState().transitions.length > MAX_TRANSITIONS) {
10816
10552
  getState().transitions.shift();
@@ -10879,7 +10615,7 @@ function getTraitSnapshots() {
10879
10615
  try {
10880
10616
  snapshots.push(getter());
10881
10617
  } catch (err) {
10882
- log6.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
10618
+ log5.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
10883
10619
  }
10884
10620
  }
10885
10621
  return snapshots;
@@ -10942,12 +10678,12 @@ function waitForTransition(event, timeoutMs = 1e4) {
10942
10678
  }
10943
10679
  function bindEventBus(eventBus) {
10944
10680
  if (typeof window === "undefined") return;
10945
- log6.info("bindEventBus", { hasOnAny: !!eventBus.onAny });
10681
+ log5.info("bindEventBus", { hasOnAny: !!eventBus.onAny });
10946
10682
  exposeOnWindow();
10947
10683
  if (window.__orbitalVerification) {
10948
10684
  window.__orbitalVerification.sendEvent = (event, payload, traitScope) => {
10949
10685
  const prefixed = event.startsWith("UI:") ? event : traitScope ? `UI:${traitScope}.${event}` : `UI:${event}`;
10950
- log6.debug("sendEvent", { event: prefixed, traitScope, payloadKeys: payload ? Object.keys(payload) : [] });
10686
+ log5.debug("sendEvent", { event: prefixed, traitScope, payloadKeys: payload ? Object.keys(payload) : [] });
10951
10687
  eventBus.emit(prefixed, payload);
10952
10688
  };
10953
10689
  const eventLog = [];
@@ -10996,10 +10732,10 @@ function updateAssetStatus(url, status) {
10996
10732
  window.__orbitalVerification.assetStatus[url] = status;
10997
10733
  }
10998
10734
  }
10999
- var log6, MAX_TRANSITIONS;
10735
+ var log5, MAX_TRANSITIONS;
11000
10736
  var init_verificationRegistry = __esm({
11001
10737
  "lib/verificationRegistry.ts"() {
11002
- log6 = createLogger("almadar:bridge");
10738
+ log5 = createLogger("almadar:bridge");
11003
10739
  MAX_TRANSITIONS = 500;
11004
10740
  exposeOnWindow();
11005
10741
  }
@@ -11126,6 +10862,163 @@ var init_useCamera = __esm({
11126
10862
  "use client";
11127
10863
  }
11128
10864
  });
10865
+ function unitAtlasUrl(unit) {
10866
+ if (unit.spriteSheet) return unit.spriteSheet;
10867
+ const sprite = unit.sprite;
10868
+ if (!sprite) return null;
10869
+ const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
10870
+ if (!match) return null;
10871
+ return `${match[1]}.json`;
10872
+ }
10873
+ function resolveSheetUrl(atlasUrl, relativeSheetPath) {
10874
+ try {
10875
+ return new URL(relativeSheetPath, atlasUrl).toString();
10876
+ } catch {
10877
+ const base = atlasUrl.slice(0, atlasUrl.lastIndexOf("/") + 1);
10878
+ return `${base}${relativeSheetPath.replace(/^\.\//, "")}`;
10879
+ }
10880
+ }
10881
+ function useUnitSpriteAtlas(units) {
10882
+ const atlasCacheRef = useRef(/* @__PURE__ */ new Map());
10883
+ const loadingRef = useRef(/* @__PURE__ */ new Set());
10884
+ const [pendingCount, setPendingCount] = useState(0);
10885
+ const [, forceTick] = useState(0);
10886
+ const animStatesRef = useRef(/* @__PURE__ */ new Map());
10887
+ const lastTickRef = useRef(0);
10888
+ const rafRef = useRef(0);
10889
+ const atlasUrls = useMemo(() => {
10890
+ const set = /* @__PURE__ */ new Set();
10891
+ for (const unit of units) {
10892
+ const url = unitAtlasUrl(unit);
10893
+ if (url) set.add(url);
10894
+ }
10895
+ return [...set];
10896
+ }, [units]);
10897
+ useEffect(() => {
10898
+ const cache = atlasCacheRef.current;
10899
+ const loading = loadingRef.current;
10900
+ const toLoad = atlasUrls.filter((url) => !cache.has(url) && !loading.has(url));
10901
+ if (toLoad.length === 0) return;
10902
+ let cancelled = false;
10903
+ setPendingCount((prev) => prev + toLoad.length);
10904
+ for (const url of toLoad) {
10905
+ loading.add(url);
10906
+ fetch(url).then((res) => res.ok ? res.json() : Promise.reject(new Error(String(res.status)))).then((atlas) => {
10907
+ if (cancelled) return;
10908
+ cache.set(url, atlas);
10909
+ }).catch(() => {
10910
+ }).finally(() => {
10911
+ if (cancelled) return;
10912
+ loading.delete(url);
10913
+ setPendingCount((prev) => Math.max(0, prev - 1));
10914
+ forceTick((n) => n + 1);
10915
+ });
10916
+ }
10917
+ return () => {
10918
+ cancelled = true;
10919
+ };
10920
+ }, [atlasUrls]);
10921
+ const sheetUrls = useMemo(() => {
10922
+ const urls = /* @__PURE__ */ new Set();
10923
+ for (const unit of units) {
10924
+ const atlasUrl = unitAtlasUrl(unit);
10925
+ if (!atlasUrl) continue;
10926
+ const atlas = atlasCacheRef.current.get(atlasUrl);
10927
+ if (!atlas) continue;
10928
+ for (const rel of Object.values(atlas.sheets)) {
10929
+ if (rel) urls.add(resolveSheetUrl(atlasUrl, rel));
10930
+ }
10931
+ }
10932
+ return [...urls];
10933
+ }, [units, pendingCount]);
10934
+ useEffect(() => {
10935
+ const hasAtlasUnits = units.some((u) => unitAtlasUrl(u) !== null);
10936
+ if (!hasAtlasUnits) return;
10937
+ let running = true;
10938
+ const tick = (ts) => {
10939
+ if (!running) return;
10940
+ const last = lastTickRef.current || ts;
10941
+ const delta = ts - last;
10942
+ lastTickRef.current = ts;
10943
+ const states = animStatesRef.current;
10944
+ const currentIds = /* @__PURE__ */ new Set();
10945
+ for (const unit of units) {
10946
+ if (unitAtlasUrl(unit) === null) continue;
10947
+ currentIds.add(unit.id);
10948
+ let state = states.get(unit.id);
10949
+ if (!state) {
10950
+ state = { animation: "idle", direction: "se", elapsed: 0, walkHold: 0, prev: null };
10951
+ states.set(unit.id, state);
10952
+ }
10953
+ const posX = unit.position?.x ?? unit.x ?? 0;
10954
+ const posY = unit.position?.y ?? unit.y ?? 0;
10955
+ if (state.prev) {
10956
+ const dx = posX - state.prev.x;
10957
+ const dy = posY - state.prev.y;
10958
+ if (dx !== 0 || dy !== 0) {
10959
+ state.animation = "walk";
10960
+ state.direction = inferDirection(dx, dy);
10961
+ state.walkHold = WALK_HOLD_MS;
10962
+ } else if (state.animation === "walk") {
10963
+ state.walkHold -= delta;
10964
+ if (state.walkHold <= 0) state.animation = "idle";
10965
+ }
10966
+ }
10967
+ state.prev = { x: posX, y: posY };
10968
+ state.elapsed += delta;
10969
+ }
10970
+ for (const id of states.keys()) {
10971
+ if (!currentIds.has(id)) states.delete(id);
10972
+ }
10973
+ rafRef.current = requestAnimationFrame(tick);
10974
+ };
10975
+ rafRef.current = requestAnimationFrame(tick);
10976
+ return () => {
10977
+ running = false;
10978
+ cancelAnimationFrame(rafRef.current);
10979
+ lastTickRef.current = 0;
10980
+ };
10981
+ }, [units]);
10982
+ const resolveUnitFrame = useCallback((unitId) => {
10983
+ const unit = units.find((u) => u.id === unitId);
10984
+ if (!unit) return null;
10985
+ const atlasUrl = unitAtlasUrl(unit);
10986
+ if (!atlasUrl) return null;
10987
+ const atlas = atlasCacheRef.current.get(atlasUrl);
10988
+ if (!atlas) return null;
10989
+ const state = animStatesRef.current.get(unitId);
10990
+ const animation = state?.animation ?? "idle";
10991
+ const direction = state?.direction ?? "se";
10992
+ const elapsed = state?.elapsed ?? 0;
10993
+ const def = atlas.animations[animation] ?? atlas.animations.idle;
10994
+ if (!def) return null;
10995
+ const { sheetDir, flipX } = resolveSheetDirection(direction);
10996
+ const rel = atlas.sheets[sheetDir] ?? atlas.sheets.se ?? atlas.sheets.sw;
10997
+ if (!rel) return null;
10998
+ const sheetUrl = resolveSheetUrl(atlasUrl, rel);
10999
+ const isIdle = animation === "idle";
11000
+ const frame = isIdle ? 0 : getCurrentFrameFromDef(def, elapsed).frame;
11001
+ const rect = frameRect(frame, def.row, atlas.columns, atlas.frameWidth, atlas.frameHeight);
11002
+ return {
11003
+ sheetUrl,
11004
+ sx: rect.sx,
11005
+ sy: rect.sy,
11006
+ sw: rect.sw,
11007
+ sh: rect.sh,
11008
+ flipX,
11009
+ applyBreathing: isIdle
11010
+ };
11011
+ }, [units]);
11012
+ return { sheetUrls, resolveUnitFrame, pendingCount };
11013
+ }
11014
+ var WALK_HOLD_MS;
11015
+ var init_useUnitSpriteAtlas = __esm({
11016
+ "components/game/molecules/useUnitSpriteAtlas.ts"() {
11017
+ "use client";
11018
+ init_spriteAnimation();
11019
+ WALK_HOLD_MS = 600;
11020
+ }
11021
+ });
11129
11022
 
11130
11023
  // components/game/organisms/utils/isometric.ts
11131
11024
  function isoToScreen(tileX, tileY, scale, baseOffsetX) {
@@ -11240,6 +11133,10 @@ function IsometricCanvas({
11240
11133
  () => unitsProp.map((u) => u.position ? u : { ...u, position: { x: u.x ?? 0, y: u.y ?? 0 } }),
11241
11134
  [unitsProp]
11242
11135
  );
11136
+ const { sheetUrls: atlasSheetUrls, resolveUnitFrame: resolveUnitFrameInternal, pendingCount: atlasPending } = useUnitSpriteAtlas(units);
11137
+ const resolveFrameForUnit = useCallback((unitId) => {
11138
+ return resolveUnitFrame?.(unitId) ?? resolveUnitFrameInternal(unitId);
11139
+ }, [resolveUnitFrame, resolveUnitFrameInternal]);
11243
11140
  const features = useMemo(
11244
11141
  () => featuresProp.map((f3) => {
11245
11142
  if (f3.type) return f3;
@@ -11323,9 +11220,10 @@ function IsometricCanvas({
11323
11220
  }
11324
11221
  }
11325
11222
  if (effectSpriteUrls) urls.push(...effectSpriteUrls);
11223
+ if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
11326
11224
  if (backgroundImage) urls.push(backgroundImage);
11327
11225
  return [...new Set(urls.filter(Boolean))];
11328
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, backgroundImage, assetManifest, resolveManifestUrl]);
11226
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl]);
11329
11227
  const { getImage, pendingCount } = useImageCache(spriteUrls);
11330
11228
  useEffect(() => {
11331
11229
  if (typeof window === "undefined") return;
@@ -11612,7 +11510,7 @@ function IsometricCanvas({
11612
11510
  ctx.lineWidth = 3;
11613
11511
  ctx.stroke();
11614
11512
  }
11615
- const frame = resolveUnitFrame?.(unit.id) ?? null;
11513
+ const frame = resolveFrameForUnit(unit.id);
11616
11514
  const frameImg = frame ? getImage(frame.sheetUrl) : null;
11617
11515
  if (frame && frameImg) {
11618
11516
  const frameAr = frame.sw / frame.sh;
@@ -11722,7 +11620,7 @@ function IsometricCanvas({
11722
11620
  resolveTerrainSpriteUrl,
11723
11621
  resolveFeatureSpriteUrl,
11724
11622
  resolveUnitSpriteUrl,
11725
- resolveUnitFrame,
11623
+ resolveFrameForUnit,
11726
11624
  getImage,
11727
11625
  gridWidth,
11728
11626
  gridHeight,
@@ -11754,7 +11652,7 @@ function IsometricCanvas({
11754
11652
  };
11755
11653
  }, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
11756
11654
  useEffect(() => {
11757
- const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0;
11655
+ const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
11758
11656
  draw(animTimeRef.current);
11759
11657
  if (!hasAnimations) return;
11760
11658
  let running = true;
@@ -11770,7 +11668,7 @@ function IsometricCanvas({
11770
11668
  running = false;
11771
11669
  cancelAnimationFrame(rafIdRef.current);
11772
11670
  };
11773
- }, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, lerpToTarget, targetCameraRef]);
11671
+ }, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, atlasPending, lerpToTarget, targetCameraRef]);
11774
11672
  const handleMouseMoveWithCamera = useCallback((e) => {
11775
11673
  if (enableCamera) {
11776
11674
  const wasPanning = handleMouseMove(e, () => draw(animTimeRef.current));
@@ -11915,6 +11813,7 @@ var init_IsometricCanvas = __esm({
11915
11813
  init_ErrorState();
11916
11814
  init_useImageCache();
11917
11815
  init_useCamera();
11816
+ init_useUnitSpriteAtlas();
11918
11817
  init_verificationRegistry();
11919
11818
  init_isometric();
11920
11819
  IsometricCanvas.displayName = "IsometricCanvas";
@@ -13130,7 +13029,7 @@ var init_avl_elk_layout = __esm({
13130
13029
  elk = new ELK();
13131
13030
  }
13132
13031
  });
13133
- var log7, SWIM_GUTTER, CENTER_W, BehaviorView;
13032
+ var log6, SWIM_GUTTER, CENTER_W, BehaviorView;
13134
13033
  var init_BehaviorView = __esm({
13135
13034
  "components/avl/molecules/BehaviorView.tsx"() {
13136
13035
  "use client";
@@ -13139,7 +13038,7 @@ var init_BehaviorView = __esm({
13139
13038
  init_AvlSwimLane();
13140
13039
  init_types();
13141
13040
  init_avl_elk_layout();
13142
- log7 = createLogger("almadar:ui:avl:behavior-view");
13041
+ log6 = createLogger("almadar:ui:avl:behavior-view");
13143
13042
  SWIM_GUTTER = 120;
13144
13043
  CENTER_W = 360;
13145
13044
  BehaviorView = ({ data }) => {
@@ -13150,7 +13049,7 @@ var init_BehaviorView = __esm({
13150
13049
  const dataKey = useMemo(() => JSON.stringify(traitData), [traitData]);
13151
13050
  useEffect(() => {
13152
13051
  if (!traitData) return;
13153
- computeTraitLayout(traitData).then(setLayout).catch((err) => log7.error("compute-trait-layout-failed", { error: err instanceof Error ? err : String(err) }));
13052
+ computeTraitLayout(traitData).then(setLayout).catch((err) => log6.error("compute-trait-layout-failed", { error: err instanceof Error ? err : String(err) }));
13154
13053
  }, [dataKey]);
13155
13054
  if (!traitData) {
13156
13055
  return /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-[var(--color-border)] bg-[var(--color-card)] p-4 text-center text-[var(--color-muted-foreground)] text-sm", children: t("avl.noTraitData") });
@@ -13561,7 +13460,7 @@ function generateDiff(oldVal, newVal) {
13561
13460
  }
13562
13461
  return diff;
13563
13462
  }
13564
- var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log8, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
13463
+ var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log7, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
13565
13464
  var init_CodeBlock = __esm({
13566
13465
  "components/core/molecules/markdown/CodeBlock.tsx"() {
13567
13466
  init_cn();
@@ -13644,7 +13543,7 @@ var init_CodeBlock = __esm({
13644
13543
  "lolo-op-async": { color: ORB_COLORS.dark.async }
13645
13544
  };
13646
13545
  loloStyle = { ...dark, ...loloStyleOverrides };
13647
- log8 = createLogger("almadar:ui:markdown-code");
13546
+ log7 = createLogger("almadar:ui:markdown-code");
13648
13547
  CODE_LANGUAGES = [
13649
13548
  "text",
13650
13549
  "json",
@@ -13683,7 +13582,7 @@ var init_CodeBlock = __esm({
13683
13582
  };
13684
13583
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
13685
13584
  HIDDEN_LINE_NUMBERS = { display: "none" };
13686
- CodeBlock = React83__default.memo(
13585
+ CodeBlock = React82__default.memo(
13687
13586
  ({
13688
13587
  code: rawCode,
13689
13588
  language = "text",
@@ -13908,7 +13807,7 @@ var init_CodeBlock = __esm({
13908
13807
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: true });
13909
13808
  setTimeout(() => setCopied(false), 2e3);
13910
13809
  } catch (err) {
13911
- log8.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
13810
+ log7.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
13912
13811
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: false });
13913
13812
  }
13914
13813
  };
@@ -14270,7 +14169,7 @@ var init_MarkdownContent = __esm({
14270
14169
  init_Box();
14271
14170
  init_CodeBlock();
14272
14171
  init_cn();
14273
- MarkdownContent = React83__default.memo(
14172
+ MarkdownContent = React82__default.memo(
14274
14173
  ({ content, direction = "ltr", className }) => {
14275
14174
  const { t: _t } = useTranslate();
14276
14175
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -15587,7 +15486,7 @@ var init_StateMachineView = __esm({
15587
15486
  style: { top: title ? 30 : 0 },
15588
15487
  children: [
15589
15488
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
15590
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React83__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
15489
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React82__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
15591
15490
  StateNode,
15592
15491
  {
15593
15492
  state,
@@ -17789,14 +17688,14 @@ function useSafeEventBus2() {
17789
17688
  } };
17790
17689
  }
17791
17690
  }
17792
- var log9, lookStyles4, ButtonGroup;
17691
+ var log8, lookStyles4, ButtonGroup;
17793
17692
  var init_ButtonGroup = __esm({
17794
17693
  "components/core/molecules/ButtonGroup.tsx"() {
17795
17694
  "use client";
17796
17695
  init_cn();
17797
17696
  init_atoms2();
17798
17697
  init_useEventBus();
17799
- log9 = createLogger("almadar:ui:button-group");
17698
+ log8 = createLogger("almadar:ui:button-group");
17800
17699
  lookStyles4 = {
17801
17700
  "right-aligned-buttons": "",
17802
17701
  "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
@@ -17877,7 +17776,7 @@ var init_ButtonGroup = __esm({
17877
17776
  {
17878
17777
  variant: "ghost",
17879
17778
  onClick: () => {
17880
- log9.debug("Filter clicked", { field: filter.field });
17779
+ log8.debug("Filter clicked", { field: filter.field });
17881
17780
  },
17882
17781
  children: filter.label
17883
17782
  },
@@ -22128,7 +22027,7 @@ function CraftingRecipe({
22128
22027
  className
22129
22028
  }) {
22130
22029
  const eventBus = useEventBus();
22131
- const handleCraft = React83.useCallback(() => {
22030
+ const handleCraft = React82.useCallback(() => {
22132
22031
  onCraft?.();
22133
22032
  if (craftEvent) {
22134
22033
  eventBus.emit(craftEvent, { output: output.label });
@@ -22145,7 +22044,7 @@ function CraftingRecipe({
22145
22044
  children: [
22146
22045
  /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap items-center", children: inputs.map((ingredient, index) => {
22147
22046
  const hasSufficient = ingredient.available >= ingredient.required;
22148
- return /* @__PURE__ */ jsxs(React83.Fragment, { children: [
22047
+ return /* @__PURE__ */ jsxs(React82.Fragment, { children: [
22149
22048
  /* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
22150
22049
  ItemSlot,
22151
22050
  {
@@ -22217,8 +22116,8 @@ function DPad({
22217
22116
  }) {
22218
22117
  const eventBus = useEventBus();
22219
22118
  const sizes = sizeMap15[size];
22220
- const [activeDirections, setActiveDirections] = React83.useState(/* @__PURE__ */ new Set());
22221
- const handlePress = React83.useCallback(
22119
+ const [activeDirections, setActiveDirections] = React82.useState(/* @__PURE__ */ new Set());
22120
+ const handlePress = React82.useCallback(
22222
22121
  (direction) => {
22223
22122
  setActiveDirections((prev) => new Set(prev).add(direction));
22224
22123
  if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
@@ -22226,7 +22125,7 @@ function DPad({
22226
22125
  },
22227
22126
  [directionEvent, eventBus, onDirection]
22228
22127
  );
22229
- const handleRelease = React83.useCallback(
22128
+ const handleRelease = React82.useCallback(
22230
22129
  (direction) => {
22231
22130
  setActiveDirections((prev) => {
22232
22131
  const next = new Set(prev);
@@ -23033,8 +22932,8 @@ var init_Menu = __esm({
23033
22932
  "bottom-end": "bottom-start"
23034
22933
  };
23035
22934
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
23036
- const triggerChild = React83__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
23037
- const triggerElement = React83__default.cloneElement(
22935
+ const triggerChild = React82__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
22936
+ const triggerElement = React82__default.cloneElement(
23038
22937
  triggerChild,
23039
22938
  {
23040
22939
  ref: triggerRef,
@@ -23168,14 +23067,14 @@ function useDataDnd(args) {
23168
23067
  const isZone = Boolean(dragGroup || accepts || sortable);
23169
23068
  const enabled = isZone || Boolean(dndRoot);
23170
23069
  const eventBus = useEventBus();
23171
- const parentRoot = React83__default.useContext(RootCtx);
23070
+ const parentRoot = React82__default.useContext(RootCtx);
23172
23071
  const isRoot = enabled && parentRoot === null;
23173
- const zoneId = React83__default.useId();
23072
+ const zoneId = React82__default.useId();
23174
23073
  const ownGroup = dragGroup ?? accepts ?? zoneId;
23175
- const [optimisticOrders, setOptimisticOrders] = React83__default.useState(() => /* @__PURE__ */ new Map());
23176
- const optimisticOrdersRef = React83__default.useRef(optimisticOrders);
23074
+ const [optimisticOrders, setOptimisticOrders] = React82__default.useState(() => /* @__PURE__ */ new Map());
23075
+ const optimisticOrdersRef = React82__default.useRef(optimisticOrders);
23177
23076
  optimisticOrdersRef.current = optimisticOrders;
23178
- const clearOptimisticOrder = React83__default.useCallback((group) => {
23077
+ const clearOptimisticOrder = React82__default.useCallback((group) => {
23179
23078
  setOptimisticOrders((prev) => {
23180
23079
  if (!prev.has(group)) return prev;
23181
23080
  const next = new Map(prev);
@@ -23200,7 +23099,7 @@ function useDataDnd(args) {
23200
23099
  const raw = it[dndItemIdField];
23201
23100
  return String(raw ?? `__idx_${idx}`);
23202
23101
  }).join("|");
23203
- const itemIds = React83__default.useMemo(
23102
+ const itemIds = React82__default.useMemo(
23204
23103
  () => orderedItems.map((it, idx) => {
23205
23104
  const raw = it[dndItemIdField];
23206
23105
  return raw ?? `__idx_${idx}`;
@@ -23208,7 +23107,7 @@ function useDataDnd(args) {
23208
23107
  [itemIdsSignature]
23209
23108
  );
23210
23109
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
23211
- React83__default.useEffect(() => {
23110
+ React82__default.useEffect(() => {
23212
23111
  const root = isRoot ? null : parentRoot;
23213
23112
  if (root) {
23214
23113
  root.clearOptimisticOrder(ownGroup);
@@ -23216,20 +23115,20 @@ function useDataDnd(args) {
23216
23115
  clearOptimisticOrder(ownGroup);
23217
23116
  }
23218
23117
  }, [itemsContentSig, ownGroup]);
23219
- const zonesRef = React83__default.useRef(/* @__PURE__ */ new Map());
23220
- const registerZone = React83__default.useCallback((zoneId2, meta2) => {
23118
+ const zonesRef = React82__default.useRef(/* @__PURE__ */ new Map());
23119
+ const registerZone = React82__default.useCallback((zoneId2, meta2) => {
23221
23120
  zonesRef.current.set(zoneId2, meta2);
23222
23121
  }, []);
23223
- const unregisterZone = React83__default.useCallback((zoneId2) => {
23122
+ const unregisterZone = React82__default.useCallback((zoneId2) => {
23224
23123
  zonesRef.current.delete(zoneId2);
23225
23124
  }, []);
23226
- const [activeDrag, setActiveDrag] = React83__default.useState(null);
23227
- const [overZoneGroup, setOverZoneGroup] = React83__default.useState(null);
23228
- const meta = React83__default.useMemo(
23125
+ const [activeDrag, setActiveDrag] = React82__default.useState(null);
23126
+ const [overZoneGroup, setOverZoneGroup] = React82__default.useState(null);
23127
+ const meta = React82__default.useMemo(
23229
23128
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
23230
23129
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
23231
23130
  );
23232
- React83__default.useEffect(() => {
23131
+ React82__default.useEffect(() => {
23233
23132
  const target = isRoot ? null : parentRoot;
23234
23133
  if (!target) {
23235
23134
  zonesRef.current.set(zoneId, meta);
@@ -23248,7 +23147,7 @@ function useDataDnd(args) {
23248
23147
  }, [parentRoot, isRoot, zoneId, meta]);
23249
23148
  const sensors = useAlmadarDndSensors(true);
23250
23149
  const collisionDetection = almadarDndCollisionDetection;
23251
- const findZoneByItem = React83__default.useCallback(
23150
+ const findZoneByItem = React82__default.useCallback(
23252
23151
  (id) => {
23253
23152
  for (const z of zonesRef.current.values()) {
23254
23153
  if (z.itemIds.includes(id)) return z;
@@ -23257,7 +23156,7 @@ function useDataDnd(args) {
23257
23156
  },
23258
23157
  []
23259
23158
  );
23260
- React83__default.useCallback(
23159
+ React82__default.useCallback(
23261
23160
  (group) => {
23262
23161
  for (const z of zonesRef.current.values()) {
23263
23162
  if (z.group === group) return z;
@@ -23266,7 +23165,7 @@ function useDataDnd(args) {
23266
23165
  },
23267
23166
  []
23268
23167
  );
23269
- const handleDragEnd = React83__default.useCallback(
23168
+ const handleDragEnd = React82__default.useCallback(
23270
23169
  (event) => {
23271
23170
  const { active, over } = event;
23272
23171
  const activeIdStr = String(active.id);
@@ -23357,8 +23256,8 @@ function useDataDnd(args) {
23357
23256
  },
23358
23257
  [eventBus]
23359
23258
  );
23360
- const sortableData = React83__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
23361
- const SortableItem = React83__default.useCallback(
23259
+ const sortableData = React82__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
23260
+ const SortableItem = React82__default.useCallback(
23362
23261
  ({ id, children }) => {
23363
23262
  const {
23364
23263
  attributes,
@@ -23398,7 +23297,7 @@ function useDataDnd(args) {
23398
23297
  id: droppableId,
23399
23298
  data: sortableData
23400
23299
  });
23401
- const ctx = React83__default.useContext(RootCtx);
23300
+ const ctx = React82__default.useContext(RootCtx);
23402
23301
  const activeDrag2 = ctx?.activeDrag ?? null;
23403
23302
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
23404
23303
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -23413,7 +23312,7 @@ function useDataDnd(args) {
23413
23312
  showForeignPlaceholder,
23414
23313
  ctxAvailable: ctx != null
23415
23314
  });
23416
- React83__default.useEffect(() => {
23315
+ React82__default.useEffect(() => {
23417
23316
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
23418
23317
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
23419
23318
  return /* @__PURE__ */ jsx(
@@ -23427,11 +23326,11 @@ function useDataDnd(args) {
23427
23326
  }
23428
23327
  );
23429
23328
  };
23430
- const rootContextValue = React83__default.useMemo(
23329
+ const rootContextValue = React82__default.useMemo(
23431
23330
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
23432
23331
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
23433
23332
  );
23434
- const handleDragStart = React83__default.useCallback((event) => {
23333
+ const handleDragStart = React82__default.useCallback((event) => {
23435
23334
  const sourceZone = findZoneByItem(event.active.id);
23436
23335
  const rect = event.active.rect.current.initial;
23437
23336
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -23450,7 +23349,7 @@ function useDataDnd(args) {
23450
23349
  isRoot
23451
23350
  });
23452
23351
  }, [findZoneByItem, isRoot, zoneId]);
23453
- const handleDragOver = React83__default.useCallback((event) => {
23352
+ const handleDragOver = React82__default.useCallback((event) => {
23454
23353
  const { active, over } = event;
23455
23354
  const overData = over?.data?.current;
23456
23355
  const overGroup = overData?.dndGroup ?? null;
@@ -23520,7 +23419,7 @@ function useDataDnd(args) {
23520
23419
  return next;
23521
23420
  });
23522
23421
  }, []);
23523
- const handleDragCancel = React83__default.useCallback((event) => {
23422
+ const handleDragCancel = React82__default.useCallback((event) => {
23524
23423
  setActiveDrag(null);
23525
23424
  setOverZoneGroup(null);
23526
23425
  dndLog.warn("dragCancel", {
@@ -23528,12 +23427,12 @@ function useDataDnd(args) {
23528
23427
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
23529
23428
  });
23530
23429
  }, []);
23531
- const handleDragEndWithCleanup = React83__default.useCallback((event) => {
23430
+ const handleDragEndWithCleanup = React82__default.useCallback((event) => {
23532
23431
  handleDragEnd(event);
23533
23432
  setActiveDrag(null);
23534
23433
  setOverZoneGroup(null);
23535
23434
  }, [handleDragEnd]);
23536
- const wrapContainer = React83__default.useCallback(
23435
+ const wrapContainer = React82__default.useCallback(
23537
23436
  (children) => {
23538
23437
  if (!enabled) return children;
23539
23438
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -23587,7 +23486,7 @@ var init_useDataDnd = __esm({
23587
23486
  init_useAlmadarDndCollision();
23588
23487
  init_Box();
23589
23488
  dndLog = createLogger("almadar:ui:dnd");
23590
- RootCtx = React83__default.createContext(null);
23489
+ RootCtx = React82__default.createContext(null);
23591
23490
  }
23592
23491
  });
23593
23492
  function renderIconInput(icon, props) {
@@ -24113,7 +24012,7 @@ function DataList({
24113
24012
  }) {
24114
24013
  const eventBus = useEventBus();
24115
24014
  const { t } = useTranslate();
24116
- const [visibleCount, setVisibleCount] = React83__default.useState(pageSize || Infinity);
24015
+ const [visibleCount, setVisibleCount] = React82__default.useState(pageSize || Infinity);
24117
24016
  const fieldDefs = fields ?? columns ?? [];
24118
24017
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
24119
24018
  const dnd = useDataDnd({
@@ -24132,7 +24031,7 @@ function DataList({
24132
24031
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
24133
24032
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
24134
24033
  const hasRenderProp = typeof children === "function";
24135
- React83__default.useEffect(() => {
24034
+ React82__default.useEffect(() => {
24136
24035
  const renderItemTypeOf = typeof schemaRenderItem;
24137
24036
  const childrenTypeOf = typeof children;
24138
24037
  if (data.length > 0 && !hasRenderProp) {
@@ -24237,7 +24136,7 @@ function DataList({
24237
24136
  const items2 = data.map((item) => item);
24238
24137
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
24239
24138
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
24240
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
24139
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
24241
24140
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
24242
24141
  group.items.map((itemData, index) => {
24243
24142
  const id = itemData.id || `${gi}-${index}`;
@@ -24378,7 +24277,7 @@ function DataList({
24378
24277
  className
24379
24278
  ),
24380
24279
  children: [
24381
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
24280
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
24382
24281
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
24383
24282
  group.items.map(
24384
24283
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -25294,7 +25193,7 @@ var init_Grid = __esm({
25294
25193
  as: Component2 = "div"
25295
25194
  }) => {
25296
25195
  const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
25297
- return React83__default.createElement(
25196
+ return React82__default.createElement(
25298
25197
  Component2,
25299
25198
  {
25300
25199
  className: cn(
@@ -25482,8 +25381,8 @@ var init_Popover = __esm({
25482
25381
  onMouseEnter: handleOpen,
25483
25382
  onMouseLeave: handleClose
25484
25383
  };
25485
- const childElement = React83__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25486
- const triggerElement = React83__default.cloneElement(
25384
+ const childElement = React82__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25385
+ const triggerElement = React82__default.cloneElement(
25487
25386
  childElement,
25488
25387
  {
25489
25388
  ref: triggerRef,
@@ -25539,9 +25438,9 @@ function debug(...args) {
25539
25438
  const [first, ...rest] = args;
25540
25439
  const message = typeof first === "string" ? first : "<debug>";
25541
25440
  if (rest.length === 0 && typeof first === "string") {
25542
- log10.debug(message);
25441
+ log9.debug(message);
25543
25442
  } else {
25544
- log10.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
25443
+ log9.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
25545
25444
  }
25546
25445
  }
25547
25446
  function debugGroup(label) {
@@ -25569,11 +25468,11 @@ function toLogMetaValue(v) {
25569
25468
  }
25570
25469
  return String(v);
25571
25470
  }
25572
- var NAMESPACE, log10;
25471
+ var NAMESPACE, log9;
25573
25472
  var init_debug = __esm({
25574
25473
  "lib/debug.ts"() {
25575
25474
  NAMESPACE = "almadar:ui:debug";
25576
- log10 = createLogger(NAMESPACE);
25475
+ log9 = createLogger(NAMESPACE);
25577
25476
  createLogger("almadar:ui:debug:input");
25578
25477
  createLogger("almadar:ui:debug:collision");
25579
25478
  createLogger("almadar:ui:debug:physics");
@@ -26073,8 +25972,8 @@ var init_Tooltip = __esm({
26073
25972
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
26074
25973
  };
26075
25974
  }, []);
26076
- const triggerElement = React83__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
26077
- const trigger = React83__default.cloneElement(triggerElement, {
25975
+ const triggerElement = React82__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25976
+ const trigger = React82__default.cloneElement(triggerElement, {
26078
25977
  ref: triggerRef,
26079
25978
  onMouseEnter: handleMouseEnter,
26080
25979
  onMouseLeave: handleMouseLeave,
@@ -26160,7 +26059,7 @@ var init_WizardProgress = __esm({
26160
26059
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
26161
26060
  const isActive = index === currentStep;
26162
26061
  const isCompleted = index < currentStep;
26163
- return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
26062
+ return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
26164
26063
  /* @__PURE__ */ jsx(
26165
26064
  "button",
26166
26065
  {
@@ -27224,7 +27123,7 @@ function InventoryGrid({
27224
27123
  const eventBus = useEventBus();
27225
27124
  const slotCount = totalSlots ?? items.length;
27226
27125
  const emptySlotCount = Math.max(0, slotCount - items.length);
27227
- const handleSelect = React83.useCallback(
27126
+ const handleSelect = React82.useCallback(
27228
27127
  (id) => {
27229
27128
  onSelect?.(id);
27230
27129
  if (selectEvent) {
@@ -27458,31 +27357,31 @@ function GameCanvas2D({
27458
27357
  assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
27459
27358
  className
27460
27359
  }) {
27461
- const canvasRef = React83.useRef(null);
27462
- const rafRef = React83.useRef(0);
27463
- const frameRef = React83.useRef(0);
27464
- const lastTimeRef = React83.useRef(0);
27465
- const imageCache = React83.useRef(/* @__PURE__ */ new Map());
27360
+ const canvasRef = React82.useRef(null);
27361
+ const rafRef = React82.useRef(0);
27362
+ const frameRef = React82.useRef(0);
27363
+ const lastTimeRef = React82.useRef(0);
27364
+ const imageCache = React82.useRef(/* @__PURE__ */ new Map());
27466
27365
  const emit = useEmitEvent();
27467
- const onDrawRef = React83.useRef(onDraw);
27366
+ const onDrawRef = React82.useRef(onDraw);
27468
27367
  onDrawRef.current = onDraw;
27469
- const onTickRef = React83.useRef(onTick);
27368
+ const onTickRef = React82.useRef(onTick);
27470
27369
  onTickRef.current = onTick;
27471
- const tickEventRef = React83.useRef(tickEvent);
27370
+ const tickEventRef = React82.useRef(tickEvent);
27472
27371
  tickEventRef.current = tickEvent;
27473
- const drawEventRef = React83.useRef(drawEvent);
27372
+ const drawEventRef = React82.useRef(drawEvent);
27474
27373
  drawEventRef.current = drawEvent;
27475
- const emitRef = React83.useRef(emit);
27374
+ const emitRef = React82.useRef(emit);
27476
27375
  emitRef.current = emit;
27477
- const assetBaseUrlRef = React83.useRef(assetBaseUrl);
27376
+ const assetBaseUrlRef = React82.useRef(assetBaseUrl);
27478
27377
  assetBaseUrlRef.current = assetBaseUrl;
27479
- const backgroundImageRef = React83.useRef(backgroundImage);
27378
+ const backgroundImageRef = React82.useRef(backgroundImage);
27480
27379
  backgroundImageRef.current = backgroundImage;
27481
- const widthRef = React83.useRef(width);
27380
+ const widthRef = React82.useRef(width);
27482
27381
  widthRef.current = width;
27483
- const heightRef = React83.useRef(height);
27382
+ const heightRef = React82.useRef(height);
27484
27383
  heightRef.current = height;
27485
- const loadImage = React83.useCallback((url) => {
27384
+ const loadImage = React82.useCallback((url) => {
27486
27385
  const fullUrl = url.startsWith("http") ? url : `${assetBaseUrlRef.current}${url}`;
27487
27386
  const cached = imageCache.current.get(fullUrl);
27488
27387
  if (cached?.complete && cached.naturalWidth > 0) return cached;
@@ -27494,7 +27393,7 @@ function GameCanvas2D({
27494
27393
  }
27495
27394
  return null;
27496
27395
  }, []);
27497
- React83.useEffect(() => {
27396
+ React82.useEffect(() => {
27498
27397
  const canvas = canvasRef.current;
27499
27398
  if (!canvas) return;
27500
27399
  const ctx = canvas.getContext("2d");
@@ -27806,7 +27705,7 @@ function TurnPanel({
27806
27705
  className
27807
27706
  }) {
27808
27707
  const eventBus = useEventBus();
27809
- const handleAction = React83.useCallback(
27708
+ const handleAction = React82.useCallback(
27810
27709
  (event) => {
27811
27710
  if (event) {
27812
27711
  eventBus.emit(event, { turn: currentTurn, phase, activeTeam });
@@ -27975,7 +27874,7 @@ function UnitCommandBar({
27975
27874
  className
27976
27875
  }) {
27977
27876
  const eventBus = useEventBus();
27978
- const handleCommand = React83.useCallback(
27877
+ const handleCommand = React82.useCallback(
27979
27878
  (event) => {
27980
27879
  if (event) {
27981
27880
  eventBus.emit(event, { unitId: selectedUnitId });
@@ -28489,7 +28388,7 @@ function GameMenu({
28489
28388
  } catch {
28490
28389
  }
28491
28390
  const eventBus = eventBusProp || eventBusFromHook;
28492
- const handleOptionClick = React83.useCallback(
28391
+ const handleOptionClick = React82.useCallback(
28493
28392
  (option) => {
28494
28393
  if (option.event && eventBus) {
28495
28394
  eventBus.emit(`UI:${option.event}`, { option });
@@ -28608,7 +28507,7 @@ function GameOverScreen({
28608
28507
  } catch {
28609
28508
  }
28610
28509
  const eventBus = eventBusProp || eventBusFromHook;
28611
- const handleActionClick = React83.useCallback(
28510
+ const handleActionClick = React82.useCallback(
28612
28511
  (action) => {
28613
28512
  if (action.event && eventBus) {
28614
28513
  eventBus.emit(`UI:${action.event}`, { action });
@@ -29497,12 +29396,12 @@ var init_MapView = __esm({
29497
29396
  shadowSize: [41, 41]
29498
29397
  });
29499
29398
  L.Marker.prototype.options.icon = defaultIcon;
29500
- const { useEffect: useEffect79, useRef: useRef74, useCallback: useCallback118, useState: useState109 } = React83__default;
29399
+ const { useEffect: useEffect79, useRef: useRef75, useCallback: useCallback118, useState: useState109 } = React82__default;
29501
29400
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
29502
29401
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
29503
29402
  function MapUpdater({ centerLat, centerLng, zoom }) {
29504
29403
  const map = useMap();
29505
- const prevRef = useRef74({ centerLat, centerLng, zoom });
29404
+ const prevRef = useRef75({ centerLat, centerLng, zoom });
29506
29405
  useEffect79(() => {
29507
29406
  const prev = prevRef.current;
29508
29407
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
@@ -30403,8 +30302,8 @@ function TableView({
30403
30302
  }) {
30404
30303
  const eventBus = useEventBus();
30405
30304
  const { t } = useTranslate();
30406
- const [visibleCount, setVisibleCount] = React83__default.useState(pageSize > 0 ? pageSize : Infinity);
30407
- const [localSelected, setLocalSelected] = React83__default.useState(/* @__PURE__ */ new Set());
30305
+ const [visibleCount, setVisibleCount] = React82__default.useState(pageSize > 0 ? pageSize : Infinity);
30306
+ const [localSelected, setLocalSelected] = React82__default.useState(/* @__PURE__ */ new Set());
30408
30307
  const colDefs = columns ?? fields ?? [];
30409
30308
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
30410
30309
  const dnd = useDataDnd({
@@ -30599,12 +30498,12 @@ function TableView({
30599
30498
  ]
30600
30499
  }
30601
30500
  );
30602
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React83__default.Fragment, { children: rowInner }, id);
30501
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React82__default.Fragment, { children: rowInner }, id);
30603
30502
  };
30604
30503
  const items = data.map((row) => row);
30605
30504
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
30606
30505
  let runningIndex = 0;
30607
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
30506
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
30608
30507
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
30609
30508
  group.items.map((row) => renderRow(row, runningIndex++))
30610
30509
  ] }, gi)) });
@@ -31961,7 +31860,7 @@ var init_StepFlow = __esm({
31961
31860
  className
31962
31861
  }) => {
31963
31862
  if (orientation === "vertical") {
31964
- return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React83__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
31863
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React82__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
31965
31864
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
31966
31865
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
31967
31866
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -31972,7 +31871,7 @@ var init_StepFlow = __esm({
31972
31871
  ] })
31973
31872
  ] }) }, index)) });
31974
31873
  }
31975
- return /* @__PURE__ */ jsx(Box, { className: cn("w-full flex flex-col md:flex-row items-start gap-0", className), children: steps.map((step, index) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
31874
+ return /* @__PURE__ */ jsx(Box, { className: cn("w-full flex flex-col md:flex-row items-start gap-0", className), children: steps.map((step, index) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
31976
31875
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
31977
31876
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
31978
31877
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -32957,7 +32856,7 @@ var init_LikertScale = __esm({
32957
32856
  md: "text-base",
32958
32857
  lg: "text-lg"
32959
32858
  };
32960
- LikertScale = React83__default.forwardRef(
32859
+ LikertScale = React82__default.forwardRef(
32961
32860
  ({
32962
32861
  question,
32963
32862
  options = DEFAULT_LIKERT_OPTIONS,
@@ -32969,7 +32868,7 @@ var init_LikertScale = __esm({
32969
32868
  variant = "radios",
32970
32869
  className
32971
32870
  }, ref) => {
32972
- const groupId = React83__default.useId();
32871
+ const groupId = React82__default.useId();
32973
32872
  const eventBus = useEventBus();
32974
32873
  const handleSelect = useCallback(
32975
32874
  (next) => {
@@ -35251,7 +35150,7 @@ var init_DocBreadcrumb = __esm({
35251
35150
  "aria-label": t("aria.breadcrumb"),
35252
35151
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
35253
35152
  const isLast = idx === items.length - 1;
35254
- return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
35153
+ return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
35255
35154
  idx > 0 && /* @__PURE__ */ jsx(
35256
35155
  Icon,
35257
35156
  {
@@ -36120,7 +36019,7 @@ var init_MiniStateMachine = __esm({
36120
36019
  const x = 2 + i * (NODE_W + GAP + ARROW_W + GAP);
36121
36020
  const tc = transitionCounts[s.name] ?? 0;
36122
36021
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
36123
- return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
36022
+ return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
36124
36023
  /* @__PURE__ */ jsx(
36125
36024
  AvlState,
36126
36025
  {
@@ -36324,7 +36223,7 @@ var init_PageHeader = __esm({
36324
36223
  info: "bg-info/10 text-info"
36325
36224
  };
36326
36225
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
36327
- breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
36226
+ breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
36328
36227
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
36329
36228
  crumb.href ? /* @__PURE__ */ jsx(
36330
36229
  "a",
@@ -37053,7 +36952,7 @@ var init_WizardContainer = __esm({
37053
36952
  const isCompleted = index < currentStep;
37054
36953
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
37055
36954
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
37056
- return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
36955
+ return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
37057
36956
  /* @__PURE__ */ jsx(
37058
36957
  Button,
37059
36958
  {
@@ -39388,7 +39287,7 @@ var init_DetailPanel = __esm({
39388
39287
  }
39389
39288
  });
39390
39289
  function extractTitle(children) {
39391
- if (!React83__default.isValidElement(children)) return void 0;
39290
+ if (!React82__default.isValidElement(children)) return void 0;
39392
39291
  const props = children.props;
39393
39292
  if (typeof props.title === "string") {
39394
39293
  return props.title;
@@ -39443,7 +39342,7 @@ function LinearView({
39443
39342
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
39444
39343
  const isDone = i < currentIdx;
39445
39344
  const isCurrent = i === currentIdx;
39446
- return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
39345
+ return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
39447
39346
  i > 0 && /* @__PURE__ */ jsx(
39448
39347
  Typography,
39449
39348
  {
@@ -40393,12 +40292,12 @@ var init_Form = __esm({
40393
40292
  const isSchemaEntity = isOrbitalEntitySchema(entity);
40394
40293
  const resolvedEntity = isSchemaEntity ? entity : void 0;
40395
40294
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
40396
- const normalizedInitialData = React83__default.useMemo(() => {
40295
+ const normalizedInitialData = React82__default.useMemo(() => {
40397
40296
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
40398
40297
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
40399
40298
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
40400
40299
  }, [entity, initialData]);
40401
- const entityDerivedFields = React83__default.useMemo(() => {
40300
+ const entityDerivedFields = React82__default.useMemo(() => {
40402
40301
  if (fields && fields.length > 0) return void 0;
40403
40302
  if (!resolvedEntity) return void 0;
40404
40303
  return resolvedEntity.fields.map(
@@ -40418,16 +40317,16 @@ var init_Form = __esm({
40418
40317
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
40419
40318
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
40420
40319
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
40421
- const [formData, setFormData] = React83__default.useState(
40320
+ const [formData, setFormData] = React82__default.useState(
40422
40321
  normalizedInitialData
40423
40322
  );
40424
- const [collapsedSections, setCollapsedSections] = React83__default.useState(
40323
+ const [collapsedSections, setCollapsedSections] = React82__default.useState(
40425
40324
  /* @__PURE__ */ new Set()
40426
40325
  );
40427
- const [submitError, setSubmitError] = React83__default.useState(null);
40428
- const formRef = React83__default.useRef(null);
40326
+ const [submitError, setSubmitError] = React82__default.useState(null);
40327
+ const formRef = React82__default.useRef(null);
40429
40328
  const formMode = props.mode;
40430
- const mountedRef = React83__default.useRef(false);
40329
+ const mountedRef = React82__default.useRef(false);
40431
40330
  if (!mountedRef.current) {
40432
40331
  mountedRef.current = true;
40433
40332
  debug("forms", "mount", {
@@ -40440,7 +40339,7 @@ var init_Form = __esm({
40440
40339
  });
40441
40340
  }
40442
40341
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
40443
- const evalContext = React83__default.useMemo(
40342
+ const evalContext = React82__default.useMemo(
40444
40343
  () => ({
40445
40344
  formValues: formData,
40446
40345
  globalVariables: externalContext?.globalVariables ?? {},
@@ -40449,7 +40348,7 @@ var init_Form = __esm({
40449
40348
  }),
40450
40349
  [formData, externalContext]
40451
40350
  );
40452
- React83__default.useEffect(() => {
40351
+ React82__default.useEffect(() => {
40453
40352
  debug("forms", "initialData-sync", {
40454
40353
  mode: formMode,
40455
40354
  normalizedInitialData,
@@ -40460,7 +40359,7 @@ var init_Form = __esm({
40460
40359
  setFormData(normalizedInitialData);
40461
40360
  }
40462
40361
  }, [normalizedInitialData]);
40463
- const processCalculations = React83__default.useCallback(
40362
+ const processCalculations = React82__default.useCallback(
40464
40363
  (changedFieldId, newFormData) => {
40465
40364
  if (!hiddenCalculations.length) return;
40466
40365
  const context = {
@@ -40485,7 +40384,7 @@ var init_Form = __esm({
40485
40384
  },
40486
40385
  [hiddenCalculations, externalContext, eventBus]
40487
40386
  );
40488
- const checkViolations = React83__default.useCallback(
40387
+ const checkViolations = React82__default.useCallback(
40489
40388
  (changedFieldId, newFormData) => {
40490
40389
  if (!violationTriggers.length) return;
40491
40390
  const context = {
@@ -40523,7 +40422,7 @@ var init_Form = __esm({
40523
40422
  processCalculations(name, newFormData);
40524
40423
  checkViolations(name, newFormData);
40525
40424
  };
40526
- const isFieldVisible = React83__default.useCallback(
40425
+ const isFieldVisible = React82__default.useCallback(
40527
40426
  (fieldName) => {
40528
40427
  const condition = conditionalFields[fieldName];
40529
40428
  if (!condition) return true;
@@ -40531,7 +40430,7 @@ var init_Form = __esm({
40531
40430
  },
40532
40431
  [conditionalFields, evalContext]
40533
40432
  );
40534
- const isSectionVisible = React83__default.useCallback(
40433
+ const isSectionVisible = React82__default.useCallback(
40535
40434
  (section) => {
40536
40435
  if (!section.condition) return true;
40537
40436
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -40607,7 +40506,7 @@ var init_Form = __esm({
40607
40506
  eventBus.emit(`UI:${onCancel}`);
40608
40507
  }
40609
40508
  };
40610
- const renderField = React83__default.useCallback(
40509
+ const renderField = React82__default.useCallback(
40611
40510
  (field) => {
40612
40511
  const fieldName = field.name || field.field;
40613
40512
  if (!fieldName) return null;
@@ -40628,7 +40527,7 @@ var init_Form = __esm({
40628
40527
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
40629
40528
  );
40630
40529
  const effectiveFields = entityDerivedFields ?? fields;
40631
- const normalizedFields = React83__default.useMemo(() => {
40530
+ const normalizedFields = React82__default.useMemo(() => {
40632
40531
  if (!effectiveFields || effectiveFields.length === 0) return [];
40633
40532
  return effectiveFields.map((field) => {
40634
40533
  if (typeof field === "string") {
@@ -40651,7 +40550,7 @@ var init_Form = __esm({
40651
40550
  return field;
40652
40551
  });
40653
40552
  }, [effectiveFields, resolvedEntity]);
40654
- const schemaFields = React83__default.useMemo(() => {
40553
+ const schemaFields = React82__default.useMemo(() => {
40655
40554
  if (normalizedFields.length === 0) return null;
40656
40555
  if (isDebugEnabled()) {
40657
40556
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -40661,7 +40560,7 @@ var init_Form = __esm({
40661
40560
  }
40662
40561
  return normalizedFields.map(renderField).filter(Boolean);
40663
40562
  }, [normalizedFields, renderField, entityName, conditionalFields]);
40664
- const sectionElements = React83__default.useMemo(() => {
40563
+ const sectionElements = React82__default.useMemo(() => {
40665
40564
  if (!sections || sections.length === 0) return null;
40666
40565
  return sections.map((section) => {
40667
40566
  if (!isSectionVisible(section)) {
@@ -41270,7 +41169,7 @@ var init_AssetLoader = __esm({
41270
41169
  __publicField(this, "textureCache");
41271
41170
  __publicField(this, "loadingPromises");
41272
41171
  this.objLoader = new OBJLoader();
41273
- this.textureLoader = new THREE.TextureLoader();
41172
+ this.textureLoader = new THREE3.TextureLoader();
41274
41173
  this.modelCache = /* @__PURE__ */ new Map();
41275
41174
  this.textureCache = /* @__PURE__ */ new Map();
41276
41175
  this.loadingPromises = /* @__PURE__ */ new Map();
@@ -41344,7 +41243,7 @@ var init_AssetLoader = __esm({
41344
41243
  return this.loadingPromises.get(`texture:${url}`);
41345
41244
  }
41346
41245
  const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
41347
- texture.colorSpace = THREE.SRGBColorSpace;
41246
+ texture.colorSpace = THREE3.SRGBColorSpace;
41348
41247
  this.textureCache.set(url, texture);
41349
41248
  this.loadingPromises.delete(`texture:${url}`);
41350
41249
  return texture;
@@ -41418,7 +41317,7 @@ var init_AssetLoader = __esm({
41418
41317
  });
41419
41318
  this.modelCache.forEach((model) => {
41420
41319
  model.scene.traverse((child) => {
41421
- if (child instanceof THREE.Mesh) {
41320
+ if (child instanceof THREE3.Mesh) {
41422
41321
  child.geometry.dispose();
41423
41322
  if (Array.isArray(child.material)) {
41424
41323
  child.material.forEach((m) => m.dispose());
@@ -41831,11 +41730,11 @@ var init_Canvas3DErrorBoundary = __esm({
41831
41730
  "components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
41832
41731
  }
41833
41732
  });
41834
- var log11, Canvas3DErrorBoundary;
41733
+ var log10, Canvas3DErrorBoundary;
41835
41734
  var init_Canvas3DErrorBoundary2 = __esm({
41836
41735
  "components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
41837
41736
  init_Canvas3DErrorBoundary();
41838
- log11 = createLogger("almadar:ui:game:canvas3d:error-boundary");
41737
+ log10 = createLogger("almadar:ui:game:canvas3d:error-boundary");
41839
41738
  Canvas3DErrorBoundary = class extends Component {
41840
41739
  constructor(props) {
41841
41740
  super(props);
@@ -41863,8 +41762,8 @@ var init_Canvas3DErrorBoundary2 = __esm({
41863
41762
  componentDidCatch(error, errorInfo) {
41864
41763
  this.setState({ errorInfo });
41865
41764
  this.props.onError?.(error, errorInfo);
41866
- log11.error("Error caught", { error });
41867
- log11.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
41765
+ log10.error("Error caught", { error });
41766
+ log10.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
41868
41767
  }
41869
41768
  render() {
41870
41769
  if (this.state.hasError) {
@@ -41927,7 +41826,7 @@ function useGLTFModel(url, resourceBasePath) {
41927
41826
  setState({ model: null, isLoading: false, error: null });
41928
41827
  return;
41929
41828
  }
41930
- log12.debug("Loading", { url });
41829
+ log11.debug("Loading", { url });
41931
41830
  setState((prev) => ({ ...prev, isLoading: true, error: null }));
41932
41831
  const assetRoot = resourceBasePath || detectAssetRoot2(url);
41933
41832
  const loader = new GLTFLoader$1();
@@ -41935,7 +41834,7 @@ function useGLTFModel(url, resourceBasePath) {
41935
41834
  loader.load(
41936
41835
  url,
41937
41836
  (gltf) => {
41938
- log12.debug("Loaded", { url });
41837
+ log11.debug("Loaded", { url });
41939
41838
  setState({
41940
41839
  model: gltf.scene,
41941
41840
  isLoading: false,
@@ -41944,7 +41843,7 @@ function useGLTFModel(url, resourceBasePath) {
41944
41843
  },
41945
41844
  void 0,
41946
41845
  (err) => {
41947
- log12.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
41846
+ log11.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
41948
41847
  setState({
41949
41848
  model: null,
41950
41849
  isLoading: false,
@@ -41974,7 +41873,7 @@ function ModelLoader({
41974
41873
  if (!loadedModel) return null;
41975
41874
  const cloned = loadedModel.clone();
41976
41875
  cloned.traverse((child) => {
41977
- if (child instanceof THREE.Mesh) {
41876
+ if (child instanceof THREE3.Mesh) {
41978
41877
  child.castShadow = castShadow;
41979
41878
  child.receiveShadow = receiveShadow;
41980
41879
  }
@@ -42060,11 +41959,11 @@ function ModelLoader({
42060
41959
  }
42061
41960
  );
42062
41961
  }
42063
- var log12;
41962
+ var log11;
42064
41963
  var init_ModelLoader = __esm({
42065
41964
  "components/game/molecules/three/components/ModelLoader.tsx"() {
42066
41965
  "use client";
42067
- log12 = createLogger("almadar:ui:game:model-loader");
41966
+ log11 = createLogger("almadar:ui:game:model-loader");
42068
41967
  }
42069
41968
  });
42070
41969
 
@@ -42088,6 +41987,47 @@ function CameraController({
42088
41987
  }, [camera.position, onCameraChange]);
42089
41988
  return null;
42090
41989
  }
41990
+ function UnitSpriteBillboard({
41991
+ sheetUrl,
41992
+ resolveFrame,
41993
+ height = 1.2
41994
+ }) {
41995
+ const texture = useLoader(THREE3.TextureLoader, sheetUrl);
41996
+ const meshRef = useRef(null);
41997
+ const matRef = useRef(null);
41998
+ const [aspect, setAspect] = useState(1);
41999
+ useFrame(() => {
42000
+ const frame = resolveFrame();
42001
+ if (!frame || !texture.image) return;
42002
+ const imgW = texture.image.width;
42003
+ const imgH = texture.image.height;
42004
+ if (!imgW || !imgH) return;
42005
+ texture.repeat.set((frame.flipX ? -1 : 1) * (frame.sw / imgW), frame.sh / imgH);
42006
+ texture.offset.set(
42007
+ frame.flipX ? (frame.sx + frame.sw) / imgW : frame.sx / imgW,
42008
+ 1 - (frame.sy + frame.sh) / imgH
42009
+ );
42010
+ texture.magFilter = THREE3.NearestFilter;
42011
+ texture.minFilter = THREE3.NearestFilter;
42012
+ texture.needsUpdate = true;
42013
+ const nextAspect = frame.sw / frame.sh;
42014
+ if (Math.abs(nextAspect - aspect) > 1e-3) setAspect(nextAspect);
42015
+ if (matRef.current) matRef.current.needsUpdate = true;
42016
+ });
42017
+ return /* @__PURE__ */ jsxs("mesh", { ref: meshRef, position: [0, height / 2, 0], children: [
42018
+ /* @__PURE__ */ jsx("planeGeometry", { args: [height * aspect, height] }),
42019
+ /* @__PURE__ */ jsx(
42020
+ "meshBasicMaterial",
42021
+ {
42022
+ ref: matRef,
42023
+ map: texture,
42024
+ transparent: true,
42025
+ alphaTest: 0.1,
42026
+ side: THREE3.DoubleSide
42027
+ }
42028
+ )
42029
+ ] });
42030
+ }
42091
42031
  var DEFAULT_GRID_CONFIG, GameCanvas3D;
42092
42032
  var init_GameCanvas3D2 = __esm({
42093
42033
  "components/game/molecules/GameCanvas3D.tsx"() {
@@ -42098,6 +42038,7 @@ var init_GameCanvas3D2 = __esm({
42098
42038
  init_Canvas3DLoadingState2();
42099
42039
  init_Canvas3DErrorBoundary2();
42100
42040
  init_ModelLoader();
42041
+ init_useUnitSpriteAtlas();
42101
42042
  init_cn();
42102
42043
  init_GameCanvas3D();
42103
42044
  DEFAULT_GRID_CONFIG = {
@@ -42154,8 +42095,10 @@ var init_GameCanvas3D2 = __esm({
42154
42095
  const controlsRef = useRef(null);
42155
42096
  const [hoveredTile, setHoveredTile] = useState(null);
42156
42097
  const [internalError, setInternalError] = useState(null);
42098
+ const { sheetUrls: atlasSheetUrls, resolveUnitFrame } = useUnitSpriteAtlas(units);
42099
+ const preloadUrls = useMemo(() => [...preloadAssets, ...atlasSheetUrls], [preloadAssets, atlasSheetUrls]);
42157
42100
  const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
42158
- preloadUrls: preloadAssets,
42101
+ preloadUrls,
42159
42102
  loader: customAssetLoader
42160
42103
  });
42161
42104
  const eventHandlers = useGameCanvas3DEvents({
@@ -42214,7 +42157,7 @@ var init_GameCanvas3D2 = __esm({
42214
42157
  getCameraPosition: () => {
42215
42158
  if (controlsRef.current) {
42216
42159
  const pos = controlsRef.current.object.position;
42217
- return new THREE.Vector3(pos.x, pos.y, pos.z);
42160
+ return new THREE3.Vector3(pos.x, pos.y, pos.z);
42218
42161
  }
42219
42162
  return null;
42220
42163
  },
@@ -42366,6 +42309,8 @@ var init_GameCanvas3D2 = __esm({
42366
42309
  ({ unit, position }) => {
42367
42310
  const isSelected = selectedUnitId === unit.id;
42368
42311
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
42312
+ const hasAtlas = unitAtlasUrl(unit) !== null;
42313
+ const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
42369
42314
  return /* @__PURE__ */ jsxs(
42370
42315
  "group",
42371
42316
  {
@@ -42377,7 +42322,16 @@ var init_GameCanvas3D2 = __esm({
42377
42322
  /* @__PURE__ */ jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
42378
42323
  /* @__PURE__ */ jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
42379
42324
  ] }),
42380
- unit.modelUrl ? (
42325
+ hasAtlas && initialFrame ? (
42326
+ /* Animated sprite-sheet billboard — single cropped frame, by state */
42327
+ /* @__PURE__ */ jsx(Billboard, { children: /* @__PURE__ */ jsx(
42328
+ UnitSpriteBillboard,
42329
+ {
42330
+ sheetUrl: initialFrame.sheetUrl,
42331
+ resolveFrame: () => resolveUnitFrame(unit.id)
42332
+ }
42333
+ ) })
42334
+ ) : unit.modelUrl ? (
42381
42335
  /* GLB unit model (box fallback while loading / on error) */
42382
42336
  /* @__PURE__ */ jsx(
42383
42337
  ModelLoader,
@@ -42431,7 +42385,7 @@ var init_GameCanvas3D2 = __esm({
42431
42385
  }
42432
42386
  );
42433
42387
  },
42434
- [selectedUnitId, handleUnitClick]
42388
+ [selectedUnitId, handleUnitClick, resolveUnitFrame]
42435
42389
  );
42436
42390
  const DefaultFeatureRenderer = useCallback(
42437
42391
  ({
@@ -43498,7 +43452,7 @@ var init_List = __esm({
43498
43452
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
43499
43453
  return [];
43500
43454
  }, [entity]);
43501
- const getItemActions = React83__default.useCallback(
43455
+ const getItemActions = React82__default.useCallback(
43502
43456
  (item) => {
43503
43457
  if (!itemActions) return [];
43504
43458
  if (typeof itemActions === "function") {
@@ -43974,7 +43928,7 @@ var init_MediaGallery = __esm({
43974
43928
  [selectable, selectedItems, selectionEvent, eventBus]
43975
43929
  );
43976
43930
  const entityData = Array.isArray(entity) ? entity : [];
43977
- const items = React83__default.useMemo(() => {
43931
+ const items = React82__default.useMemo(() => {
43978
43932
  if (propItems) return propItems;
43979
43933
  if (entityData.length === 0) return [];
43980
43934
  return entityData.map((record, idx) => ({
@@ -44135,7 +44089,7 @@ var init_MediaGallery = __esm({
44135
44089
  }
44136
44090
  });
44137
44091
  function extractTitle2(children) {
44138
- if (!React83__default.isValidElement(children)) return void 0;
44092
+ if (!React82__default.isValidElement(children)) return void 0;
44139
44093
  const props = children.props;
44140
44094
  if (typeof props.title === "string") {
44141
44095
  return props.title;
@@ -45140,7 +45094,7 @@ var init_debugRegistry = __esm({
45140
45094
  }
45141
45095
  });
45142
45096
  function useDebugData() {
45143
- const [data, setData] = React83.useState(() => ({
45097
+ const [data, setData] = React82.useState(() => ({
45144
45098
  traits: [],
45145
45099
  ticks: [],
45146
45100
  guards: [],
@@ -45154,7 +45108,7 @@ function useDebugData() {
45154
45108
  },
45155
45109
  lastUpdate: Date.now()
45156
45110
  }));
45157
- React83.useEffect(() => {
45111
+ React82.useEffect(() => {
45158
45112
  const updateData = () => {
45159
45113
  setData({
45160
45114
  traits: getAllTraits(),
@@ -45263,12 +45217,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
45263
45217
  return positions;
45264
45218
  }
45265
45219
  function WalkMinimap() {
45266
- const [walkStep, setWalkStep] = React83.useState(null);
45267
- const [traits2, setTraits] = React83.useState([]);
45268
- const [coveredEdges, setCoveredEdges] = React83.useState([]);
45269
- const [completedTraits, setCompletedTraits] = React83.useState(/* @__PURE__ */ new Set());
45270
- const prevTraitRef = React83.useRef(null);
45271
- React83.useEffect(() => {
45220
+ const [walkStep, setWalkStep] = React82.useState(null);
45221
+ const [traits2, setTraits] = React82.useState([]);
45222
+ const [coveredEdges, setCoveredEdges] = React82.useState([]);
45223
+ const [completedTraits, setCompletedTraits] = React82.useState(/* @__PURE__ */ new Set());
45224
+ const prevTraitRef = React82.useRef(null);
45225
+ React82.useEffect(() => {
45272
45226
  const interval = setInterval(() => {
45273
45227
  const w = window;
45274
45228
  const step = w.__orbitalWalkStep;
@@ -45704,15 +45658,15 @@ var init_EntitiesTab = __esm({
45704
45658
  });
45705
45659
  function EventFlowTab({ events: events2 }) {
45706
45660
  const { t } = useTranslate();
45707
- const [filter, setFilter] = React83.useState("all");
45708
- const containerRef = React83.useRef(null);
45709
- const [autoScroll, setAutoScroll] = React83.useState(true);
45710
- React83.useEffect(() => {
45661
+ const [filter, setFilter] = React82.useState("all");
45662
+ const containerRef = React82.useRef(null);
45663
+ const [autoScroll, setAutoScroll] = React82.useState(true);
45664
+ React82.useEffect(() => {
45711
45665
  if (autoScroll && containerRef.current) {
45712
45666
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
45713
45667
  }
45714
45668
  }, [events2.length, autoScroll]);
45715
- const filteredEvents = React83.useMemo(() => {
45669
+ const filteredEvents = React82.useMemo(() => {
45716
45670
  if (filter === "all") return events2;
45717
45671
  return events2.filter((e) => e.type === filter);
45718
45672
  }, [events2, filter]);
@@ -45828,7 +45782,7 @@ var init_EventFlowTab = __esm({
45828
45782
  });
45829
45783
  function GuardsPanel({ guards }) {
45830
45784
  const { t } = useTranslate();
45831
- const [filter, setFilter] = React83.useState("all");
45785
+ const [filter, setFilter] = React82.useState("all");
45832
45786
  if (guards.length === 0) {
45833
45787
  return /* @__PURE__ */ jsx(
45834
45788
  EmptyState,
@@ -45841,7 +45795,7 @@ function GuardsPanel({ guards }) {
45841
45795
  }
45842
45796
  const passedCount = guards.filter((g) => g.result).length;
45843
45797
  const failedCount = guards.length - passedCount;
45844
- const filteredGuards = React83.useMemo(() => {
45798
+ const filteredGuards = React82.useMemo(() => {
45845
45799
  if (filter === "all") return guards;
45846
45800
  if (filter === "passed") return guards.filter((g) => g.result);
45847
45801
  return guards.filter((g) => !g.result);
@@ -46004,10 +45958,10 @@ function EffectBadge({ effect }) {
46004
45958
  }
46005
45959
  function TransitionTimeline({ transitions }) {
46006
45960
  const { t } = useTranslate();
46007
- const containerRef = React83.useRef(null);
46008
- const [autoScroll, setAutoScroll] = React83.useState(true);
46009
- const [expandedId, setExpandedId] = React83.useState(null);
46010
- React83.useEffect(() => {
45961
+ const containerRef = React82.useRef(null);
45962
+ const [autoScroll, setAutoScroll] = React82.useState(true);
45963
+ const [expandedId, setExpandedId] = React82.useState(null);
45964
+ React82.useEffect(() => {
46011
45965
  if (autoScroll && containerRef.current) {
46012
45966
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
46013
45967
  }
@@ -46287,9 +46241,9 @@ function getAllEvents(traits2) {
46287
46241
  function EventDispatcherTab({ traits: traits2, schema }) {
46288
46242
  const eventBus = useEventBus();
46289
46243
  const { t } = useTranslate();
46290
- const [log14, setLog] = React83.useState([]);
46291
- const prevStatesRef = React83.useRef(/* @__PURE__ */ new Map());
46292
- React83.useEffect(() => {
46244
+ const [log13, setLog] = React82.useState([]);
46245
+ const prevStatesRef = React82.useRef(/* @__PURE__ */ new Map());
46246
+ React82.useEffect(() => {
46293
46247
  for (const trait of traits2) {
46294
46248
  const prev = prevStatesRef.current.get(trait.id);
46295
46249
  if (prev && prev !== trait.currentState) {
@@ -46351,9 +46305,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
46351
46305
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
46352
46306
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: unavailableEvents.map((event) => /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", className: "opacity-50", children: event }, event)) })
46353
46307
  ] }),
46354
- log14.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
46308
+ log13.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
46355
46309
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
46356
- /* @__PURE__ */ jsx(Stack, { gap: "xs", children: log14.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
46310
+ /* @__PURE__ */ jsx(Stack, { gap: "xs", children: log13.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
46357
46311
  /* @__PURE__ */ jsx("span", { className: "text-purple-400", children: entry.traitName }),
46358
46312
  " ",
46359
46313
  /* @__PURE__ */ jsx("span", { className: "text-gray-500", children: entry.from }),
@@ -46458,10 +46412,10 @@ function VerifyModePanel({
46458
46412
  localCount
46459
46413
  }) {
46460
46414
  const { t } = useTranslate();
46461
- const [expanded, setExpanded] = React83.useState(true);
46462
- const scrollRef = React83.useRef(null);
46463
- const prevCountRef = React83.useRef(0);
46464
- React83.useEffect(() => {
46415
+ const [expanded, setExpanded] = React82.useState(true);
46416
+ const scrollRef = React82.useRef(null);
46417
+ const prevCountRef = React82.useRef(0);
46418
+ React82.useEffect(() => {
46465
46419
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
46466
46420
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
46467
46421
  }
@@ -46518,10 +46472,10 @@ function RuntimeDebugger({
46518
46472
  schema
46519
46473
  }) {
46520
46474
  const { t } = useTranslate();
46521
- const [isCollapsed, setIsCollapsed] = React83.useState(mode === "verify" ? true : defaultCollapsed);
46522
- const [isVisible, setIsVisible] = React83.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
46475
+ const [isCollapsed, setIsCollapsed] = React82.useState(mode === "verify" ? true : defaultCollapsed);
46476
+ const [isVisible, setIsVisible] = React82.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
46523
46477
  const debugData = useDebugData();
46524
- React83.useEffect(() => {
46478
+ React82.useEffect(() => {
46525
46479
  if (mode === "inline") return;
46526
46480
  return onDebugToggle((enabled) => {
46527
46481
  setIsVisible(enabled);
@@ -46530,7 +46484,7 @@ function RuntimeDebugger({
46530
46484
  }
46531
46485
  });
46532
46486
  }, [mode]);
46533
- React83.useEffect(() => {
46487
+ React82.useEffect(() => {
46534
46488
  if (mode === "inline") return;
46535
46489
  const handleKeyDown = (e) => {
46536
46490
  if (e.key === "`" && isVisible) {
@@ -47090,7 +47044,7 @@ function SequenceBar({
47090
47044
  onSlotRemove(index);
47091
47045
  }, [onSlotRemove, playing]);
47092
47046
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
47093
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
47047
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
47094
47048
  i > 0 && /* @__PURE__ */ jsx(
47095
47049
  Typography,
47096
47050
  {
@@ -47979,7 +47933,7 @@ var init_StatCard = __esm({
47979
47933
  const labelToUse = propLabel ?? propTitle;
47980
47934
  const eventBus = useEventBus();
47981
47935
  const { t } = useTranslate();
47982
- const handleActionClick = React83__default.useCallback(() => {
47936
+ const handleActionClick = React82__default.useCallback(() => {
47983
47937
  if (action?.event) {
47984
47938
  eventBus.emit(`UI:${action.event}`, {});
47985
47939
  }
@@ -47990,7 +47944,7 @@ var init_StatCard = __esm({
47990
47944
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
47991
47945
  const isLoading = externalLoading ?? false;
47992
47946
  const error = externalError;
47993
- const computeMetricValue = React83__default.useCallback(
47947
+ const computeMetricValue = React82__default.useCallback(
47994
47948
  (metric, items) => {
47995
47949
  if (metric.value !== void 0) {
47996
47950
  return metric.value;
@@ -48029,7 +47983,7 @@ var init_StatCard = __esm({
48029
47983
  },
48030
47984
  []
48031
47985
  );
48032
- const schemaStats = React83__default.useMemo(() => {
47986
+ const schemaStats = React82__default.useMemo(() => {
48033
47987
  if (!metrics || metrics.length === 0) return null;
48034
47988
  return metrics.map((metric) => ({
48035
47989
  label: metric.label,
@@ -48037,7 +47991,7 @@ var init_StatCard = __esm({
48037
47991
  format: metric.format
48038
47992
  }));
48039
47993
  }, [metrics, data, computeMetricValue]);
48040
- const calculatedTrend = React83__default.useMemo(() => {
47994
+ const calculatedTrend = React82__default.useMemo(() => {
48041
47995
  if (manualTrend !== void 0) return manualTrend;
48042
47996
  if (previousValue === void 0 || currentValue === void 0)
48043
47997
  return void 0;
@@ -49003,7 +48957,7 @@ var init_Timeline = __esm({
49003
48957
  }) => {
49004
48958
  const { t } = useTranslate();
49005
48959
  const entityData = Array.isArray(entity) ? entity : [];
49006
- const items = React83__default.useMemo(() => {
48960
+ const items = React82__default.useMemo(() => {
49007
48961
  if (propItems) return propItems;
49008
48962
  if (entityData.length === 0) return [];
49009
48963
  return entityData.map((record, idx) => {
@@ -49110,7 +49064,7 @@ var init_Timeline = __esm({
49110
49064
  }
49111
49065
  });
49112
49066
  function extractToastProps(children) {
49113
- if (!React83__default.isValidElement(children)) {
49067
+ if (!React82__default.isValidElement(children)) {
49114
49068
  if (typeof children === "string") {
49115
49069
  return { message: children };
49116
49070
  }
@@ -49148,7 +49102,7 @@ var init_ToastSlot = __esm({
49148
49102
  eventBus.emit("UI:CLOSE");
49149
49103
  };
49150
49104
  if (!isVisible) return null;
49151
- const isCustomContent = React83__default.isValidElement(children) && !message;
49105
+ const isCustomContent = React82__default.isValidElement(children) && !message;
49152
49106
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
49153
49107
  Toast,
49154
49108
  {
@@ -50017,7 +49971,7 @@ var init_WorldMapTemplate = __esm({
50017
49971
  }
50018
49972
  });
50019
49973
  function lazyThree(name, loader) {
50020
- const Lazy = React83__default.lazy(
49974
+ const Lazy = React82__default.lazy(
50021
49975
  () => loader().then((m) => {
50022
49976
  const Resolved = m[name];
50023
49977
  if (!Resolved) {
@@ -50029,13 +49983,13 @@ function lazyThree(name, loader) {
50029
49983
  })
50030
49984
  );
50031
49985
  function ThreeWrapper(props) {
50032
- return React83__default.createElement(
49986
+ return React82__default.createElement(
50033
49987
  ThreeBoundary,
50034
49988
  { name },
50035
- React83__default.createElement(
50036
- React83__default.Suspense,
49989
+ React82__default.createElement(
49990
+ React82__default.Suspense,
50037
49991
  { fallback: null },
50038
- React83__default.createElement(Lazy, props)
49992
+ React82__default.createElement(Lazy, props)
50039
49993
  )
50040
49994
  );
50041
49995
  }
@@ -50333,7 +50287,7 @@ var init_component_registry_generated = __esm({
50333
50287
  init_WorldMapBoard();
50334
50288
  init_WorldMapTemplate();
50335
50289
  init_XPBar();
50336
- ThreeBoundary = class extends React83__default.Component {
50290
+ ThreeBoundary = class extends React82__default.Component {
50337
50291
  constructor() {
50338
50292
  super(...arguments);
50339
50293
  __publicField(this, "state", { failed: false });
@@ -50343,7 +50297,7 @@ var init_component_registry_generated = __esm({
50343
50297
  }
50344
50298
  render() {
50345
50299
  if (this.state.failed) {
50346
- return React83__default.createElement(
50300
+ return React82__default.createElement(
50347
50301
  "div",
50348
50302
  {
50349
50303
  "data-testid": "three-unavailable",
@@ -50684,7 +50638,7 @@ function SuspenseConfigProvider({
50684
50638
  config,
50685
50639
  children
50686
50640
  }) {
50687
- return React83__default.createElement(
50641
+ return React82__default.createElement(
50688
50642
  SuspenseConfigContext.Provider,
50689
50643
  { value: config },
50690
50644
  children
@@ -51174,7 +51128,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
51174
51128
  const key = `${parentId}-${index}-trait:${traitName}`;
51175
51129
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
51176
51130
  }
51177
- return /* @__PURE__ */ jsx(React83__default.Fragment, { children: child }, `${parentId}-${index}`);
51131
+ return /* @__PURE__ */ jsx(React82__default.Fragment, { children: child }, `${parentId}-${index}`);
51178
51132
  }
51179
51133
  if (!child || typeof child !== "object") return null;
51180
51134
  const childId = `${parentId}-${index}`;
@@ -51214,14 +51168,14 @@ function isPatternConfig(value) {
51214
51168
  if (value === null || value === void 0) return false;
51215
51169
  if (typeof value !== "object") return false;
51216
51170
  if (Array.isArray(value)) return false;
51217
- if (React83__default.isValidElement(value)) return false;
51171
+ if (React82__default.isValidElement(value)) return false;
51218
51172
  if (value instanceof Date) return false;
51219
51173
  if (typeof value === "function") return false;
51220
51174
  const record = value;
51221
51175
  return "type" in record && typeof record.type === "string";
51222
51176
  }
51223
51177
  function isPlainConfigObject(value) {
51224
- if (React83__default.isValidElement(value)) return false;
51178
+ if (React82__default.isValidElement(value)) return false;
51225
51179
  if (value instanceof Date) return false;
51226
51180
  const proto = Object.getPrototypeOf(value);
51227
51181
  return proto === Object.prototype || proto === null;
@@ -51560,9 +51514,6 @@ var init_UISlotRenderer = __esm({
51560
51514
  }
51561
51515
  });
51562
51516
 
51563
- // providers/OrbitalProvider.tsx
51564
- init_ThemeContext();
51565
-
51566
51517
  // providers/EventBusProvider.tsx
51567
51518
  init_useEventBus();
51568
51519
  var busLog = createLogger("almadar:eventbus");
@@ -51714,7 +51665,7 @@ function EventBusProvider({ children, isolated = false }) {
51714
51665
 
51715
51666
  // providers/SelectionProvider.tsx
51716
51667
  init_useEventBus();
51717
- var log3 = createLogger("almadar:ui:selection");
51668
+ var log2 = createLogger("almadar:ui:selection");
51718
51669
  var SelectionContext = createContext(null);
51719
51670
  var defaultCompareEntities = (a, b) => {
51720
51671
  if (a === b) return true;
@@ -51737,7 +51688,7 @@ function SelectionProvider({
51737
51688
  (entity) => {
51738
51689
  setSelectedState(entity);
51739
51690
  if (debug2) {
51740
- log3.debug("Selection set", () => ({
51691
+ log2.debug("Selection set", () => ({
51741
51692
  hasEntity: entity !== null && entity !== void 0,
51742
51693
  entityId: entity && typeof entity === "object" ? String(entity.id ?? "") : ""
51743
51694
  }));
@@ -51748,7 +51699,7 @@ function SelectionProvider({
51748
51699
  const clearSelection = useCallback(() => {
51749
51700
  setSelectedState(null);
51750
51701
  if (debug2) {
51751
- log3.debug("Selection cleared");
51702
+ log2.debug("Selection cleared");
51752
51703
  }
51753
51704
  }, [debug2]);
51754
51705
  const isSelected = useCallback(
@@ -51763,7 +51714,7 @@ function SelectionProvider({
51763
51714
  if (row) {
51764
51715
  setSelected(row);
51765
51716
  if (debug2) {
51766
- log3.debug("event received", () => ({
51717
+ log2.debug("event received", () => ({
51767
51718
  type: event.type,
51768
51719
  rowId: row && typeof row === "object" ? String(row.id ?? "") : ""
51769
51720
  }));
@@ -51773,7 +51724,7 @@ function SelectionProvider({
51773
51724
  const handleDeselect = (event) => {
51774
51725
  clearSelection();
51775
51726
  if (debug2) {
51776
- log3.debug("event received - clearing selection", { type: event.type });
51727
+ log2.debug("event received - clearing selection", { type: event.type });
51777
51728
  }
51778
51729
  };
51779
51730
  const unsubView = eventBus.on("UI:VIEW", handleSelect);
@@ -51815,7 +51766,7 @@ init_UISlotRenderer();
51815
51766
  // providers/VerificationProvider.tsx
51816
51767
  init_useEventBus();
51817
51768
  init_verificationRegistry();
51818
- var log13 = createLogger("almadar:verify");
51769
+ var log12 = createLogger("almadar:verify");
51819
51770
  var DISPATCH_SUFFIX = ":DISPATCH";
51820
51771
  var SUCCESS_SUFFIX = ":SUCCESS";
51821
51772
  var ERROR_SUFFIX = ":ERROR";
@@ -51862,7 +51813,7 @@ function VerificationProvider({
51862
51813
  const verificationProviderLifecycleListener = (evt) => {
51863
51814
  const parsed = parseLifecycleEvent(evt.type);
51864
51815
  if (!parsed) return;
51865
- log13.debug("lifecycle:event", { kind: parsed.kind, traitName: parsed.traitName, event: parsed.event, type: evt.type });
51816
+ log12.debug("lifecycle:event", { kind: parsed.kind, traitName: parsed.traitName, event: parsed.event, type: evt.type });
51866
51817
  const payload = evt.payload ?? {};
51867
51818
  if (parsed.kind === "dispatch") {
51868
51819
  const key = `${parsed.traitName}:${String(payload["event"] ?? "")}`;
@@ -51917,7 +51868,7 @@ function VerificationProvider({
51917
51868
  },
51918
51869
  timestamp: Date.now()
51919
51870
  });
51920
- log13.debug("transition:success", { trait: parsed.traitName, event: parsed.event, from: pending?.from, to: newState, effectCount: effects.length });
51871
+ log12.debug("transition:success", { trait: parsed.traitName, event: parsed.event, from: pending?.from, to: newState, effectCount: effects.length });
51921
51872
  } else if (parsed.kind === "error" && parsed.event) {
51922
51873
  const key = `${parsed.traitName}:${parsed.event}`;
51923
51874
  const pending = pendingRef.current.get(key);
@@ -51947,7 +51898,7 @@ function VerificationProvider({
51947
51898
  },
51948
51899
  timestamp: Date.now()
51949
51900
  });
51950
- log13.warn("transition:error", { trait: parsed.traitName, event: parsed.event, from: fromState, error: errorMsg });
51901
+ log12.warn("transition:error", { trait: parsed.traitName, event: parsed.event, from: fromState, error: errorMsg });
51951
51902
  }
51952
51903
  };
51953
51904
  Object.defineProperty(verificationProviderLifecycleListener, "name", {