@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.
package/dist/avl/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import * as React91 from 'react';
3
- import React91__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
2
+ import * as React90 from 'react';
3
+ import React90__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
4
4
  import { OrbitalProvider, EventBusContext, useTraitScope, VerificationProvider, TraitScopeProvider } from '@almadar/ui/providers';
5
5
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
6
6
  import ELK from 'elkjs/lib/elk.bundled.js';
@@ -9,8 +9,8 @@ import { useTranslate, useEventBus as useEventBus$1 } from '@almadar/ui/hooks';
9
9
  import * as LucideIcons2 from 'lucide-react';
10
10
  import { Loader2, X, Code, FileText, WrapText, Check, Copy, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, 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';
11
11
  import { createPortal } from 'react-dom';
12
+ import { UISlotProvider, useUISlots, useTheme } from '@almadar/ui/context';
12
13
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
13
- import { UISlotProvider, useUISlots } from '@almadar/ui/context';
14
14
  import { Link, Outlet, useLocation } from 'react-router-dom';
15
15
  import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light.js';
16
16
  import dark from 'react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus.js';
@@ -39,15 +39,15 @@ import { FieldTypeSchema, isInlineTrait, isPageReference, isEntityCall, schemaTo
39
39
  import { useDroppable, useDraggable, DndContext, DragOverlay, useSensors, useSensor, PointerSensor, KeyboardSensor, pointerWithin, rectIntersection, closestCorners } from '@dnd-kit/core';
40
40
  import { sortableKeyboardCoordinates, useSortable, arrayMove, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
41
41
  import { CSS } from '@dnd-kit/utilities';
42
- import * as THREE from 'three';
42
+ import * as THREE3 from 'three';
43
43
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
44
44
  import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
45
45
  import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
46
- import { Canvas, useThree } from '@react-three/fiber';
47
- import { Grid as Grid$1, OrbitControls } from '@react-three/drei';
46
+ import { Canvas, useLoader, useFrame, useThree } from '@react-three/fiber';
47
+ import { Billboard, Grid as Grid$1, OrbitControls } from '@react-three/drei';
48
48
  import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1, isEntityAwarePattern } from '@almadar/patterns';
49
49
  import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
50
- import { InMemoryPersistence, StateMachineManager, createContextFromBindings, interpolateValue, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor } from '@almadar/runtime';
50
+ import { InMemoryPersistence, StateMachineManager, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor, interpolateValue, createContextFromBindings } from '@almadar/runtime';
51
51
 
52
52
  var __defProp = Object.defineProperty;
53
53
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -3470,7 +3470,7 @@ var init_Box = __esm({
3470
3470
  fixed: "fixed",
3471
3471
  sticky: "sticky"
3472
3472
  };
3473
- Box = React91__default.forwardRef(
3473
+ Box = React90__default.forwardRef(
3474
3474
  ({
3475
3475
  padding,
3476
3476
  paddingX,
@@ -3520,7 +3520,7 @@ var init_Box = __esm({
3520
3520
  onMouseLeave?.(e);
3521
3521
  }, [hoverEvent, eventBus, onMouseLeave]);
3522
3522
  const isClickable = action || onClick;
3523
- return React91__default.createElement(
3523
+ return React90__default.createElement(
3524
3524
  Component2,
3525
3525
  {
3526
3526
  ref,
@@ -4110,7 +4110,7 @@ var init_MiniStateMachine = __esm({
4110
4110
  const x = 2 + i * (NODE_W + GAP + ARROW_W + GAP);
4111
4111
  const tc = transitionCounts[s.name] ?? 0;
4112
4112
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
4113
- return /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
4113
+ return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
4114
4114
  /* @__PURE__ */ jsx(
4115
4115
  AvlState,
4116
4116
  {
@@ -4485,7 +4485,7 @@ function loadLib(key, importer) {
4485
4485
  return p2;
4486
4486
  }
4487
4487
  function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
4488
- const Lazy = React91__default.lazy(async () => {
4488
+ const Lazy = React90__default.lazy(async () => {
4489
4489
  const lib = await loadLib(libKey, importer);
4490
4490
  const Comp = pick(lib);
4491
4491
  if (!Comp) {
@@ -4495,7 +4495,7 @@ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
4495
4495
  return { default: Comp };
4496
4496
  });
4497
4497
  const Wrapped = (props) => /* @__PURE__ */ jsx(
4498
- React91__default.Suspense,
4498
+ React90__default.Suspense,
4499
4499
  {
4500
4500
  fallback: /* @__PURE__ */ jsx(
4501
4501
  "span",
@@ -5221,7 +5221,7 @@ var init_Icon = __esm({
5221
5221
  const directIcon = typeof icon === "string" ? void 0 : icon;
5222
5222
  const effectiveName = typeof icon === "string" ? icon : name;
5223
5223
  const family = useIconFamily();
5224
- const RenderedComponent = React91__default.useMemo(() => {
5224
+ const RenderedComponent = React90__default.useMemo(() => {
5225
5225
  if (directIcon) return null;
5226
5226
  return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
5227
5227
  }, [directIcon, effectiveName, family]);
@@ -5280,7 +5280,7 @@ function resolveIconProp(value, sizeClass) {
5280
5280
  const IconComp = value;
5281
5281
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
5282
5282
  }
5283
- if (React91__default.isValidElement(value)) {
5283
+ if (React90__default.isValidElement(value)) {
5284
5284
  return value;
5285
5285
  }
5286
5286
  if (typeof value === "object" && value !== null && "render" in value) {
@@ -5356,7 +5356,7 @@ var init_Button = __esm({
5356
5356
  md: "h-icon-default w-icon-default",
5357
5357
  lg: "h-icon-default w-icon-default"
5358
5358
  };
5359
- Button = React91__default.forwardRef(
5359
+ Button = React90__default.forwardRef(
5360
5360
  ({
5361
5361
  className,
5362
5362
  variant = "primary",
@@ -5421,7 +5421,7 @@ var Dialog;
5421
5421
  var init_Dialog = __esm({
5422
5422
  "components/core/atoms/Dialog.tsx"() {
5423
5423
  init_cn();
5424
- Dialog = React91__default.forwardRef(
5424
+ Dialog = React90__default.forwardRef(
5425
5425
  ({
5426
5426
  role = "dialog",
5427
5427
  "aria-modal": ariaModal = true,
@@ -5916,7 +5916,7 @@ var init_Badge = __esm({
5916
5916
  md: "px-2.5 py-1 text-sm",
5917
5917
  lg: "px-3 py-1.5 text-base"
5918
5918
  };
5919
- Badge = React91__default.forwardRef(
5919
+ Badge = React90__default.forwardRef(
5920
5920
  ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
5921
5921
  const iconSizes3 = {
5922
5922
  sm: "h-icon-default w-icon-default",
@@ -6252,7 +6252,7 @@ var init_SvgFlow = __esm({
6252
6252
  width = 100,
6253
6253
  height = 100
6254
6254
  }) => {
6255
- const markerId = React91__default.useMemo(() => {
6255
+ const markerId = React90__default.useMemo(() => {
6256
6256
  flowIdCounter += 1;
6257
6257
  return `almadar-flow-arrow-${flowIdCounter}`;
6258
6258
  }, []);
@@ -6845,7 +6845,7 @@ var init_SvgRing = __esm({
6845
6845
  width = 100,
6846
6846
  height = 100
6847
6847
  }) => {
6848
- const gradientId = React91__default.useMemo(() => {
6848
+ const gradientId = React90__default.useMemo(() => {
6849
6849
  ringIdCounter += 1;
6850
6850
  return `almadar-ring-glow-${ringIdCounter}`;
6851
6851
  }, []);
@@ -7026,7 +7026,7 @@ var init_Input = __esm({
7026
7026
  init_cn();
7027
7027
  init_Icon();
7028
7028
  init_useEventBus();
7029
- Input = React91__default.forwardRef(
7029
+ Input = React90__default.forwardRef(
7030
7030
  ({
7031
7031
  className,
7032
7032
  inputType,
@@ -7186,7 +7186,7 @@ var Label;
7186
7186
  var init_Label = __esm({
7187
7187
  "components/core/atoms/Label.tsx"() {
7188
7188
  init_cn();
7189
- Label = React91__default.forwardRef(
7189
+ Label = React90__default.forwardRef(
7190
7190
  ({ className, required, children, ...props }, ref) => {
7191
7191
  return /* @__PURE__ */ jsxs(
7192
7192
  "label",
@@ -7213,7 +7213,7 @@ var init_Textarea = __esm({
7213
7213
  "components/core/atoms/Textarea.tsx"() {
7214
7214
  init_cn();
7215
7215
  init_useEventBus();
7216
- Textarea = React91__default.forwardRef(
7216
+ Textarea = React90__default.forwardRef(
7217
7217
  ({ className, error, onChange, ...props }, ref) => {
7218
7218
  const eventBus = useEventBus();
7219
7219
  const handleChange = (e) => {
@@ -7452,7 +7452,7 @@ var init_Select = __esm({
7452
7452
  init_cn();
7453
7453
  init_Icon();
7454
7454
  init_useEventBus();
7455
- Select = React91__default.forwardRef(
7455
+ Select = React90__default.forwardRef(
7456
7456
  (props, _ref) => {
7457
7457
  const { multiple, searchable, clearable } = props;
7458
7458
  if (multiple || searchable || clearable) {
@@ -7469,7 +7469,7 @@ var init_Checkbox = __esm({
7469
7469
  "components/core/atoms/Checkbox.tsx"() {
7470
7470
  init_cn();
7471
7471
  init_useEventBus();
7472
- Checkbox = React91__default.forwardRef(
7472
+ Checkbox = React90__default.forwardRef(
7473
7473
  ({ className, label, id, onChange, ...props }, ref) => {
7474
7474
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
7475
7475
  const eventBus = useEventBus();
@@ -7523,7 +7523,7 @@ var init_Spinner = __esm({
7523
7523
  md: "h-6 w-6",
7524
7524
  lg: "h-8 w-8"
7525
7525
  };
7526
- Spinner = React91__default.forwardRef(
7526
+ Spinner = React90__default.forwardRef(
7527
7527
  ({ className, size = "md", overlay, ...props }, ref) => {
7528
7528
  if (overlay) {
7529
7529
  return /* @__PURE__ */ jsx(
@@ -7613,7 +7613,7 @@ var init_Card = __esm({
7613
7613
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
7614
7614
  "tile-image-first": "p-0 overflow-hidden"
7615
7615
  };
7616
- Card = React91__default.forwardRef(
7616
+ Card = React90__default.forwardRef(
7617
7617
  ({
7618
7618
  className,
7619
7619
  variant = "bordered",
@@ -7661,9 +7661,9 @@ var init_Card = __esm({
7661
7661
  }
7662
7662
  );
7663
7663
  Card.displayName = "Card";
7664
- CardHeader = React91__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
7664
+ CardHeader = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
7665
7665
  CardHeader.displayName = "CardHeader";
7666
- CardTitle = React91__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7666
+ CardTitle = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7667
7667
  "h3",
7668
7668
  {
7669
7669
  ref,
@@ -7676,11 +7676,11 @@ var init_Card = __esm({
7676
7676
  }
7677
7677
  ));
7678
7678
  CardTitle.displayName = "CardTitle";
7679
- CardContent = React91__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
7679
+ CardContent = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
7680
7680
  CardContent.displayName = "CardContent";
7681
7681
  CardBody = CardContent;
7682
7682
  CardBody.displayName = "CardBody";
7683
- CardFooter = React91__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7683
+ CardFooter = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7684
7684
  "div",
7685
7685
  {
7686
7686
  ref,
@@ -7735,7 +7735,7 @@ var init_FilterPill = __esm({
7735
7735
  md: "w-3.5 h-3.5",
7736
7736
  lg: "w-4 h-4"
7737
7737
  };
7738
- FilterPill = React91__default.forwardRef(
7738
+ FilterPill = React90__default.forwardRef(
7739
7739
  ({
7740
7740
  className,
7741
7741
  variant = "default",
@@ -7864,8 +7864,8 @@ var init_Avatar = __esm({
7864
7864
  actionPayload
7865
7865
  }) => {
7866
7866
  const eventBus = useEventBus();
7867
- const [imgFailed, setImgFailed] = React91__default.useState(false);
7868
- React91__default.useEffect(() => {
7867
+ const [imgFailed, setImgFailed] = React90__default.useState(false);
7868
+ React90__default.useEffect(() => {
7869
7869
  setImgFailed(false);
7870
7870
  }, [src]);
7871
7871
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -8250,7 +8250,7 @@ var init_Radio = __esm({
8250
8250
  md: "w-2.5 h-2.5",
8251
8251
  lg: "w-3 h-3"
8252
8252
  };
8253
- Radio = React91__default.forwardRef(
8253
+ Radio = React90__default.forwardRef(
8254
8254
  ({
8255
8255
  label,
8256
8256
  helperText,
@@ -8267,12 +8267,12 @@ var init_Radio = __esm({
8267
8267
  onChange,
8268
8268
  ...props
8269
8269
  }, ref) => {
8270
- const reactId = React91__default.useId();
8270
+ const reactId = React90__default.useId();
8271
8271
  const baseId = id || `radio-${reactId}`;
8272
8272
  const hasError = !!error;
8273
8273
  const eventBus = useEventBus();
8274
- const [selected, setSelected] = React91__default.useState(value);
8275
- React91__default.useEffect(() => {
8274
+ const [selected, setSelected] = React90__default.useState(value);
8275
+ React90__default.useEffect(() => {
8276
8276
  if (value !== void 0) setSelected(value);
8277
8277
  }, [value]);
8278
8278
  const pick = (next, e) => {
@@ -8454,7 +8454,7 @@ var init_Switch = __esm({
8454
8454
  "components/core/atoms/Switch.tsx"() {
8455
8455
  "use client";
8456
8456
  init_cn();
8457
- Switch = React91.forwardRef(
8457
+ Switch = React90.forwardRef(
8458
8458
  ({
8459
8459
  checked,
8460
8460
  defaultChecked = false,
@@ -8465,10 +8465,10 @@ var init_Switch = __esm({
8465
8465
  name,
8466
8466
  className
8467
8467
  }, ref) => {
8468
- const [isChecked, setIsChecked] = React91.useState(
8468
+ const [isChecked, setIsChecked] = React90.useState(
8469
8469
  checked !== void 0 ? checked : defaultChecked
8470
8470
  );
8471
- React91.useEffect(() => {
8471
+ React90.useEffect(() => {
8472
8472
  if (checked !== void 0) {
8473
8473
  setIsChecked(checked);
8474
8474
  }
@@ -8637,188 +8637,12 @@ var init_TextHighlight = __esm({
8637
8637
  TextHighlight.displayName = "TextHighlight";
8638
8638
  }
8639
8639
  });
8640
- function useTheme() {
8641
- const context = useContext(ThemeContext);
8642
- if (context === void 0) {
8643
- return {
8644
- theme: "wireframe",
8645
- mode: "light",
8646
- resolvedMode: "light",
8647
- setTheme: () => {
8648
- },
8649
- setMode: () => {
8650
- },
8651
- toggleMode: () => {
8652
- },
8653
- availableThemes: BUILT_IN_THEMES,
8654
- appliedTheme: "wireframe-light"
8655
- };
8656
- }
8657
- return context;
8658
- }
8659
- var BUILT_IN_THEMES, ThemeContext;
8660
- var init_ThemeContext = __esm({
8661
- "context/ThemeContext.tsx"() {
8662
- "use client";
8663
- createLogger("almadar:ui:theme");
8664
- BUILT_IN_THEMES = [
8665
- {
8666
- name: "wireframe",
8667
- displayName: "Wireframe",
8668
- hasLightMode: true,
8669
- hasDarkMode: true
8670
- },
8671
- {
8672
- name: "minimalist",
8673
- displayName: "Minimalist",
8674
- hasLightMode: true,
8675
- hasDarkMode: true
8676
- },
8677
- {
8678
- name: "almadar",
8679
- displayName: "Almadar",
8680
- hasLightMode: true,
8681
- hasDarkMode: true
8682
- },
8683
- {
8684
- name: "trait-wars",
8685
- displayName: "Trait Wars",
8686
- hasLightMode: false,
8687
- hasDarkMode: true
8688
- },
8689
- // Extended themes
8690
- {
8691
- name: "ocean",
8692
- displayName: "Ocean",
8693
- hasLightMode: true,
8694
- hasDarkMode: true
8695
- },
8696
- {
8697
- name: "forest",
8698
- displayName: "Forest",
8699
- hasLightMode: true,
8700
- hasDarkMode: true
8701
- },
8702
- {
8703
- name: "sunset",
8704
- displayName: "Sunset",
8705
- hasLightMode: true,
8706
- hasDarkMode: true
8707
- },
8708
- {
8709
- name: "lavender",
8710
- displayName: "Lavender",
8711
- hasLightMode: true,
8712
- hasDarkMode: true
8713
- },
8714
- {
8715
- name: "rose",
8716
- displayName: "Rose",
8717
- hasLightMode: true,
8718
- hasDarkMode: true
8719
- },
8720
- {
8721
- name: "slate",
8722
- displayName: "Slate",
8723
- hasLightMode: true,
8724
- hasDarkMode: true
8725
- },
8726
- {
8727
- name: "ember",
8728
- displayName: "Ember",
8729
- hasLightMode: true,
8730
- hasDarkMode: true
8731
- },
8732
- {
8733
- name: "midnight",
8734
- displayName: "Midnight",
8735
- hasLightMode: true,
8736
- hasDarkMode: true
8737
- },
8738
- {
8739
- name: "sand",
8740
- displayName: "Sand",
8741
- hasLightMode: true,
8742
- hasDarkMode: true
8743
- },
8744
- {
8745
- name: "neon",
8746
- displayName: "Neon",
8747
- hasLightMode: true,
8748
- hasDarkMode: true
8749
- },
8750
- {
8751
- name: "arctic",
8752
- displayName: "Arctic",
8753
- hasLightMode: true,
8754
- hasDarkMode: true
8755
- },
8756
- {
8757
- name: "copper",
8758
- displayName: "Copper",
8759
- hasLightMode: true,
8760
- hasDarkMode: true
8761
- },
8762
- // Layer 1 skin axes — truly-unique themes (compact tech / editorial / brutalist dense / display-heavy / touch-first)
8763
- {
8764
- name: "prism",
8765
- displayName: "Prism",
8766
- hasLightMode: true,
8767
- hasDarkMode: true
8768
- },
8769
- {
8770
- name: "gazette",
8771
- displayName: "Gazette",
8772
- hasLightMode: true,
8773
- hasDarkMode: true
8774
- },
8775
- {
8776
- name: "terminal",
8777
- displayName: "Terminal",
8778
- hasLightMode: true,
8779
- hasDarkMode: true
8780
- },
8781
- {
8782
- name: "atelier",
8783
- displayName: "Atelier",
8784
- hasLightMode: true,
8785
- hasDarkMode: true
8786
- },
8787
- {
8788
- name: "kiosk",
8789
- displayName: "Kiosk",
8790
- hasLightMode: true,
8791
- hasDarkMode: true
8792
- },
8793
- {
8794
- name: "linear-clean",
8795
- displayName: "Linear Clean",
8796
- hasLightMode: true,
8797
- hasDarkMode: true
8798
- },
8799
- {
8800
- name: "notion-editorial",
8801
- displayName: "Notion Editorial",
8802
- hasLightMode: true,
8803
- hasDarkMode: true
8804
- },
8805
- {
8806
- name: "bloomberg-dense",
8807
- displayName: "Bloomberg Dense",
8808
- hasLightMode: true,
8809
- hasDarkMode: true
8810
- }
8811
- ];
8812
- ThemeContext = createContext(void 0);
8813
- }
8814
- });
8815
8640
  var sizeClasses5, iconSizes2, ThemeToggle;
8816
8641
  var init_ThemeToggle = __esm({
8817
8642
  "components/core/atoms/ThemeToggle.tsx"() {
8818
8643
  "use client";
8819
8644
  init_Icon();
8820
8645
  init_cn();
8821
- init_ThemeContext();
8822
8646
  sizeClasses5 = {
8823
8647
  sm: "p-1.5",
8824
8648
  md: "p-2",
@@ -8913,7 +8737,7 @@ var Aside;
8913
8737
  var init_Aside = __esm({
8914
8738
  "components/core/atoms/Aside.tsx"() {
8915
8739
  init_cn();
8916
- Aside = React91__default.forwardRef(
8740
+ Aside = React90__default.forwardRef(
8917
8741
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
8918
8742
  );
8919
8743
  Aside.displayName = "Aside";
@@ -8991,8 +8815,8 @@ var init_LawReferenceTooltip = __esm({
8991
8815
  className
8992
8816
  }) => {
8993
8817
  const { t } = useTranslate();
8994
- const [isVisible, setIsVisible] = React91__default.useState(false);
8995
- const timeoutRef = React91__default.useRef(null);
8818
+ const [isVisible, setIsVisible] = React90__default.useState(false);
8819
+ const timeoutRef = React90__default.useRef(null);
8996
8820
  const handleMouseEnter = () => {
8997
8821
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
8998
8822
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -9001,7 +8825,7 @@ var init_LawReferenceTooltip = __esm({
9001
8825
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
9002
8826
  setIsVisible(false);
9003
8827
  };
9004
- React91__default.useEffect(() => {
8828
+ React90__default.useEffect(() => {
9005
8829
  return () => {
9006
8830
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
9007
8831
  };
@@ -9211,7 +9035,7 @@ var init_StatusDot = __esm({
9211
9035
  md: "w-2.5 h-2.5",
9212
9036
  lg: "w-3 h-3"
9213
9037
  };
9214
- StatusDot = React91__default.forwardRef(
9038
+ StatusDot = React90__default.forwardRef(
9215
9039
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
9216
9040
  return /* @__PURE__ */ jsx(
9217
9041
  "span",
@@ -9265,7 +9089,7 @@ var init_TrendIndicator = __esm({
9265
9089
  down: "trending-down",
9266
9090
  flat: "arrow-right"
9267
9091
  };
9268
- TrendIndicator = React91__default.forwardRef(
9092
+ TrendIndicator = React90__default.forwardRef(
9269
9093
  ({
9270
9094
  className,
9271
9095
  value,
@@ -9332,7 +9156,7 @@ var init_RangeSlider = __esm({
9332
9156
  md: "w-4 h-4",
9333
9157
  lg: "w-5 h-5"
9334
9158
  };
9335
- RangeSlider = React91__default.forwardRef(
9159
+ RangeSlider = React90__default.forwardRef(
9336
9160
  ({
9337
9161
  className,
9338
9162
  min = 0,
@@ -9840,7 +9664,7 @@ var init_ContentSection = __esm({
9840
9664
  md: "py-16",
9841
9665
  lg: "py-24"
9842
9666
  };
9843
- ContentSection = React91__default.forwardRef(
9667
+ ContentSection = React90__default.forwardRef(
9844
9668
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
9845
9669
  return /* @__PURE__ */ jsx(
9846
9670
  Box,
@@ -10374,7 +10198,7 @@ var init_AnimatedReveal = __esm({
10374
10198
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
10375
10199
  "none": {}
10376
10200
  };
10377
- AnimatedReveal = React91__default.forwardRef(
10201
+ AnimatedReveal = React90__default.forwardRef(
10378
10202
  ({
10379
10203
  trigger = "scroll",
10380
10204
  animation = "fade-up",
@@ -10534,7 +10358,7 @@ var init_AnimatedGraphic = __esm({
10534
10358
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
10535
10359
  "use client";
10536
10360
  init_cn();
10537
- AnimatedGraphic = React91__default.forwardRef(
10361
+ AnimatedGraphic = React90__default.forwardRef(
10538
10362
  ({
10539
10363
  src,
10540
10364
  svgContent,
@@ -10557,7 +10381,7 @@ var init_AnimatedGraphic = __esm({
10557
10381
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
10558
10382
  const resolvedSvg = svgContent ?? fetchedSvg;
10559
10383
  const prevAnimateRef = useRef(animate);
10560
- const setRef = React91__default.useCallback(
10384
+ const setRef = React90__default.useCallback(
10561
10385
  (node) => {
10562
10386
  containerRef.current = node;
10563
10387
  if (typeof ref === "function") ref(node);
@@ -10783,9 +10607,9 @@ function ScoreDisplay({
10783
10607
  ...rest
10784
10608
  }) {
10785
10609
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof rest.score === "number" && !Number.isNaN(rest.score) ? rest.score : 0;
10786
- const [displayValue, setDisplayValue] = React91.useState(resolvedValue);
10787
- const [isAnimating, setIsAnimating] = React91.useState(false);
10788
- React91.useEffect(() => {
10610
+ const [displayValue, setDisplayValue] = React90.useState(resolvedValue);
10611
+ const [isAnimating, setIsAnimating] = React90.useState(false);
10612
+ React90.useEffect(() => {
10789
10613
  if (!animated || displayValue === resolvedValue) {
10790
10614
  setDisplayValue(resolvedValue);
10791
10615
  return;
@@ -10868,9 +10692,9 @@ function ControlButton({
10868
10692
  className
10869
10693
  }) {
10870
10694
  const eventBus = useEventBus();
10871
- const [isPressed, setIsPressed] = React91.useState(false);
10695
+ const [isPressed, setIsPressed] = React90.useState(false);
10872
10696
  const actualPressed = pressed ?? isPressed;
10873
- const handlePointerDown = React91.useCallback(
10697
+ const handlePointerDown = React90.useCallback(
10874
10698
  (e) => {
10875
10699
  e.preventDefault();
10876
10700
  if (disabled) return;
@@ -10880,7 +10704,7 @@ function ControlButton({
10880
10704
  },
10881
10705
  [disabled, pressEvent, eventBus, onPress]
10882
10706
  );
10883
- const handlePointerUp = React91.useCallback(
10707
+ const handlePointerUp = React90.useCallback(
10884
10708
  (e) => {
10885
10709
  e.preventDefault();
10886
10710
  if (disabled) return;
@@ -10890,7 +10714,7 @@ function ControlButton({
10890
10714
  },
10891
10715
  [disabled, releaseEvent, eventBus, onRelease]
10892
10716
  );
10893
- const handlePointerLeave = React91.useCallback(
10717
+ const handlePointerLeave = React90.useCallback(
10894
10718
  (e) => {
10895
10719
  if (isPressed) {
10896
10720
  setIsPressed(false);
@@ -10968,6 +10792,52 @@ var init_ControlButton = __esm({
10968
10792
  ControlButton.displayName = "ControlButton";
10969
10793
  }
10970
10794
  });
10795
+
10796
+ // components/game/organisms/utils/spriteAnimation.ts
10797
+ function inferDirection(dx, dy) {
10798
+ if (dx === 0 && dy === 0) return "se";
10799
+ if (dx >= 0 && dy >= 0) return "se";
10800
+ if (dx <= 0 && dy >= 0) return "sw";
10801
+ if (dx >= 0 && dy <= 0) return "ne";
10802
+ return "nw";
10803
+ }
10804
+ function resolveSheetDirection(facing) {
10805
+ switch (facing) {
10806
+ case "se":
10807
+ return { sheetDir: "se", flipX: false };
10808
+ case "sw":
10809
+ return { sheetDir: "sw", flipX: false };
10810
+ case "ne":
10811
+ return { sheetDir: "sw", flipX: true };
10812
+ case "nw":
10813
+ return { sheetDir: "se", flipX: true };
10814
+ }
10815
+ }
10816
+ function frameRect(frame, row, columns, frameWidth, frameHeight) {
10817
+ return {
10818
+ sx: frame % columns * frameWidth,
10819
+ sy: row * frameHeight,
10820
+ sw: frameWidth,
10821
+ sh: frameHeight
10822
+ };
10823
+ }
10824
+ function getCurrentFrameFromDef(def, elapsed) {
10825
+ const frameDuration = 1e3 / def.frameRate;
10826
+ const totalDuration = def.frames * frameDuration;
10827
+ if (def.loop) {
10828
+ const frame2 = Math.floor(elapsed % totalDuration / frameDuration);
10829
+ return { frame: frame2, finished: false };
10830
+ }
10831
+ if (elapsed >= totalDuration) {
10832
+ return { frame: def.frames - 1, finished: true };
10833
+ }
10834
+ const frame = Math.floor(elapsed / frameDuration);
10835
+ return { frame, finished: false };
10836
+ }
10837
+ var init_spriteAnimation = __esm({
10838
+ "components/game/organisms/utils/spriteAnimation.ts"() {
10839
+ }
10840
+ });
10971
10841
  function Sprite({
10972
10842
  spritesheet = "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
10973
10843
  frameWidth = 64,
@@ -10988,12 +10858,8 @@ function Sprite({
10988
10858
  }) {
10989
10859
  const eventBus = useEventBus();
10990
10860
  const sourcePosition = useMemo(() => {
10991
- const frameX = frame % columns;
10992
- const frameY = Math.floor(frame / columns);
10993
- return {
10994
- x: frameX * frameWidth,
10995
- y: frameY * frameHeight
10996
- };
10861
+ const { sx, sy } = frameRect(frame, Math.floor(frame / columns), columns, frameWidth, frameHeight);
10862
+ return { x: sx, y: sy };
10997
10863
  }, [frame, columns, frameWidth, frameHeight]);
10998
10864
  const transform = useMemo(() => {
10999
10865
  const transforms = [
@@ -11041,6 +10907,7 @@ var init_Sprite = __esm({
11041
10907
  "components/game/atoms/Sprite.tsx"() {
11042
10908
  "use client";
11043
10909
  init_useEventBus();
10910
+ init_spriteAnimation();
11044
10911
  }
11045
10912
  });
11046
10913
  function StateIndicator({
@@ -11468,8 +11335,8 @@ function XPBar({
11468
11335
  }) {
11469
11336
  const sizes = sizeMap9[size];
11470
11337
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
11471
- const [fillWidth, setFillWidth] = React91.useState(animated ? 0 : percentage);
11472
- React91.useEffect(() => {
11338
+ const [fillWidth, setFillWidth] = React90.useState(animated ? 0 : percentage);
11339
+ React90.useEffect(() => {
11473
11340
  if (!animated) {
11474
11341
  setFillWidth(percentage);
11475
11342
  return;
@@ -11957,9 +11824,9 @@ function MiniMap({
11957
11824
  viewportRect = DEFAULT_VIEWPORT,
11958
11825
  className
11959
11826
  }) {
11960
- const canvasRef = React91.useRef(null);
11961
- const frameRef = React91.useRef(0);
11962
- React91.useEffect(() => {
11827
+ const canvasRef = React90.useRef(null);
11828
+ const frameRef = React90.useRef(0);
11829
+ React90.useEffect(() => {
11963
11830
  const canvas = canvasRef.current;
11964
11831
  if (!canvas) return;
11965
11832
  const ctx = canvas.getContext("2d");
@@ -12148,7 +12015,7 @@ var init_ErrorBoundary = __esm({
12148
12015
  }
12149
12016
  );
12150
12017
  };
12151
- ErrorBoundary = class extends React91__default.Component {
12018
+ ErrorBoundary = class extends React90__default.Component {
12152
12019
  constructor(props) {
12153
12020
  super(props);
12154
12021
  __publicField(this, "reset", () => {
@@ -13183,8 +13050,8 @@ function ActionButtons({
13183
13050
  disabled
13184
13051
  }) {
13185
13052
  const eventBus = useEventBus();
13186
- const [activeButtons, setActiveButtons] = React91.useState(/* @__PURE__ */ new Set());
13187
- const handlePress = React91.useCallback(
13053
+ const [activeButtons, setActiveButtons] = React90.useState(/* @__PURE__ */ new Set());
13054
+ const handlePress = React90.useCallback(
13188
13055
  (id) => {
13189
13056
  setActiveButtons((prev) => new Set(prev).add(id));
13190
13057
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -13192,7 +13059,7 @@ function ActionButtons({
13192
13059
  },
13193
13060
  [actionEvent, eventBus, onAction]
13194
13061
  );
13195
- const handleRelease = React91.useCallback(
13062
+ const handleRelease = React90.useCallback(
13196
13063
  (id) => {
13197
13064
  setActiveButtons((prev) => {
13198
13065
  const next = new Set(prev);
@@ -14104,7 +13971,7 @@ function recordTransition(trace) {
14104
13971
  ...trace,
14105
13972
  id: `t-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
14106
13973
  };
14107
- log5.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
13974
+ log4.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
14108
13975
  getState().transitions.push(entry);
14109
13976
  if (getState().transitions.length > MAX_TRANSITIONS) {
14110
13977
  getState().transitions.shift();
@@ -14203,7 +14070,7 @@ function getTraitSnapshots() {
14203
14070
  try {
14204
14071
  snapshots.push(getter());
14205
14072
  } catch (err) {
14206
- log5.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
14073
+ log4.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
14207
14074
  }
14208
14075
  }
14209
14076
  return snapshots;
@@ -14302,10 +14169,10 @@ function updateAssetStatus(url, status) {
14302
14169
  window.__orbitalVerification.assetStatus[url] = status;
14303
14170
  }
14304
14171
  }
14305
- var log5, MAX_TRANSITIONS;
14172
+ var log4, MAX_TRANSITIONS;
14306
14173
  var init_verificationRegistry = __esm({
14307
14174
  "lib/verificationRegistry.ts"() {
14308
- log5 = createLogger("almadar:bridge");
14175
+ log4 = createLogger("almadar:bridge");
14309
14176
  MAX_TRANSITIONS = 500;
14310
14177
  exposeOnWindow();
14311
14178
  }
@@ -14432,6 +14299,163 @@ var init_useCamera = __esm({
14432
14299
  "use client";
14433
14300
  }
14434
14301
  });
14302
+ function unitAtlasUrl(unit) {
14303
+ if (unit.spriteSheet) return unit.spriteSheet;
14304
+ const sprite = unit.sprite;
14305
+ if (!sprite) return null;
14306
+ const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
14307
+ if (!match) return null;
14308
+ return `${match[1]}.json`;
14309
+ }
14310
+ function resolveSheetUrl(atlasUrl, relativeSheetPath) {
14311
+ try {
14312
+ return new URL(relativeSheetPath, atlasUrl).toString();
14313
+ } catch {
14314
+ const base = atlasUrl.slice(0, atlasUrl.lastIndexOf("/") + 1);
14315
+ return `${base}${relativeSheetPath.replace(/^\.\//, "")}`;
14316
+ }
14317
+ }
14318
+ function useUnitSpriteAtlas(units) {
14319
+ const atlasCacheRef = useRef(/* @__PURE__ */ new Map());
14320
+ const loadingRef = useRef(/* @__PURE__ */ new Set());
14321
+ const [pendingCount, setPendingCount] = useState(0);
14322
+ const [, forceTick] = useState(0);
14323
+ const animStatesRef = useRef(/* @__PURE__ */ new Map());
14324
+ const lastTickRef = useRef(0);
14325
+ const rafRef = useRef(0);
14326
+ const atlasUrls = useMemo(() => {
14327
+ const set = /* @__PURE__ */ new Set();
14328
+ for (const unit of units) {
14329
+ const url = unitAtlasUrl(unit);
14330
+ if (url) set.add(url);
14331
+ }
14332
+ return [...set];
14333
+ }, [units]);
14334
+ useEffect(() => {
14335
+ const cache = atlasCacheRef.current;
14336
+ const loading = loadingRef.current;
14337
+ const toLoad = atlasUrls.filter((url) => !cache.has(url) && !loading.has(url));
14338
+ if (toLoad.length === 0) return;
14339
+ let cancelled = false;
14340
+ setPendingCount((prev) => prev + toLoad.length);
14341
+ for (const url of toLoad) {
14342
+ loading.add(url);
14343
+ fetch(url).then((res) => res.ok ? res.json() : Promise.reject(new Error(String(res.status)))).then((atlas) => {
14344
+ if (cancelled) return;
14345
+ cache.set(url, atlas);
14346
+ }).catch(() => {
14347
+ }).finally(() => {
14348
+ if (cancelled) return;
14349
+ loading.delete(url);
14350
+ setPendingCount((prev) => Math.max(0, prev - 1));
14351
+ forceTick((n) => n + 1);
14352
+ });
14353
+ }
14354
+ return () => {
14355
+ cancelled = true;
14356
+ };
14357
+ }, [atlasUrls]);
14358
+ const sheetUrls = useMemo(() => {
14359
+ const urls = /* @__PURE__ */ new Set();
14360
+ for (const unit of units) {
14361
+ const atlasUrl = unitAtlasUrl(unit);
14362
+ if (!atlasUrl) continue;
14363
+ const atlas = atlasCacheRef.current.get(atlasUrl);
14364
+ if (!atlas) continue;
14365
+ for (const rel of Object.values(atlas.sheets)) {
14366
+ if (rel) urls.add(resolveSheetUrl(atlasUrl, rel));
14367
+ }
14368
+ }
14369
+ return [...urls];
14370
+ }, [units, pendingCount]);
14371
+ useEffect(() => {
14372
+ const hasAtlasUnits = units.some((u) => unitAtlasUrl(u) !== null);
14373
+ if (!hasAtlasUnits) return;
14374
+ let running = true;
14375
+ const tick = (ts) => {
14376
+ if (!running) return;
14377
+ const last = lastTickRef.current || ts;
14378
+ const delta = ts - last;
14379
+ lastTickRef.current = ts;
14380
+ const states = animStatesRef.current;
14381
+ const currentIds = /* @__PURE__ */ new Set();
14382
+ for (const unit of units) {
14383
+ if (unitAtlasUrl(unit) === null) continue;
14384
+ currentIds.add(unit.id);
14385
+ let state = states.get(unit.id);
14386
+ if (!state) {
14387
+ state = { animation: "idle", direction: "se", elapsed: 0, walkHold: 0, prev: null };
14388
+ states.set(unit.id, state);
14389
+ }
14390
+ const posX = unit.position?.x ?? unit.x ?? 0;
14391
+ const posY = unit.position?.y ?? unit.y ?? 0;
14392
+ if (state.prev) {
14393
+ const dx = posX - state.prev.x;
14394
+ const dy = posY - state.prev.y;
14395
+ if (dx !== 0 || dy !== 0) {
14396
+ state.animation = "walk";
14397
+ state.direction = inferDirection(dx, dy);
14398
+ state.walkHold = WALK_HOLD_MS;
14399
+ } else if (state.animation === "walk") {
14400
+ state.walkHold -= delta;
14401
+ if (state.walkHold <= 0) state.animation = "idle";
14402
+ }
14403
+ }
14404
+ state.prev = { x: posX, y: posY };
14405
+ state.elapsed += delta;
14406
+ }
14407
+ for (const id of states.keys()) {
14408
+ if (!currentIds.has(id)) states.delete(id);
14409
+ }
14410
+ rafRef.current = requestAnimationFrame(tick);
14411
+ };
14412
+ rafRef.current = requestAnimationFrame(tick);
14413
+ return () => {
14414
+ running = false;
14415
+ cancelAnimationFrame(rafRef.current);
14416
+ lastTickRef.current = 0;
14417
+ };
14418
+ }, [units]);
14419
+ const resolveUnitFrame = useCallback((unitId) => {
14420
+ const unit = units.find((u) => u.id === unitId);
14421
+ if (!unit) return null;
14422
+ const atlasUrl = unitAtlasUrl(unit);
14423
+ if (!atlasUrl) return null;
14424
+ const atlas = atlasCacheRef.current.get(atlasUrl);
14425
+ if (!atlas) return null;
14426
+ const state = animStatesRef.current.get(unitId);
14427
+ const animation = state?.animation ?? "idle";
14428
+ const direction = state?.direction ?? "se";
14429
+ const elapsed = state?.elapsed ?? 0;
14430
+ const def = atlas.animations[animation] ?? atlas.animations.idle;
14431
+ if (!def) return null;
14432
+ const { sheetDir, flipX } = resolveSheetDirection(direction);
14433
+ const rel = atlas.sheets[sheetDir] ?? atlas.sheets.se ?? atlas.sheets.sw;
14434
+ if (!rel) return null;
14435
+ const sheetUrl = resolveSheetUrl(atlasUrl, rel);
14436
+ const isIdle = animation === "idle";
14437
+ const frame = isIdle ? 0 : getCurrentFrameFromDef(def, elapsed).frame;
14438
+ const rect = frameRect(frame, def.row, atlas.columns, atlas.frameWidth, atlas.frameHeight);
14439
+ return {
14440
+ sheetUrl,
14441
+ sx: rect.sx,
14442
+ sy: rect.sy,
14443
+ sw: rect.sw,
14444
+ sh: rect.sh,
14445
+ flipX,
14446
+ applyBreathing: isIdle
14447
+ };
14448
+ }, [units]);
14449
+ return { sheetUrls, resolveUnitFrame, pendingCount };
14450
+ }
14451
+ var WALK_HOLD_MS;
14452
+ var init_useUnitSpriteAtlas = __esm({
14453
+ "components/game/molecules/useUnitSpriteAtlas.ts"() {
14454
+ "use client";
14455
+ init_spriteAnimation();
14456
+ WALK_HOLD_MS = 600;
14457
+ }
14458
+ });
14435
14459
 
14436
14460
  // components/game/organisms/utils/isometric.ts
14437
14461
  function isoToScreen(tileX, tileY, scale, baseOffsetX) {
@@ -14546,6 +14570,10 @@ function IsometricCanvas({
14546
14570
  () => unitsProp.map((u) => u.position ? u : { ...u, position: { x: u.x ?? 0, y: u.y ?? 0 } }),
14547
14571
  [unitsProp]
14548
14572
  );
14573
+ const { sheetUrls: atlasSheetUrls, resolveUnitFrame: resolveUnitFrameInternal, pendingCount: atlasPending } = useUnitSpriteAtlas(units);
14574
+ const resolveFrameForUnit = useCallback((unitId) => {
14575
+ return resolveUnitFrame?.(unitId) ?? resolveUnitFrameInternal(unitId);
14576
+ }, [resolveUnitFrame, resolveUnitFrameInternal]);
14549
14577
  const features = useMemo(
14550
14578
  () => featuresProp.map((f3) => {
14551
14579
  if (f3.type) return f3;
@@ -14629,9 +14657,10 @@ function IsometricCanvas({
14629
14657
  }
14630
14658
  }
14631
14659
  if (effectSpriteUrls) urls.push(...effectSpriteUrls);
14660
+ if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
14632
14661
  if (backgroundImage) urls.push(backgroundImage);
14633
14662
  return [...new Set(urls.filter(Boolean))];
14634
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, backgroundImage, assetManifest, resolveManifestUrl]);
14663
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl]);
14635
14664
  const { getImage, pendingCount } = useImageCache(spriteUrls);
14636
14665
  useEffect(() => {
14637
14666
  if (typeof window === "undefined") return;
@@ -14918,7 +14947,7 @@ function IsometricCanvas({
14918
14947
  ctx.lineWidth = 3;
14919
14948
  ctx.stroke();
14920
14949
  }
14921
- const frame = resolveUnitFrame?.(unit.id) ?? null;
14950
+ const frame = resolveFrameForUnit(unit.id);
14922
14951
  const frameImg = frame ? getImage(frame.sheetUrl) : null;
14923
14952
  if (frame && frameImg) {
14924
14953
  const frameAr = frame.sw / frame.sh;
@@ -15028,7 +15057,7 @@ function IsometricCanvas({
15028
15057
  resolveTerrainSpriteUrl,
15029
15058
  resolveFeatureSpriteUrl,
15030
15059
  resolveUnitSpriteUrl,
15031
- resolveUnitFrame,
15060
+ resolveFrameForUnit,
15032
15061
  getImage,
15033
15062
  gridWidth,
15034
15063
  gridHeight,
@@ -15060,7 +15089,7 @@ function IsometricCanvas({
15060
15089
  };
15061
15090
  }, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
15062
15091
  useEffect(() => {
15063
- const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0;
15092
+ const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
15064
15093
  draw(animTimeRef.current);
15065
15094
  if (!hasAnimations) return;
15066
15095
  let running = true;
@@ -15076,7 +15105,7 @@ function IsometricCanvas({
15076
15105
  running = false;
15077
15106
  cancelAnimationFrame(rafIdRef.current);
15078
15107
  };
15079
- }, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, lerpToTarget, targetCameraRef]);
15108
+ }, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, atlasPending, lerpToTarget, targetCameraRef]);
15080
15109
  const handleMouseMoveWithCamera = useCallback((e) => {
15081
15110
  if (enableCamera) {
15082
15111
  const wasPanning = handleMouseMove(e, () => draw(animTimeRef.current));
@@ -15221,6 +15250,7 @@ var init_IsometricCanvas = __esm({
15221
15250
  init_ErrorState();
15222
15251
  init_useImageCache();
15223
15252
  init_useCamera();
15253
+ init_useUnitSpriteAtlas();
15224
15254
  init_verificationRegistry();
15225
15255
  init_isometric();
15226
15256
  IsometricCanvas.displayName = "IsometricCanvas";
@@ -16038,7 +16068,7 @@ function generateDiff(oldVal, newVal) {
16038
16068
  }
16039
16069
  return diff;
16040
16070
  }
16041
- var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log6, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
16071
+ var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log5, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
16042
16072
  var init_CodeBlock = __esm({
16043
16073
  "components/core/molecules/markdown/CodeBlock.tsx"() {
16044
16074
  init_cn();
@@ -16121,7 +16151,7 @@ var init_CodeBlock = __esm({
16121
16151
  "lolo-op-async": { color: ORB_COLORS.dark.async }
16122
16152
  };
16123
16153
  loloStyle = { ...dark, ...loloStyleOverrides };
16124
- log6 = createLogger("almadar:ui:markdown-code");
16154
+ log5 = createLogger("almadar:ui:markdown-code");
16125
16155
  CODE_LANGUAGES = [
16126
16156
  "text",
16127
16157
  "json",
@@ -16160,7 +16190,7 @@ var init_CodeBlock = __esm({
16160
16190
  };
16161
16191
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
16162
16192
  HIDDEN_LINE_NUMBERS = { display: "none" };
16163
- CodeBlock = React91__default.memo(
16193
+ CodeBlock = React90__default.memo(
16164
16194
  ({
16165
16195
  code: rawCode,
16166
16196
  language = "text",
@@ -16385,7 +16415,7 @@ var init_CodeBlock = __esm({
16385
16415
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: true });
16386
16416
  setTimeout(() => setCopied(false), 2e3);
16387
16417
  } catch (err) {
16388
- log6.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
16418
+ log5.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
16389
16419
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: false });
16390
16420
  }
16391
16421
  };
@@ -16747,7 +16777,7 @@ var init_MarkdownContent = __esm({
16747
16777
  init_Box();
16748
16778
  init_CodeBlock();
16749
16779
  init_cn();
16750
- MarkdownContent = React91__default.memo(
16780
+ MarkdownContent = React90__default.memo(
16751
16781
  ({ content, direction = "ltr", className }) => {
16752
16782
  const { t: _t } = useTranslate();
16753
16783
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -18064,7 +18094,7 @@ var init_StateMachineView = __esm({
18064
18094
  style: { top: title ? 30 : 0 },
18065
18095
  children: [
18066
18096
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
18067
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React91__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
18097
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React90__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
18068
18098
  StateNode,
18069
18099
  {
18070
18100
  state,
@@ -20266,14 +20296,14 @@ function useSafeEventBus2() {
20266
20296
  } };
20267
20297
  }
20268
20298
  }
20269
- var log7, lookStyles4, ButtonGroup;
20299
+ var log6, lookStyles4, ButtonGroup;
20270
20300
  var init_ButtonGroup = __esm({
20271
20301
  "components/core/molecules/ButtonGroup.tsx"() {
20272
20302
  "use client";
20273
20303
  init_cn();
20274
20304
  init_atoms2();
20275
20305
  init_useEventBus();
20276
- log7 = createLogger("almadar:ui:button-group");
20306
+ log6 = createLogger("almadar:ui:button-group");
20277
20307
  lookStyles4 = {
20278
20308
  "right-aligned-buttons": "",
20279
20309
  "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
@@ -20354,7 +20384,7 @@ var init_ButtonGroup = __esm({
20354
20384
  {
20355
20385
  variant: "ghost",
20356
20386
  onClick: () => {
20357
- log7.debug("Filter clicked", { field: filter.field });
20387
+ log6.debug("Filter clicked", { field: filter.field });
20358
20388
  },
20359
20389
  children: filter.label
20360
20390
  },
@@ -24605,7 +24635,7 @@ function CraftingRecipe({
24605
24635
  className
24606
24636
  }) {
24607
24637
  const eventBus = useEventBus();
24608
- const handleCraft = React91.useCallback(() => {
24638
+ const handleCraft = React90.useCallback(() => {
24609
24639
  onCraft?.();
24610
24640
  if (craftEvent) {
24611
24641
  eventBus.emit(craftEvent, { output: output.label });
@@ -24622,7 +24652,7 @@ function CraftingRecipe({
24622
24652
  children: [
24623
24653
  /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap items-center", children: inputs.map((ingredient, index) => {
24624
24654
  const hasSufficient = ingredient.available >= ingredient.required;
24625
- return /* @__PURE__ */ jsxs(React91.Fragment, { children: [
24655
+ return /* @__PURE__ */ jsxs(React90.Fragment, { children: [
24626
24656
  /* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
24627
24657
  ItemSlot,
24628
24658
  {
@@ -24694,8 +24724,8 @@ function DPad({
24694
24724
  }) {
24695
24725
  const eventBus = useEventBus();
24696
24726
  const sizes = sizeMap15[size];
24697
- const [activeDirections, setActiveDirections] = React91.useState(/* @__PURE__ */ new Set());
24698
- const handlePress = React91.useCallback(
24727
+ const [activeDirections, setActiveDirections] = React90.useState(/* @__PURE__ */ new Set());
24728
+ const handlePress = React90.useCallback(
24699
24729
  (direction) => {
24700
24730
  setActiveDirections((prev) => new Set(prev).add(direction));
24701
24731
  if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
@@ -24703,7 +24733,7 @@ function DPad({
24703
24733
  },
24704
24734
  [directionEvent, eventBus, onDirection]
24705
24735
  );
24706
- const handleRelease = React91.useCallback(
24736
+ const handleRelease = React90.useCallback(
24707
24737
  (direction) => {
24708
24738
  setActiveDirections((prev) => {
24709
24739
  const next = new Set(prev);
@@ -25510,8 +25540,8 @@ var init_Menu = __esm({
25510
25540
  "bottom-end": "bottom-start"
25511
25541
  };
25512
25542
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
25513
- const triggerChild = React91__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
25514
- const triggerElement = React91__default.cloneElement(
25543
+ const triggerChild = React90__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
25544
+ const triggerElement = React90__default.cloneElement(
25515
25545
  triggerChild,
25516
25546
  {
25517
25547
  ref: triggerRef,
@@ -25645,14 +25675,14 @@ function useDataDnd(args) {
25645
25675
  const isZone = Boolean(dragGroup || accepts || sortable);
25646
25676
  const enabled = isZone || Boolean(dndRoot);
25647
25677
  const eventBus = useEventBus();
25648
- const parentRoot = React91__default.useContext(RootCtx);
25678
+ const parentRoot = React90__default.useContext(RootCtx);
25649
25679
  const isRoot = enabled && parentRoot === null;
25650
- const zoneId = React91__default.useId();
25680
+ const zoneId = React90__default.useId();
25651
25681
  const ownGroup = dragGroup ?? accepts ?? zoneId;
25652
- const [optimisticOrders, setOptimisticOrders] = React91__default.useState(() => /* @__PURE__ */ new Map());
25653
- const optimisticOrdersRef = React91__default.useRef(optimisticOrders);
25682
+ const [optimisticOrders, setOptimisticOrders] = React90__default.useState(() => /* @__PURE__ */ new Map());
25683
+ const optimisticOrdersRef = React90__default.useRef(optimisticOrders);
25654
25684
  optimisticOrdersRef.current = optimisticOrders;
25655
- const clearOptimisticOrder = React91__default.useCallback((group) => {
25685
+ const clearOptimisticOrder = React90__default.useCallback((group) => {
25656
25686
  setOptimisticOrders((prev) => {
25657
25687
  if (!prev.has(group)) return prev;
25658
25688
  const next = new Map(prev);
@@ -25677,7 +25707,7 @@ function useDataDnd(args) {
25677
25707
  const raw = it[dndItemIdField];
25678
25708
  return String(raw ?? `__idx_${idx}`);
25679
25709
  }).join("|");
25680
- const itemIds = React91__default.useMemo(
25710
+ const itemIds = React90__default.useMemo(
25681
25711
  () => orderedItems.map((it, idx) => {
25682
25712
  const raw = it[dndItemIdField];
25683
25713
  return raw ?? `__idx_${idx}`;
@@ -25685,7 +25715,7 @@ function useDataDnd(args) {
25685
25715
  [itemIdsSignature]
25686
25716
  );
25687
25717
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
25688
- React91__default.useEffect(() => {
25718
+ React90__default.useEffect(() => {
25689
25719
  const root = isRoot ? null : parentRoot;
25690
25720
  if (root) {
25691
25721
  root.clearOptimisticOrder(ownGroup);
@@ -25693,20 +25723,20 @@ function useDataDnd(args) {
25693
25723
  clearOptimisticOrder(ownGroup);
25694
25724
  }
25695
25725
  }, [itemsContentSig, ownGroup]);
25696
- const zonesRef = React91__default.useRef(/* @__PURE__ */ new Map());
25697
- const registerZone = React91__default.useCallback((zoneId2, meta2) => {
25726
+ const zonesRef = React90__default.useRef(/* @__PURE__ */ new Map());
25727
+ const registerZone = React90__default.useCallback((zoneId2, meta2) => {
25698
25728
  zonesRef.current.set(zoneId2, meta2);
25699
25729
  }, []);
25700
- const unregisterZone = React91__default.useCallback((zoneId2) => {
25730
+ const unregisterZone = React90__default.useCallback((zoneId2) => {
25701
25731
  zonesRef.current.delete(zoneId2);
25702
25732
  }, []);
25703
- const [activeDrag, setActiveDrag] = React91__default.useState(null);
25704
- const [overZoneGroup, setOverZoneGroup] = React91__default.useState(null);
25705
- const meta = React91__default.useMemo(
25733
+ const [activeDrag, setActiveDrag] = React90__default.useState(null);
25734
+ const [overZoneGroup, setOverZoneGroup] = React90__default.useState(null);
25735
+ const meta = React90__default.useMemo(
25706
25736
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
25707
25737
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
25708
25738
  );
25709
- React91__default.useEffect(() => {
25739
+ React90__default.useEffect(() => {
25710
25740
  const target = isRoot ? null : parentRoot;
25711
25741
  if (!target) {
25712
25742
  zonesRef.current.set(zoneId, meta);
@@ -25725,7 +25755,7 @@ function useDataDnd(args) {
25725
25755
  }, [parentRoot, isRoot, zoneId, meta]);
25726
25756
  const sensors = useAlmadarDndSensors(true);
25727
25757
  const collisionDetection = almadarDndCollisionDetection;
25728
- const findZoneByItem = React91__default.useCallback(
25758
+ const findZoneByItem = React90__default.useCallback(
25729
25759
  (id) => {
25730
25760
  for (const z of zonesRef.current.values()) {
25731
25761
  if (z.itemIds.includes(id)) return z;
@@ -25734,7 +25764,7 @@ function useDataDnd(args) {
25734
25764
  },
25735
25765
  []
25736
25766
  );
25737
- React91__default.useCallback(
25767
+ React90__default.useCallback(
25738
25768
  (group) => {
25739
25769
  for (const z of zonesRef.current.values()) {
25740
25770
  if (z.group === group) return z;
@@ -25743,7 +25773,7 @@ function useDataDnd(args) {
25743
25773
  },
25744
25774
  []
25745
25775
  );
25746
- const handleDragEnd = React91__default.useCallback(
25776
+ const handleDragEnd = React90__default.useCallback(
25747
25777
  (event) => {
25748
25778
  const { active, over } = event;
25749
25779
  const activeIdStr = String(active.id);
@@ -25834,8 +25864,8 @@ function useDataDnd(args) {
25834
25864
  },
25835
25865
  [eventBus]
25836
25866
  );
25837
- const sortableData = React91__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
25838
- const SortableItem = React91__default.useCallback(
25867
+ const sortableData = React90__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
25868
+ const SortableItem = React90__default.useCallback(
25839
25869
  ({ id, children }) => {
25840
25870
  const {
25841
25871
  attributes,
@@ -25875,7 +25905,7 @@ function useDataDnd(args) {
25875
25905
  id: droppableId,
25876
25906
  data: sortableData
25877
25907
  });
25878
- const ctx = React91__default.useContext(RootCtx);
25908
+ const ctx = React90__default.useContext(RootCtx);
25879
25909
  const activeDrag2 = ctx?.activeDrag ?? null;
25880
25910
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
25881
25911
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -25890,7 +25920,7 @@ function useDataDnd(args) {
25890
25920
  showForeignPlaceholder,
25891
25921
  ctxAvailable: ctx != null
25892
25922
  });
25893
- React91__default.useEffect(() => {
25923
+ React90__default.useEffect(() => {
25894
25924
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
25895
25925
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
25896
25926
  return /* @__PURE__ */ jsx(
@@ -25904,11 +25934,11 @@ function useDataDnd(args) {
25904
25934
  }
25905
25935
  );
25906
25936
  };
25907
- const rootContextValue = React91__default.useMemo(
25937
+ const rootContextValue = React90__default.useMemo(
25908
25938
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
25909
25939
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
25910
25940
  );
25911
- const handleDragStart = React91__default.useCallback((event) => {
25941
+ const handleDragStart = React90__default.useCallback((event) => {
25912
25942
  const sourceZone = findZoneByItem(event.active.id);
25913
25943
  const rect = event.active.rect.current.initial;
25914
25944
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -25927,7 +25957,7 @@ function useDataDnd(args) {
25927
25957
  isRoot
25928
25958
  });
25929
25959
  }, [findZoneByItem, isRoot, zoneId]);
25930
- const handleDragOver = React91__default.useCallback((event) => {
25960
+ const handleDragOver = React90__default.useCallback((event) => {
25931
25961
  const { active, over } = event;
25932
25962
  const overData = over?.data?.current;
25933
25963
  const overGroup = overData?.dndGroup ?? null;
@@ -25997,7 +26027,7 @@ function useDataDnd(args) {
25997
26027
  return next;
25998
26028
  });
25999
26029
  }, []);
26000
- const handleDragCancel = React91__default.useCallback((event) => {
26030
+ const handleDragCancel = React90__default.useCallback((event) => {
26001
26031
  setActiveDrag(null);
26002
26032
  setOverZoneGroup(null);
26003
26033
  dndLog.warn("dragCancel", {
@@ -26005,12 +26035,12 @@ function useDataDnd(args) {
26005
26035
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
26006
26036
  });
26007
26037
  }, []);
26008
- const handleDragEndWithCleanup = React91__default.useCallback((event) => {
26038
+ const handleDragEndWithCleanup = React90__default.useCallback((event) => {
26009
26039
  handleDragEnd(event);
26010
26040
  setActiveDrag(null);
26011
26041
  setOverZoneGroup(null);
26012
26042
  }, [handleDragEnd]);
26013
- const wrapContainer = React91__default.useCallback(
26043
+ const wrapContainer = React90__default.useCallback(
26014
26044
  (children) => {
26015
26045
  if (!enabled) return children;
26016
26046
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -26064,7 +26094,7 @@ var init_useDataDnd = __esm({
26064
26094
  init_useAlmadarDndCollision();
26065
26095
  init_Box();
26066
26096
  dndLog = createLogger("almadar:ui:dnd");
26067
- RootCtx = React91__default.createContext(null);
26097
+ RootCtx = React90__default.createContext(null);
26068
26098
  }
26069
26099
  });
26070
26100
  function renderIconInput(icon, props) {
@@ -26590,7 +26620,7 @@ function DataList({
26590
26620
  }) {
26591
26621
  const eventBus = useEventBus();
26592
26622
  const { t } = useTranslate();
26593
- const [visibleCount, setVisibleCount] = React91__default.useState(pageSize || Infinity);
26623
+ const [visibleCount, setVisibleCount] = React90__default.useState(pageSize || Infinity);
26594
26624
  const fieldDefs = fields ?? columns ?? [];
26595
26625
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
26596
26626
  const dnd = useDataDnd({
@@ -26609,7 +26639,7 @@ function DataList({
26609
26639
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
26610
26640
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
26611
26641
  const hasRenderProp = typeof children === "function";
26612
- React91__default.useEffect(() => {
26642
+ React90__default.useEffect(() => {
26613
26643
  const renderItemTypeOf = typeof schemaRenderItem;
26614
26644
  const childrenTypeOf = typeof children;
26615
26645
  if (data.length > 0 && !hasRenderProp) {
@@ -26714,7 +26744,7 @@ function DataList({
26714
26744
  const items2 = data.map((item) => item);
26715
26745
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
26716
26746
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
26717
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
26747
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
26718
26748
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
26719
26749
  group.items.map((itemData, index) => {
26720
26750
  const id = itemData.id || `${gi}-${index}`;
@@ -26855,7 +26885,7 @@ function DataList({
26855
26885
  className
26856
26886
  ),
26857
26887
  children: [
26858
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
26888
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
26859
26889
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
26860
26890
  group.items.map(
26861
26891
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -27771,7 +27801,7 @@ var init_Grid = __esm({
27771
27801
  as: Component2 = "div"
27772
27802
  }) => {
27773
27803
  const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
27774
- return React91__default.createElement(
27804
+ return React90__default.createElement(
27775
27805
  Component2,
27776
27806
  {
27777
27807
  className: cn(
@@ -27959,8 +27989,8 @@ var init_Popover = __esm({
27959
27989
  onMouseEnter: handleOpen,
27960
27990
  onMouseLeave: handleClose
27961
27991
  };
27962
- const childElement = React91__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
27963
- const triggerElement = React91__default.cloneElement(
27992
+ const childElement = React90__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
27993
+ const triggerElement = React90__default.cloneElement(
27964
27994
  childElement,
27965
27995
  {
27966
27996
  ref: triggerRef,
@@ -28016,9 +28046,9 @@ function debug(...args) {
28016
28046
  const [first, ...rest] = args;
28017
28047
  const message = typeof first === "string" ? first : "<debug>";
28018
28048
  if (rest.length === 0 && typeof first === "string") {
28019
- log8.debug(message);
28049
+ log7.debug(message);
28020
28050
  } else {
28021
- log8.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
28051
+ log7.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
28022
28052
  }
28023
28053
  }
28024
28054
  function debugGroup(label) {
@@ -28046,11 +28076,11 @@ function toLogMetaValue(v) {
28046
28076
  }
28047
28077
  return String(v);
28048
28078
  }
28049
- var NAMESPACE, log8;
28079
+ var NAMESPACE, log7;
28050
28080
  var init_debug = __esm({
28051
28081
  "lib/debug.ts"() {
28052
28082
  NAMESPACE = "almadar:ui:debug";
28053
- log8 = createLogger(NAMESPACE);
28083
+ log7 = createLogger(NAMESPACE);
28054
28084
  createLogger("almadar:ui:debug:input");
28055
28085
  createLogger("almadar:ui:debug:collision");
28056
28086
  createLogger("almadar:ui:debug:physics");
@@ -28550,8 +28580,8 @@ var init_Tooltip = __esm({
28550
28580
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
28551
28581
  };
28552
28582
  }, []);
28553
- const triggerElement = React91__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
28554
- const trigger = React91__default.cloneElement(triggerElement, {
28583
+ const triggerElement = React90__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
28584
+ const trigger = React90__default.cloneElement(triggerElement, {
28555
28585
  ref: triggerRef,
28556
28586
  onMouseEnter: handleMouseEnter,
28557
28587
  onMouseLeave: handleMouseLeave,
@@ -28637,7 +28667,7 @@ var init_WizardProgress = __esm({
28637
28667
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
28638
28668
  const isActive = index === currentStep;
28639
28669
  const isCompleted = index < currentStep;
28640
- return /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
28670
+ return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
28641
28671
  /* @__PURE__ */ jsx(
28642
28672
  "button",
28643
28673
  {
@@ -29701,7 +29731,7 @@ function InventoryGrid({
29701
29731
  const eventBus = useEventBus();
29702
29732
  const slotCount = totalSlots ?? items.length;
29703
29733
  const emptySlotCount = Math.max(0, slotCount - items.length);
29704
- const handleSelect = React91.useCallback(
29734
+ const handleSelect = React90.useCallback(
29705
29735
  (id) => {
29706
29736
  onSelect?.(id);
29707
29737
  if (selectEvent) {
@@ -29935,31 +29965,31 @@ function GameCanvas2D({
29935
29965
  assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
29936
29966
  className
29937
29967
  }) {
29938
- const canvasRef = React91.useRef(null);
29939
- const rafRef = React91.useRef(0);
29940
- const frameRef = React91.useRef(0);
29941
- const lastTimeRef = React91.useRef(0);
29942
- const imageCache = React91.useRef(/* @__PURE__ */ new Map());
29968
+ const canvasRef = React90.useRef(null);
29969
+ const rafRef = React90.useRef(0);
29970
+ const frameRef = React90.useRef(0);
29971
+ const lastTimeRef = React90.useRef(0);
29972
+ const imageCache = React90.useRef(/* @__PURE__ */ new Map());
29943
29973
  const emit = useEmitEvent();
29944
- const onDrawRef = React91.useRef(onDraw);
29974
+ const onDrawRef = React90.useRef(onDraw);
29945
29975
  onDrawRef.current = onDraw;
29946
- const onTickRef = React91.useRef(onTick);
29976
+ const onTickRef = React90.useRef(onTick);
29947
29977
  onTickRef.current = onTick;
29948
- const tickEventRef = React91.useRef(tickEvent);
29978
+ const tickEventRef = React90.useRef(tickEvent);
29949
29979
  tickEventRef.current = tickEvent;
29950
- const drawEventRef = React91.useRef(drawEvent);
29980
+ const drawEventRef = React90.useRef(drawEvent);
29951
29981
  drawEventRef.current = drawEvent;
29952
- const emitRef = React91.useRef(emit);
29982
+ const emitRef = React90.useRef(emit);
29953
29983
  emitRef.current = emit;
29954
- const assetBaseUrlRef = React91.useRef(assetBaseUrl);
29984
+ const assetBaseUrlRef = React90.useRef(assetBaseUrl);
29955
29985
  assetBaseUrlRef.current = assetBaseUrl;
29956
- const backgroundImageRef = React91.useRef(backgroundImage);
29986
+ const backgroundImageRef = React90.useRef(backgroundImage);
29957
29987
  backgroundImageRef.current = backgroundImage;
29958
- const widthRef = React91.useRef(width);
29988
+ const widthRef = React90.useRef(width);
29959
29989
  widthRef.current = width;
29960
- const heightRef = React91.useRef(height);
29990
+ const heightRef = React90.useRef(height);
29961
29991
  heightRef.current = height;
29962
- const loadImage = React91.useCallback((url) => {
29992
+ const loadImage = React90.useCallback((url) => {
29963
29993
  const fullUrl = url.startsWith("http") ? url : `${assetBaseUrlRef.current}${url}`;
29964
29994
  const cached = imageCache.current.get(fullUrl);
29965
29995
  if (cached?.complete && cached.naturalWidth > 0) return cached;
@@ -29971,7 +30001,7 @@ function GameCanvas2D({
29971
30001
  }
29972
30002
  return null;
29973
30003
  }, []);
29974
- React91.useEffect(() => {
30004
+ React90.useEffect(() => {
29975
30005
  const canvas = canvasRef.current;
29976
30006
  if (!canvas) return;
29977
30007
  const ctx = canvas.getContext("2d");
@@ -30283,7 +30313,7 @@ function TurnPanel({
30283
30313
  className
30284
30314
  }) {
30285
30315
  const eventBus = useEventBus();
30286
- const handleAction = React91.useCallback(
30316
+ const handleAction = React90.useCallback(
30287
30317
  (event) => {
30288
30318
  if (event) {
30289
30319
  eventBus.emit(event, { turn: currentTurn, phase, activeTeam });
@@ -30452,7 +30482,7 @@ function UnitCommandBar({
30452
30482
  className
30453
30483
  }) {
30454
30484
  const eventBus = useEventBus();
30455
- const handleCommand = React91.useCallback(
30485
+ const handleCommand = React90.useCallback(
30456
30486
  (event) => {
30457
30487
  if (event) {
30458
30488
  eventBus.emit(event, { unitId: selectedUnitId });
@@ -30966,7 +30996,7 @@ function GameMenu({
30966
30996
  } catch {
30967
30997
  }
30968
30998
  const eventBus = eventBusProp || eventBusFromHook;
30969
- const handleOptionClick = React91.useCallback(
30999
+ const handleOptionClick = React90.useCallback(
30970
31000
  (option) => {
30971
31001
  if (option.event && eventBus) {
30972
31002
  eventBus.emit(`UI:${option.event}`, { option });
@@ -31085,7 +31115,7 @@ function GameOverScreen({
31085
31115
  } catch {
31086
31116
  }
31087
31117
  const eventBus = eventBusProp || eventBusFromHook;
31088
- const handleActionClick = React91.useCallback(
31118
+ const handleActionClick = React90.useCallback(
31089
31119
  (action) => {
31090
31120
  if (action.event && eventBus) {
31091
31121
  eventBus.emit(`UI:${action.event}`, { action });
@@ -31974,13 +32004,13 @@ var init_MapView = __esm({
31974
32004
  shadowSize: [41, 41]
31975
32005
  });
31976
32006
  L.Marker.prototype.options.icon = defaultIcon;
31977
- const { useEffect: useEffect84, useRef: useRef76, useCallback: useCallback124, useState: useState120 } = React91__default;
32007
+ const { useEffect: useEffect85, useRef: useRef77, useCallback: useCallback125, useState: useState121 } = React90__default;
31978
32008
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
31979
32009
  const { useEventBus: useEventBus4 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
31980
32010
  function MapUpdater({ centerLat, centerLng, zoom }) {
31981
32011
  const map = useMap();
31982
- const prevRef = useRef76({ centerLat, centerLng, zoom });
31983
- useEffect84(() => {
32012
+ const prevRef = useRef77({ centerLat, centerLng, zoom });
32013
+ useEffect85(() => {
31984
32014
  const prev = prevRef.current;
31985
32015
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
31986
32016
  map.setView([centerLat, centerLng], zoom);
@@ -31991,7 +32021,7 @@ var init_MapView = __esm({
31991
32021
  }
31992
32022
  function MapClickHandler({ onMapClick }) {
31993
32023
  const map = useMap();
31994
- useEffect84(() => {
32024
+ useEffect85(() => {
31995
32025
  if (!onMapClick) return;
31996
32026
  const handler = (e) => {
31997
32027
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -32019,8 +32049,8 @@ var init_MapView = __esm({
32019
32049
  showAttribution = true
32020
32050
  }) {
32021
32051
  const eventBus = useEventBus4();
32022
- const [clickedPosition, setClickedPosition] = useState120(null);
32023
- const handleMapClick = useCallback124((lat, lng) => {
32052
+ const [clickedPosition, setClickedPosition] = useState121(null);
32053
+ const handleMapClick = useCallback125((lat, lng) => {
32024
32054
  if (showClickedPin) {
32025
32055
  setClickedPosition({ lat, lng });
32026
32056
  }
@@ -32029,7 +32059,7 @@ var init_MapView = __esm({
32029
32059
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
32030
32060
  }
32031
32061
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
32032
- const handleMarkerClick = useCallback124((marker) => {
32062
+ const handleMarkerClick = useCallback125((marker) => {
32033
32063
  onMarkerClick?.(marker);
32034
32064
  if (markerClickEvent) {
32035
32065
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -32880,8 +32910,8 @@ function TableView({
32880
32910
  }) {
32881
32911
  const eventBus = useEventBus();
32882
32912
  const { t } = useTranslate();
32883
- const [visibleCount, setVisibleCount] = React91__default.useState(pageSize > 0 ? pageSize : Infinity);
32884
- const [localSelected, setLocalSelected] = React91__default.useState(/* @__PURE__ */ new Set());
32913
+ const [visibleCount, setVisibleCount] = React90__default.useState(pageSize > 0 ? pageSize : Infinity);
32914
+ const [localSelected, setLocalSelected] = React90__default.useState(/* @__PURE__ */ new Set());
32885
32915
  const colDefs = columns ?? fields ?? [];
32886
32916
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
32887
32917
  const dnd = useDataDnd({
@@ -33076,12 +33106,12 @@ function TableView({
33076
33106
  ]
33077
33107
  }
33078
33108
  );
33079
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React91__default.Fragment, { children: rowInner }, id);
33109
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React90__default.Fragment, { children: rowInner }, id);
33080
33110
  };
33081
33111
  const items = data.map((row) => row);
33082
33112
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
33083
33113
  let runningIndex = 0;
33084
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
33114
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
33085
33115
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
33086
33116
  group.items.map((row) => renderRow(row, runningIndex++))
33087
33117
  ] }, gi)) });
@@ -34438,7 +34468,7 @@ var init_StepFlow = __esm({
34438
34468
  className
34439
34469
  }) => {
34440
34470
  if (orientation === "vertical") {
34441
- return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React91__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
34471
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React90__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
34442
34472
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
34443
34473
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
34444
34474
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -34449,7 +34479,7 @@ var init_StepFlow = __esm({
34449
34479
  ] })
34450
34480
  ] }) }, index)) });
34451
34481
  }
34452
- 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(React91__default.Fragment, { children: [
34482
+ 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(React90__default.Fragment, { children: [
34453
34483
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
34454
34484
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
34455
34485
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -35434,7 +35464,7 @@ var init_LikertScale = __esm({
35434
35464
  md: "text-base",
35435
35465
  lg: "text-lg"
35436
35466
  };
35437
- LikertScale = React91__default.forwardRef(
35467
+ LikertScale = React90__default.forwardRef(
35438
35468
  ({
35439
35469
  question,
35440
35470
  options = DEFAULT_LIKERT_OPTIONS,
@@ -35446,7 +35476,7 @@ var init_LikertScale = __esm({
35446
35476
  variant = "radios",
35447
35477
  className
35448
35478
  }, ref) => {
35449
- const groupId = React91__default.useId();
35479
+ const groupId = React90__default.useId();
35450
35480
  const eventBus = useEventBus();
35451
35481
  const handleSelect = useCallback(
35452
35482
  (next) => {
@@ -37728,7 +37758,7 @@ var init_DocBreadcrumb = __esm({
37728
37758
  "aria-label": t("aria.breadcrumb"),
37729
37759
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
37730
37760
  const isLast = idx === items.length - 1;
37731
- return /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
37761
+ return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
37732
37762
  idx > 0 && /* @__PURE__ */ jsx(
37733
37763
  Icon,
37734
37764
  {
@@ -38392,7 +38422,7 @@ var init_PageHeader = __esm({
38392
38422
  info: "bg-info/10 text-info"
38393
38423
  };
38394
38424
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
38395
- 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(React91__default.Fragment, { children: [
38425
+ 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(React90__default.Fragment, { children: [
38396
38426
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
38397
38427
  crumb.href ? /* @__PURE__ */ jsx(
38398
38428
  "a",
@@ -39121,7 +39151,7 @@ var init_WizardContainer = __esm({
39121
39151
  const isCompleted = index < currentStep;
39122
39152
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
39123
39153
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
39124
- return /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
39154
+ return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
39125
39155
  /* @__PURE__ */ jsx(
39126
39156
  Button,
39127
39157
  {
@@ -41456,7 +41486,7 @@ var init_DetailPanel = __esm({
41456
41486
  }
41457
41487
  });
41458
41488
  function extractTitle(children) {
41459
- if (!React91__default.isValidElement(children)) return void 0;
41489
+ if (!React90__default.isValidElement(children)) return void 0;
41460
41490
  const props = children.props;
41461
41491
  if (typeof props.title === "string") {
41462
41492
  return props.title;
@@ -41511,7 +41541,7 @@ function LinearView({
41511
41541
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
41512
41542
  const isDone = i < currentIdx;
41513
41543
  const isCurrent = i === currentIdx;
41514
- return /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
41544
+ return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
41515
41545
  i > 0 && /* @__PURE__ */ jsx(
41516
41546
  Typography,
41517
41547
  {
@@ -42461,12 +42491,12 @@ var init_Form = __esm({
42461
42491
  const isSchemaEntity = isOrbitalEntitySchema(entity);
42462
42492
  const resolvedEntity = isSchemaEntity ? entity : void 0;
42463
42493
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
42464
- const normalizedInitialData = React91__default.useMemo(() => {
42494
+ const normalizedInitialData = React90__default.useMemo(() => {
42465
42495
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
42466
42496
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
42467
42497
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
42468
42498
  }, [entity, initialData]);
42469
- const entityDerivedFields = React91__default.useMemo(() => {
42499
+ const entityDerivedFields = React90__default.useMemo(() => {
42470
42500
  if (fields && fields.length > 0) return void 0;
42471
42501
  if (!resolvedEntity) return void 0;
42472
42502
  return resolvedEntity.fields.map(
@@ -42486,16 +42516,16 @@ var init_Form = __esm({
42486
42516
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
42487
42517
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
42488
42518
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
42489
- const [formData, setFormData] = React91__default.useState(
42519
+ const [formData, setFormData] = React90__default.useState(
42490
42520
  normalizedInitialData
42491
42521
  );
42492
- const [collapsedSections, setCollapsedSections] = React91__default.useState(
42522
+ const [collapsedSections, setCollapsedSections] = React90__default.useState(
42493
42523
  /* @__PURE__ */ new Set()
42494
42524
  );
42495
- const [submitError, setSubmitError] = React91__default.useState(null);
42496
- const formRef = React91__default.useRef(null);
42525
+ const [submitError, setSubmitError] = React90__default.useState(null);
42526
+ const formRef = React90__default.useRef(null);
42497
42527
  const formMode = props.mode;
42498
- const mountedRef = React91__default.useRef(false);
42528
+ const mountedRef = React90__default.useRef(false);
42499
42529
  if (!mountedRef.current) {
42500
42530
  mountedRef.current = true;
42501
42531
  debug("forms", "mount", {
@@ -42508,7 +42538,7 @@ var init_Form = __esm({
42508
42538
  });
42509
42539
  }
42510
42540
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
42511
- const evalContext = React91__default.useMemo(
42541
+ const evalContext = React90__default.useMemo(
42512
42542
  () => ({
42513
42543
  formValues: formData,
42514
42544
  globalVariables: externalContext?.globalVariables ?? {},
@@ -42517,7 +42547,7 @@ var init_Form = __esm({
42517
42547
  }),
42518
42548
  [formData, externalContext]
42519
42549
  );
42520
- React91__default.useEffect(() => {
42550
+ React90__default.useEffect(() => {
42521
42551
  debug("forms", "initialData-sync", {
42522
42552
  mode: formMode,
42523
42553
  normalizedInitialData,
@@ -42528,7 +42558,7 @@ var init_Form = __esm({
42528
42558
  setFormData(normalizedInitialData);
42529
42559
  }
42530
42560
  }, [normalizedInitialData]);
42531
- const processCalculations = React91__default.useCallback(
42561
+ const processCalculations = React90__default.useCallback(
42532
42562
  (changedFieldId, newFormData) => {
42533
42563
  if (!hiddenCalculations.length) return;
42534
42564
  const context = {
@@ -42553,7 +42583,7 @@ var init_Form = __esm({
42553
42583
  },
42554
42584
  [hiddenCalculations, externalContext, eventBus]
42555
42585
  );
42556
- const checkViolations = React91__default.useCallback(
42586
+ const checkViolations = React90__default.useCallback(
42557
42587
  (changedFieldId, newFormData) => {
42558
42588
  if (!violationTriggers.length) return;
42559
42589
  const context = {
@@ -42591,7 +42621,7 @@ var init_Form = __esm({
42591
42621
  processCalculations(name, newFormData);
42592
42622
  checkViolations(name, newFormData);
42593
42623
  };
42594
- const isFieldVisible = React91__default.useCallback(
42624
+ const isFieldVisible = React90__default.useCallback(
42595
42625
  (fieldName) => {
42596
42626
  const condition = conditionalFields[fieldName];
42597
42627
  if (!condition) return true;
@@ -42599,7 +42629,7 @@ var init_Form = __esm({
42599
42629
  },
42600
42630
  [conditionalFields, evalContext]
42601
42631
  );
42602
- const isSectionVisible = React91__default.useCallback(
42632
+ const isSectionVisible = React90__default.useCallback(
42603
42633
  (section) => {
42604
42634
  if (!section.condition) return true;
42605
42635
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -42675,7 +42705,7 @@ var init_Form = __esm({
42675
42705
  eventBus.emit(`UI:${onCancel}`);
42676
42706
  }
42677
42707
  };
42678
- const renderField = React91__default.useCallback(
42708
+ const renderField = React90__default.useCallback(
42679
42709
  (field) => {
42680
42710
  const fieldName = field.name || field.field;
42681
42711
  if (!fieldName) return null;
@@ -42696,7 +42726,7 @@ var init_Form = __esm({
42696
42726
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
42697
42727
  );
42698
42728
  const effectiveFields = entityDerivedFields ?? fields;
42699
- const normalizedFields = React91__default.useMemo(() => {
42729
+ const normalizedFields = React90__default.useMemo(() => {
42700
42730
  if (!effectiveFields || effectiveFields.length === 0) return [];
42701
42731
  return effectiveFields.map((field) => {
42702
42732
  if (typeof field === "string") {
@@ -42719,7 +42749,7 @@ var init_Form = __esm({
42719
42749
  return field;
42720
42750
  });
42721
42751
  }, [effectiveFields, resolvedEntity]);
42722
- const schemaFields = React91__default.useMemo(() => {
42752
+ const schemaFields = React90__default.useMemo(() => {
42723
42753
  if (normalizedFields.length === 0) return null;
42724
42754
  if (isDebugEnabled()) {
42725
42755
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -42729,7 +42759,7 @@ var init_Form = __esm({
42729
42759
  }
42730
42760
  return normalizedFields.map(renderField).filter(Boolean);
42731
42761
  }, [normalizedFields, renderField, entityName, conditionalFields]);
42732
- const sectionElements = React91__default.useMemo(() => {
42762
+ const sectionElements = React90__default.useMemo(() => {
42733
42763
  if (!sections || sections.length === 0) return null;
42734
42764
  return sections.map((section) => {
42735
42765
  if (!isSectionVisible(section)) {
@@ -43338,7 +43368,7 @@ var init_AssetLoader = __esm({
43338
43368
  __publicField(this, "textureCache");
43339
43369
  __publicField(this, "loadingPromises");
43340
43370
  this.objLoader = new OBJLoader();
43341
- this.textureLoader = new THREE.TextureLoader();
43371
+ this.textureLoader = new THREE3.TextureLoader();
43342
43372
  this.modelCache = /* @__PURE__ */ new Map();
43343
43373
  this.textureCache = /* @__PURE__ */ new Map();
43344
43374
  this.loadingPromises = /* @__PURE__ */ new Map();
@@ -43412,7 +43442,7 @@ var init_AssetLoader = __esm({
43412
43442
  return this.loadingPromises.get(`texture:${url}`);
43413
43443
  }
43414
43444
  const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
43415
- texture.colorSpace = THREE.SRGBColorSpace;
43445
+ texture.colorSpace = THREE3.SRGBColorSpace;
43416
43446
  this.textureCache.set(url, texture);
43417
43447
  this.loadingPromises.delete(`texture:${url}`);
43418
43448
  return texture;
@@ -43486,7 +43516,7 @@ var init_AssetLoader = __esm({
43486
43516
  });
43487
43517
  this.modelCache.forEach((model) => {
43488
43518
  model.scene.traverse((child) => {
43489
- if (child instanceof THREE.Mesh) {
43519
+ if (child instanceof THREE3.Mesh) {
43490
43520
  child.geometry.dispose();
43491
43521
  if (Array.isArray(child.material)) {
43492
43522
  child.material.forEach((m) => m.dispose());
@@ -43899,11 +43929,11 @@ var init_Canvas3DErrorBoundary = __esm({
43899
43929
  "components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
43900
43930
  }
43901
43931
  });
43902
- var log9, Canvas3DErrorBoundary;
43932
+ var log8, Canvas3DErrorBoundary;
43903
43933
  var init_Canvas3DErrorBoundary2 = __esm({
43904
43934
  "components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
43905
43935
  init_Canvas3DErrorBoundary();
43906
- log9 = createLogger("almadar:ui:game:canvas3d:error-boundary");
43936
+ log8 = createLogger("almadar:ui:game:canvas3d:error-boundary");
43907
43937
  Canvas3DErrorBoundary = class extends Component {
43908
43938
  constructor(props) {
43909
43939
  super(props);
@@ -43931,8 +43961,8 @@ var init_Canvas3DErrorBoundary2 = __esm({
43931
43961
  componentDidCatch(error, errorInfo) {
43932
43962
  this.setState({ errorInfo });
43933
43963
  this.props.onError?.(error, errorInfo);
43934
- log9.error("Error caught", { error });
43935
- log9.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
43964
+ log8.error("Error caught", { error });
43965
+ log8.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
43936
43966
  }
43937
43967
  render() {
43938
43968
  if (this.state.hasError) {
@@ -43995,7 +44025,7 @@ function useGLTFModel(url, resourceBasePath) {
43995
44025
  setState({ model: null, isLoading: false, error: null });
43996
44026
  return;
43997
44027
  }
43998
- log10.debug("Loading", { url });
44028
+ log9.debug("Loading", { url });
43999
44029
  setState((prev) => ({ ...prev, isLoading: true, error: null }));
44000
44030
  const assetRoot = resourceBasePath || detectAssetRoot2(url);
44001
44031
  const loader = new GLTFLoader$1();
@@ -44003,7 +44033,7 @@ function useGLTFModel(url, resourceBasePath) {
44003
44033
  loader.load(
44004
44034
  url,
44005
44035
  (gltf) => {
44006
- log10.debug("Loaded", { url });
44036
+ log9.debug("Loaded", { url });
44007
44037
  setState({
44008
44038
  model: gltf.scene,
44009
44039
  isLoading: false,
@@ -44012,7 +44042,7 @@ function useGLTFModel(url, resourceBasePath) {
44012
44042
  },
44013
44043
  void 0,
44014
44044
  (err) => {
44015
- log10.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
44045
+ log9.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
44016
44046
  setState({
44017
44047
  model: null,
44018
44048
  isLoading: false,
@@ -44042,7 +44072,7 @@ function ModelLoader({
44042
44072
  if (!loadedModel) return null;
44043
44073
  const cloned = loadedModel.clone();
44044
44074
  cloned.traverse((child) => {
44045
- if (child instanceof THREE.Mesh) {
44075
+ if (child instanceof THREE3.Mesh) {
44046
44076
  child.castShadow = castShadow;
44047
44077
  child.receiveShadow = receiveShadow;
44048
44078
  }
@@ -44128,11 +44158,11 @@ function ModelLoader({
44128
44158
  }
44129
44159
  );
44130
44160
  }
44131
- var log10;
44161
+ var log9;
44132
44162
  var init_ModelLoader = __esm({
44133
44163
  "components/game/molecules/three/components/ModelLoader.tsx"() {
44134
44164
  "use client";
44135
- log10 = createLogger("almadar:ui:game:model-loader");
44165
+ log9 = createLogger("almadar:ui:game:model-loader");
44136
44166
  }
44137
44167
  });
44138
44168
 
@@ -44156,6 +44186,47 @@ function CameraController({
44156
44186
  }, [camera.position, onCameraChange]);
44157
44187
  return null;
44158
44188
  }
44189
+ function UnitSpriteBillboard({
44190
+ sheetUrl,
44191
+ resolveFrame,
44192
+ height = 1.2
44193
+ }) {
44194
+ const texture = useLoader(THREE3.TextureLoader, sheetUrl);
44195
+ const meshRef = useRef(null);
44196
+ const matRef = useRef(null);
44197
+ const [aspect, setAspect] = useState(1);
44198
+ useFrame(() => {
44199
+ const frame = resolveFrame();
44200
+ if (!frame || !texture.image) return;
44201
+ const imgW = texture.image.width;
44202
+ const imgH = texture.image.height;
44203
+ if (!imgW || !imgH) return;
44204
+ texture.repeat.set((frame.flipX ? -1 : 1) * (frame.sw / imgW), frame.sh / imgH);
44205
+ texture.offset.set(
44206
+ frame.flipX ? (frame.sx + frame.sw) / imgW : frame.sx / imgW,
44207
+ 1 - (frame.sy + frame.sh) / imgH
44208
+ );
44209
+ texture.magFilter = THREE3.NearestFilter;
44210
+ texture.minFilter = THREE3.NearestFilter;
44211
+ texture.needsUpdate = true;
44212
+ const nextAspect = frame.sw / frame.sh;
44213
+ if (Math.abs(nextAspect - aspect) > 1e-3) setAspect(nextAspect);
44214
+ if (matRef.current) matRef.current.needsUpdate = true;
44215
+ });
44216
+ return /* @__PURE__ */ jsxs("mesh", { ref: meshRef, position: [0, height / 2, 0], children: [
44217
+ /* @__PURE__ */ jsx("planeGeometry", { args: [height * aspect, height] }),
44218
+ /* @__PURE__ */ jsx(
44219
+ "meshBasicMaterial",
44220
+ {
44221
+ ref: matRef,
44222
+ map: texture,
44223
+ transparent: true,
44224
+ alphaTest: 0.1,
44225
+ side: THREE3.DoubleSide
44226
+ }
44227
+ )
44228
+ ] });
44229
+ }
44159
44230
  var DEFAULT_GRID_CONFIG, GameCanvas3D;
44160
44231
  var init_GameCanvas3D2 = __esm({
44161
44232
  "components/game/molecules/GameCanvas3D.tsx"() {
@@ -44166,6 +44237,7 @@ var init_GameCanvas3D2 = __esm({
44166
44237
  init_Canvas3DLoadingState2();
44167
44238
  init_Canvas3DErrorBoundary2();
44168
44239
  init_ModelLoader();
44240
+ init_useUnitSpriteAtlas();
44169
44241
  init_cn();
44170
44242
  init_GameCanvas3D();
44171
44243
  DEFAULT_GRID_CONFIG = {
@@ -44222,8 +44294,10 @@ var init_GameCanvas3D2 = __esm({
44222
44294
  const controlsRef = useRef(null);
44223
44295
  const [hoveredTile, setHoveredTile] = useState(null);
44224
44296
  const [internalError, setInternalError] = useState(null);
44297
+ const { sheetUrls: atlasSheetUrls, resolveUnitFrame } = useUnitSpriteAtlas(units);
44298
+ const preloadUrls = useMemo(() => [...preloadAssets, ...atlasSheetUrls], [preloadAssets, atlasSheetUrls]);
44225
44299
  const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
44226
- preloadUrls: preloadAssets,
44300
+ preloadUrls,
44227
44301
  loader: customAssetLoader
44228
44302
  });
44229
44303
  const eventHandlers = useGameCanvas3DEvents({
@@ -44282,7 +44356,7 @@ var init_GameCanvas3D2 = __esm({
44282
44356
  getCameraPosition: () => {
44283
44357
  if (controlsRef.current) {
44284
44358
  const pos = controlsRef.current.object.position;
44285
- return new THREE.Vector3(pos.x, pos.y, pos.z);
44359
+ return new THREE3.Vector3(pos.x, pos.y, pos.z);
44286
44360
  }
44287
44361
  return null;
44288
44362
  },
@@ -44434,6 +44508,8 @@ var init_GameCanvas3D2 = __esm({
44434
44508
  ({ unit, position }) => {
44435
44509
  const isSelected = selectedUnitId === unit.id;
44436
44510
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
44511
+ const hasAtlas = unitAtlasUrl(unit) !== null;
44512
+ const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
44437
44513
  return /* @__PURE__ */ jsxs(
44438
44514
  "group",
44439
44515
  {
@@ -44445,7 +44521,16 @@ var init_GameCanvas3D2 = __esm({
44445
44521
  /* @__PURE__ */ jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
44446
44522
  /* @__PURE__ */ jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
44447
44523
  ] }),
44448
- unit.modelUrl ? (
44524
+ hasAtlas && initialFrame ? (
44525
+ /* Animated sprite-sheet billboard — single cropped frame, by state */
44526
+ /* @__PURE__ */ jsx(Billboard, { children: /* @__PURE__ */ jsx(
44527
+ UnitSpriteBillboard,
44528
+ {
44529
+ sheetUrl: initialFrame.sheetUrl,
44530
+ resolveFrame: () => resolveUnitFrame(unit.id)
44531
+ }
44532
+ ) })
44533
+ ) : unit.modelUrl ? (
44449
44534
  /* GLB unit model (box fallback while loading / on error) */
44450
44535
  /* @__PURE__ */ jsx(
44451
44536
  ModelLoader,
@@ -44499,7 +44584,7 @@ var init_GameCanvas3D2 = __esm({
44499
44584
  }
44500
44585
  );
44501
44586
  },
44502
- [selectedUnitId, handleUnitClick]
44587
+ [selectedUnitId, handleUnitClick, resolveUnitFrame]
44503
44588
  );
44504
44589
  const DefaultFeatureRenderer = useCallback(
44505
44590
  ({
@@ -45566,7 +45651,7 @@ var init_List = __esm({
45566
45651
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
45567
45652
  return [];
45568
45653
  }, [entity]);
45569
- const getItemActions = React91__default.useCallback(
45654
+ const getItemActions = React90__default.useCallback(
45570
45655
  (item) => {
45571
45656
  if (!itemActions) return [];
45572
45657
  if (typeof itemActions === "function") {
@@ -46042,7 +46127,7 @@ var init_MediaGallery = __esm({
46042
46127
  [selectable, selectedItems, selectionEvent, eventBus]
46043
46128
  );
46044
46129
  const entityData = Array.isArray(entity) ? entity : [];
46045
- const items = React91__default.useMemo(() => {
46130
+ const items = React90__default.useMemo(() => {
46046
46131
  if (propItems) return propItems;
46047
46132
  if (entityData.length === 0) return [];
46048
46133
  return entityData.map((record, idx) => ({
@@ -46203,7 +46288,7 @@ var init_MediaGallery = __esm({
46203
46288
  }
46204
46289
  });
46205
46290
  function extractTitle2(children) {
46206
- if (!React91__default.isValidElement(children)) return void 0;
46291
+ if (!React90__default.isValidElement(children)) return void 0;
46207
46292
  const props = children.props;
46208
46293
  if (typeof props.title === "string") {
46209
46294
  return props.title;
@@ -47227,7 +47312,7 @@ var init_debugRegistry = __esm({
47227
47312
  }
47228
47313
  });
47229
47314
  function useDebugData() {
47230
- const [data, setData] = React91.useState(() => ({
47315
+ const [data, setData] = React90.useState(() => ({
47231
47316
  traits: [],
47232
47317
  ticks: [],
47233
47318
  guards: [],
@@ -47241,7 +47326,7 @@ function useDebugData() {
47241
47326
  },
47242
47327
  lastUpdate: Date.now()
47243
47328
  }));
47244
- React91.useEffect(() => {
47329
+ React90.useEffect(() => {
47245
47330
  const updateData = () => {
47246
47331
  setData({
47247
47332
  traits: getAllTraits(),
@@ -47350,12 +47435,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
47350
47435
  return positions;
47351
47436
  }
47352
47437
  function WalkMinimap() {
47353
- const [walkStep, setWalkStep] = React91.useState(null);
47354
- const [traits2, setTraits] = React91.useState([]);
47355
- const [coveredEdges, setCoveredEdges] = React91.useState([]);
47356
- const [completedTraits, setCompletedTraits] = React91.useState(/* @__PURE__ */ new Set());
47357
- const prevTraitRef = React91.useRef(null);
47358
- React91.useEffect(() => {
47438
+ const [walkStep, setWalkStep] = React90.useState(null);
47439
+ const [traits2, setTraits] = React90.useState([]);
47440
+ const [coveredEdges, setCoveredEdges] = React90.useState([]);
47441
+ const [completedTraits, setCompletedTraits] = React90.useState(/* @__PURE__ */ new Set());
47442
+ const prevTraitRef = React90.useRef(null);
47443
+ React90.useEffect(() => {
47359
47444
  const interval = setInterval(() => {
47360
47445
  const w = window;
47361
47446
  const step = w.__orbitalWalkStep;
@@ -47791,15 +47876,15 @@ var init_EntitiesTab = __esm({
47791
47876
  });
47792
47877
  function EventFlowTab({ events: events2 }) {
47793
47878
  const { t } = useTranslate();
47794
- const [filter, setFilter] = React91.useState("all");
47795
- const containerRef = React91.useRef(null);
47796
- const [autoScroll, setAutoScroll] = React91.useState(true);
47797
- React91.useEffect(() => {
47879
+ const [filter, setFilter] = React90.useState("all");
47880
+ const containerRef = React90.useRef(null);
47881
+ const [autoScroll, setAutoScroll] = React90.useState(true);
47882
+ React90.useEffect(() => {
47798
47883
  if (autoScroll && containerRef.current) {
47799
47884
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
47800
47885
  }
47801
47886
  }, [events2.length, autoScroll]);
47802
- const filteredEvents = React91.useMemo(() => {
47887
+ const filteredEvents = React90.useMemo(() => {
47803
47888
  if (filter === "all") return events2;
47804
47889
  return events2.filter((e) => e.type === filter);
47805
47890
  }, [events2, filter]);
@@ -47915,7 +48000,7 @@ var init_EventFlowTab = __esm({
47915
48000
  });
47916
48001
  function GuardsPanel({ guards }) {
47917
48002
  const { t } = useTranslate();
47918
- const [filter, setFilter] = React91.useState("all");
48003
+ const [filter, setFilter] = React90.useState("all");
47919
48004
  if (guards.length === 0) {
47920
48005
  return /* @__PURE__ */ jsx(
47921
48006
  EmptyState,
@@ -47928,7 +48013,7 @@ function GuardsPanel({ guards }) {
47928
48013
  }
47929
48014
  const passedCount = guards.filter((g) => g.result).length;
47930
48015
  const failedCount = guards.length - passedCount;
47931
- const filteredGuards = React91.useMemo(() => {
48016
+ const filteredGuards = React90.useMemo(() => {
47932
48017
  if (filter === "all") return guards;
47933
48018
  if (filter === "passed") return guards.filter((g) => g.result);
47934
48019
  return guards.filter((g) => !g.result);
@@ -48091,10 +48176,10 @@ function EffectBadge({ effect }) {
48091
48176
  }
48092
48177
  function TransitionTimeline({ transitions }) {
48093
48178
  const { t } = useTranslate();
48094
- const containerRef = React91.useRef(null);
48095
- const [autoScroll, setAutoScroll] = React91.useState(true);
48096
- const [expandedId, setExpandedId] = React91.useState(null);
48097
- React91.useEffect(() => {
48179
+ const containerRef = React90.useRef(null);
48180
+ const [autoScroll, setAutoScroll] = React90.useState(true);
48181
+ const [expandedId, setExpandedId] = React90.useState(null);
48182
+ React90.useEffect(() => {
48098
48183
  if (autoScroll && containerRef.current) {
48099
48184
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
48100
48185
  }
@@ -48374,9 +48459,9 @@ function getAllEvents(traits2) {
48374
48459
  function EventDispatcherTab({ traits: traits2, schema }) {
48375
48460
  const eventBus = useEventBus();
48376
48461
  const { t } = useTranslate();
48377
- const [log15, setLog] = React91.useState([]);
48378
- const prevStatesRef = React91.useRef(/* @__PURE__ */ new Map());
48379
- React91.useEffect(() => {
48462
+ const [log15, setLog] = React90.useState([]);
48463
+ const prevStatesRef = React90.useRef(/* @__PURE__ */ new Map());
48464
+ React90.useEffect(() => {
48380
48465
  for (const trait of traits2) {
48381
48466
  const prev = prevStatesRef.current.get(trait.id);
48382
48467
  if (prev && prev !== trait.currentState) {
@@ -48545,10 +48630,10 @@ function VerifyModePanel({
48545
48630
  localCount
48546
48631
  }) {
48547
48632
  const { t } = useTranslate();
48548
- const [expanded, setExpanded] = React91.useState(true);
48549
- const scrollRef = React91.useRef(null);
48550
- const prevCountRef = React91.useRef(0);
48551
- React91.useEffect(() => {
48633
+ const [expanded, setExpanded] = React90.useState(true);
48634
+ const scrollRef = React90.useRef(null);
48635
+ const prevCountRef = React90.useRef(0);
48636
+ React90.useEffect(() => {
48552
48637
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
48553
48638
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
48554
48639
  }
@@ -48605,10 +48690,10 @@ function RuntimeDebugger({
48605
48690
  schema
48606
48691
  }) {
48607
48692
  const { t } = useTranslate();
48608
- const [isCollapsed, setIsCollapsed] = React91.useState(mode === "verify" ? true : defaultCollapsed);
48609
- const [isVisible, setIsVisible] = React91.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
48693
+ const [isCollapsed, setIsCollapsed] = React90.useState(mode === "verify" ? true : defaultCollapsed);
48694
+ const [isVisible, setIsVisible] = React90.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
48610
48695
  const debugData = useDebugData();
48611
- React91.useEffect(() => {
48696
+ React90.useEffect(() => {
48612
48697
  if (mode === "inline") return;
48613
48698
  return onDebugToggle((enabled) => {
48614
48699
  setIsVisible(enabled);
@@ -48617,7 +48702,7 @@ function RuntimeDebugger({
48617
48702
  }
48618
48703
  });
48619
48704
  }, [mode]);
48620
- React91.useEffect(() => {
48705
+ React90.useEffect(() => {
48621
48706
  if (mode === "inline") return;
48622
48707
  const handleKeyDown = (e) => {
48623
48708
  if (e.key === "`" && isVisible) {
@@ -49177,7 +49262,7 @@ function SequenceBar({
49177
49262
  onSlotRemove(index);
49178
49263
  }, [onSlotRemove, playing]);
49179
49264
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
49180
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
49265
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
49181
49266
  i > 0 && /* @__PURE__ */ jsx(
49182
49267
  Typography,
49183
49268
  {
@@ -50066,7 +50151,7 @@ var init_StatCard = __esm({
50066
50151
  const labelToUse = propLabel ?? propTitle;
50067
50152
  const eventBus = useEventBus();
50068
50153
  const { t } = useTranslate();
50069
- const handleActionClick = React91__default.useCallback(() => {
50154
+ const handleActionClick = React90__default.useCallback(() => {
50070
50155
  if (action?.event) {
50071
50156
  eventBus.emit(`UI:${action.event}`, {});
50072
50157
  }
@@ -50077,7 +50162,7 @@ var init_StatCard = __esm({
50077
50162
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
50078
50163
  const isLoading = externalLoading ?? false;
50079
50164
  const error = externalError;
50080
- const computeMetricValue = React91__default.useCallback(
50165
+ const computeMetricValue = React90__default.useCallback(
50081
50166
  (metric, items) => {
50082
50167
  if (metric.value !== void 0) {
50083
50168
  return metric.value;
@@ -50116,7 +50201,7 @@ var init_StatCard = __esm({
50116
50201
  },
50117
50202
  []
50118
50203
  );
50119
- const schemaStats = React91__default.useMemo(() => {
50204
+ const schemaStats = React90__default.useMemo(() => {
50120
50205
  if (!metrics || metrics.length === 0) return null;
50121
50206
  return metrics.map((metric) => ({
50122
50207
  label: metric.label,
@@ -50124,7 +50209,7 @@ var init_StatCard = __esm({
50124
50209
  format: metric.format
50125
50210
  }));
50126
50211
  }, [metrics, data, computeMetricValue]);
50127
- const calculatedTrend = React91__default.useMemo(() => {
50212
+ const calculatedTrend = React90__default.useMemo(() => {
50128
50213
  if (manualTrend !== void 0) return manualTrend;
50129
50214
  if (previousValue === void 0 || currentValue === void 0)
50130
50215
  return void 0;
@@ -51090,7 +51175,7 @@ var init_Timeline = __esm({
51090
51175
  }) => {
51091
51176
  const { t } = useTranslate();
51092
51177
  const entityData = Array.isArray(entity) ? entity : [];
51093
- const items = React91__default.useMemo(() => {
51178
+ const items = React90__default.useMemo(() => {
51094
51179
  if (propItems) return propItems;
51095
51180
  if (entityData.length === 0) return [];
51096
51181
  return entityData.map((record, idx) => {
@@ -51197,7 +51282,7 @@ var init_Timeline = __esm({
51197
51282
  }
51198
51283
  });
51199
51284
  function extractToastProps(children) {
51200
- if (!React91__default.isValidElement(children)) {
51285
+ if (!React90__default.isValidElement(children)) {
51201
51286
  if (typeof children === "string") {
51202
51287
  return { message: children };
51203
51288
  }
@@ -51235,7 +51320,7 @@ var init_ToastSlot = __esm({
51235
51320
  eventBus.emit("UI:CLOSE");
51236
51321
  };
51237
51322
  if (!isVisible) return null;
51238
- const isCustomContent = React91__default.isValidElement(children) && !message;
51323
+ const isCustomContent = React90__default.isValidElement(children) && !message;
51239
51324
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
51240
51325
  Toast,
51241
51326
  {
@@ -52104,7 +52189,7 @@ var init_WorldMapTemplate = __esm({
52104
52189
  }
52105
52190
  });
52106
52191
  function lazyThree(name, loader) {
52107
- const Lazy = React91__default.lazy(
52192
+ const Lazy = React90__default.lazy(
52108
52193
  () => loader().then((m) => {
52109
52194
  const Resolved = m[name];
52110
52195
  if (!Resolved) {
@@ -52116,13 +52201,13 @@ function lazyThree(name, loader) {
52116
52201
  })
52117
52202
  );
52118
52203
  function ThreeWrapper(props) {
52119
- return React91__default.createElement(
52204
+ return React90__default.createElement(
52120
52205
  ThreeBoundary,
52121
52206
  { name },
52122
- React91__default.createElement(
52123
- React91__default.Suspense,
52207
+ React90__default.createElement(
52208
+ React90__default.Suspense,
52124
52209
  { fallback: null },
52125
- React91__default.createElement(Lazy, props)
52210
+ React90__default.createElement(Lazy, props)
52126
52211
  )
52127
52212
  );
52128
52213
  }
@@ -52420,7 +52505,7 @@ var init_component_registry_generated = __esm({
52420
52505
  init_WorldMapBoard();
52421
52506
  init_WorldMapTemplate();
52422
52507
  init_XPBar();
52423
- ThreeBoundary = class extends React91__default.Component {
52508
+ ThreeBoundary = class extends React90__default.Component {
52424
52509
  constructor() {
52425
52510
  super(...arguments);
52426
52511
  __publicField(this, "state", { failed: false });
@@ -52430,7 +52515,7 @@ var init_component_registry_generated = __esm({
52430
52515
  }
52431
52516
  render() {
52432
52517
  if (this.state.failed) {
52433
- return React91__default.createElement(
52518
+ return React90__default.createElement(
52434
52519
  "div",
52435
52520
  {
52436
52521
  "data-testid": "three-unavailable",
@@ -52771,7 +52856,7 @@ function SuspenseConfigProvider({
52771
52856
  config,
52772
52857
  children
52773
52858
  }) {
52774
- return React91__default.createElement(
52859
+ return React90__default.createElement(
52775
52860
  SuspenseConfigContext.Provider,
52776
52861
  { value: config },
52777
52862
  children
@@ -53261,7 +53346,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
53261
53346
  const key = `${parentId}-${index}-trait:${traitName}`;
53262
53347
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
53263
53348
  }
53264
- return /* @__PURE__ */ jsx(React91__default.Fragment, { children: child }, `${parentId}-${index}`);
53349
+ return /* @__PURE__ */ jsx(React90__default.Fragment, { children: child }, `${parentId}-${index}`);
53265
53350
  }
53266
53351
  if (!child || typeof child !== "object") return null;
53267
53352
  const childId = `${parentId}-${index}`;
@@ -53301,14 +53386,14 @@ function isPatternConfig(value) {
53301
53386
  if (value === null || value === void 0) return false;
53302
53387
  if (typeof value !== "object") return false;
53303
53388
  if (Array.isArray(value)) return false;
53304
- if (React91__default.isValidElement(value)) return false;
53389
+ if (React90__default.isValidElement(value)) return false;
53305
53390
  if (value instanceof Date) return false;
53306
53391
  if (typeof value === "function") return false;
53307
53392
  const record = value;
53308
53393
  return "type" in record && typeof record.type === "string";
53309
53394
  }
53310
53395
  function isPlainConfigObject(value) {
53311
- if (React91__default.isValidElement(value)) return false;
53396
+ if (React90__default.isValidElement(value)) return false;
53312
53397
  if (value instanceof Date) return false;
53313
53398
  const proto = Object.getPrototypeOf(value);
53314
53399
  return proto === Object.prototype || proto === null;
@@ -53815,7 +53900,7 @@ var AvlTransition = ({
53815
53900
  opacity = 1,
53816
53901
  className
53817
53902
  }) => {
53818
- const ids = React91__default.useMemo(() => {
53903
+ const ids = React90__default.useMemo(() => {
53819
53904
  avlTransitionId += 1;
53820
53905
  return { arrow: `avl-tr-${avlTransitionId}-arrow` };
53821
53906
  }, []);
@@ -54376,7 +54461,7 @@ var AvlStateMachine = ({
54376
54461
  color = "var(--color-primary)",
54377
54462
  animated = false
54378
54463
  }) => {
54379
- const ids = React91__default.useMemo(() => {
54464
+ const ids = React90__default.useMemo(() => {
54380
54465
  avlSmId += 1;
54381
54466
  const base = `avl-sm-${avlSmId}`;
54382
54467
  return { glow: `${base}-glow`, grad: `${base}-grad` };
@@ -54575,7 +54660,7 @@ var AvlOrbitalUnit = ({
54575
54660
  color = "var(--color-primary)",
54576
54661
  animated = false
54577
54662
  }) => {
54578
- const ids = React91__default.useMemo(() => {
54663
+ const ids = React90__default.useMemo(() => {
54579
54664
  avlOuId += 1;
54580
54665
  const base = `avl-ou-${avlOuId}`;
54581
54666
  return { glow: `${base}-glow`, grad: `${base}-grad` };
@@ -54671,7 +54756,7 @@ var AvlClosedCircuit = ({
54671
54756
  color = "var(--color-primary)",
54672
54757
  animated = false
54673
54758
  }) => {
54674
- const ids = React91__default.useMemo(() => {
54759
+ const ids = React90__default.useMemo(() => {
54675
54760
  avlCcId += 1;
54676
54761
  const base = `avl-cc-${avlCcId}`;
54677
54762
  return { glow: `${base}-glow`, grad: `${base}-grad`, arrow: `${base}-arrow` };
@@ -54826,7 +54911,7 @@ var AvlEmitListen = ({
54826
54911
  color = "var(--color-primary)",
54827
54912
  animated = false
54828
54913
  }) => {
54829
- const ids = React91__default.useMemo(() => {
54914
+ const ids = React90__default.useMemo(() => {
54830
54915
  avlElId += 1;
54831
54916
  const base = `avl-el-${avlElId}`;
54832
54917
  return { arrow: `${base}-arrow`, grad: `${base}-grad` };
@@ -55100,7 +55185,7 @@ function renderNode(node, color, glowId) {
55100
55185
  const baseR = node.type === "operator" ? 20 : 16;
55101
55186
  const r2 = Math.max(baseR, labelLen * 3.5 + 6);
55102
55187
  const nc = nodeColor(node.type, color);
55103
- return /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
55188
+ return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
55104
55189
  node.children.map((child, i) => {
55105
55190
  const childR = Math.max(
55106
55191
  child.type === "operator" ? 20 : 16,
@@ -55157,7 +55242,7 @@ var AvlExprTree = ({
55157
55242
  className,
55158
55243
  color = "var(--color-primary)"
55159
55244
  }) => {
55160
- const ids = React91__default.useMemo(() => {
55245
+ const ids = React90__default.useMemo(() => {
55161
55246
  avlEtId += 1;
55162
55247
  return { glow: `avl-et-${avlEtId}-glow` };
55163
55248
  }, []);
@@ -55981,7 +56066,7 @@ var SystemNode = ({ data }) => {
55981
56066
  stateChain.length > 0 && /* @__PURE__ */ jsx("svg", { width: stateChain.length * 14 + 2, height: 10, viewBox: `0 0 ${stateChain.length * 14 + 2} 10`, children: stateChain.map((s, i) => {
55982
56067
  const tc = transitionCounts[s.name] ?? 0;
55983
56068
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
55984
- return /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
56069
+ return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
55985
56070
  /* @__PURE__ */ jsx(AvlState, { x: i * 14 + 1, y: 1, width: 10, height: 8, name: "", role, isInitial: s.isInitial, isTerminal: s.isTerminal }),
55986
56071
  i < stateChain.length - 1 && /* @__PURE__ */ jsx("line", { x1: i * 14 + 12, y1: 5, x2: i * 14 + 15, y2: 5, stroke: "var(--color-border)", strokeWidth: 0.5 })
55987
56072
  ] }, s.name);
@@ -57133,7 +57218,7 @@ function resolveLambdaBindings(body, params, item, index) {
57133
57218
  if (Array.isArray(body)) {
57134
57219
  return body.map((b) => recur(b));
57135
57220
  }
57136
- if (body !== null && typeof body === "object" && !React91__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
57221
+ if (body !== null && typeof body === "object" && !React90__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
57137
57222
  const out = {};
57138
57223
  for (const [k, v] of Object.entries(body)) {
57139
57224
  out[k] = recur(v);
@@ -57152,7 +57237,7 @@ function getSlotContentRenderer2() {
57152
57237
  function makeLambdaFn(params, lambdaBody, callerKey) {
57153
57238
  return (item, index) => {
57154
57239
  const resolvedBody = resolveLambdaBindings(lambdaBody, params, item, index);
57155
- if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React91__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
57240
+ if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React90__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
57156
57241
  return null;
57157
57242
  }
57158
57243
  const record = resolvedBody;
@@ -57171,7 +57256,7 @@ function makeLambdaFn(params, lambdaBody, callerKey) {
57171
57256
  props: childProps,
57172
57257
  priority: 0
57173
57258
  };
57174
- return React91__default.createElement(SlotContentRenderer2, { content: childContent });
57259
+ return React90__default.createElement(SlotContentRenderer2, { content: childContent });
57175
57260
  };
57176
57261
  }
57177
57262
  function convertNode(node, callerKey) {
@@ -57190,7 +57275,7 @@ function convertNode(node, callerKey) {
57190
57275
  });
57191
57276
  return anyChanged ? mapped : node;
57192
57277
  }
57193
- if (typeof node === "object" && !React91__default.isValidElement(node) && !(node instanceof Date)) {
57278
+ if (typeof node === "object" && !React90__default.isValidElement(node) && !(node instanceof Date)) {
57194
57279
  return convertObjectProps(node);
57195
57280
  }
57196
57281
  return node;
@@ -57217,7 +57302,7 @@ function convertObjectProps(props) {
57217
57302
  function convertFnFormLambdasInProps(props) {
57218
57303
  return convertObjectProps(props);
57219
57304
  }
57220
- var log11 = createLogger("almadar:ui:effects:client-handlers");
57305
+ var log10 = createLogger("almadar:ui:effects:client-handlers");
57221
57306
  function createClientEffectHandlers(options) {
57222
57307
  const { eventBus, slotSetter, navigate, notify, callService } = options;
57223
57308
  return {
@@ -57226,10 +57311,10 @@ function createClientEffectHandlers(options) {
57226
57311
  eventBus.emit(prefixedEvent, payload);
57227
57312
  },
57228
57313
  persist: async () => {
57229
- log11.warn("persist is server-side only, ignored on client");
57314
+ log10.warn("persist is server-side only, ignored on client");
57230
57315
  },
57231
57316
  set: () => {
57232
- log11.warn("set is server-side only, ignored on client");
57317
+ log10.warn("set is server-side only, ignored on client");
57233
57318
  },
57234
57319
  callService: async (service, action, params) => {
57235
57320
  if (callService) return callService(service, action, params);
@@ -57258,10 +57343,10 @@ function createClientEffectHandlers(options) {
57258
57343
  slotSetter.addPattern(slot, pattern, props);
57259
57344
  },
57260
57345
  navigate: navigate ?? ((path) => {
57261
- log11.warn("No navigate handler, ignoring", { path });
57346
+ log10.warn("No navigate handler, ignoring", { path });
57262
57347
  }),
57263
57348
  notify: notify ?? ((msg, type) => {
57264
- log11.debug("notify", { type, message: msg });
57349
+ log10.debug("notify", { type, message: msg });
57265
57350
  })
57266
57351
  };
57267
57352
  }
@@ -57273,6 +57358,27 @@ init_verificationRegistry();
57273
57358
  var crossTraitLog = createLogger("almadar:ui:cross-trait");
57274
57359
  var flushLog = createLogger("almadar:ui:slot-flush");
57275
57360
  var stateLog = createLogger("almadar:ui:state-transitions");
57361
+ var tickLog = createLogger("almadar:ui:tick-effects");
57362
+ var SYNC_TICK_OPERATORS = /* @__PURE__ */ new Set([
57363
+ "set",
57364
+ "emit",
57365
+ "render-ui",
57366
+ "render",
57367
+ "navigate",
57368
+ "notify",
57369
+ "log",
57370
+ // Synchronous structural forms that wrap sync effects. A tick authored as
57371
+ // a single top-level `(let ((..)) (do (set ..) (render-ui ..)))` or
57372
+ // `(if cond (set ..) ..)` is one of these at its head — the EffectExecutor
57373
+ // resolves the binding values / condition through the canonical evaluator
57374
+ // and runs the wrapped sync effects. Without these in the allow-list the
57375
+ // whole tick is filtered out (its head op isn't `set`/`emit`/...), so the
57376
+ // physics/gameflow/AI tick never runs.
57377
+ "let",
57378
+ "if",
57379
+ "do",
57380
+ "when"
57381
+ ]);
57276
57382
  function toTraitDefinition(binding) {
57277
57383
  return {
57278
57384
  name: binding.trait.name,
@@ -57469,50 +57575,196 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
57469
57575
  for (const unreg of snapshotUnregs) unreg();
57470
57576
  };
57471
57577
  }, [traitBindings]);
57472
- const runTickEffects = useCallback((tick, binding) => {
57473
- const currentState = traitStatesRef.current.get(binding.trait.name)?.currentState ?? "";
57474
- if (tick.appliesTo.length > 0 && !tick.appliesTo.includes(currentState)) return;
57475
- const bindingCtx = { entity: {}, payload: {}, state: currentState };
57476
- if (binding.config) {
57477
- bindingCtx.config = binding.config;
57478
- }
57479
- const evalCtx = createContextFromBindings(bindingCtx);
57480
- if (tick.guard !== void 0) {
57481
- const passed = interpolateValue(tick.guard, evalCtx);
57482
- if (!passed) return;
57483
- }
57578
+ const executeTransitionEffects = useCallback(async (params) => {
57579
+ const { binding, previousState, newState, payload, flushEvent, syncOnly, log: log15 } = params;
57580
+ const traitName = binding.trait.name;
57581
+ const linkedEntity = binding.linkedEntity || "";
57582
+ const entityId = payload?.entityId;
57583
+ const effects = syncOnly ? params.effects.filter(
57584
+ (e) => Array.isArray(e) && SYNC_TICK_OPERATORS.has(String(e[0]))
57585
+ ) : params.effects;
57586
+ if (effects.length === 0) return [];
57484
57587
  const pendingSlots = /* @__PURE__ */ new Map();
57485
57588
  ({
57486
- trait: binding.trait.name,
57487
- transition: `${currentState}->tick:${tick.name}`,
57488
- effects: tick.effects,
57489
57589
  traitDefinition: binding.trait
57490
57590
  });
57491
- for (const effect of tick.effects) {
57492
- if (!Array.isArray(effect)) continue;
57493
- const op = effect[0];
57494
- if (op === "render-ui" || op === "render") {
57495
- const slot = effect[1];
57496
- const rawPattern = effect[2];
57497
- if (rawPattern === null || rawPattern === void 0) {
57591
+ const clientHandlers = createClientEffectHandlers({
57592
+ eventBus,
57593
+ slotSetter: {
57594
+ addPattern: (slot, pattern, props) => {
57595
+ const existing = pendingSlots.get(slot) || [];
57596
+ existing.push({ pattern, props: props || {} });
57597
+ pendingSlots.set(slot, existing);
57598
+ },
57599
+ clearSlot: (slot) => {
57498
57600
  pendingSlots.set(slot, []);
57499
- continue;
57500
57601
  }
57501
- const updatedCtx = createContextFromBindings(bindingCtx);
57502
- const resolved = interpolateValue(rawPattern, updatedCtx);
57503
- const existing = pendingSlots.get(slot) ?? [];
57504
- existing.push({ pattern: resolved, props: {} });
57505
- pendingSlots.set(slot, existing);
57602
+ },
57603
+ navigate: optionsRef.current?.navigate,
57604
+ notify: optionsRef.current?.notify,
57605
+ callService: optionsRef.current?.callService
57606
+ });
57607
+ const persistence = syncOnly ? void 0 : optionsRef.current?.persistence;
57608
+ let handlers = clientHandlers;
57609
+ if (persistence) {
57610
+ const sharedBindings = {
57611
+ // Seed `@entity` from the trait's scalar field state (a real
57612
+ // EntityRow), the same source the executor's own bindingCtx
57613
+ // uses below. `@payload.*` resolves from `payload` separately,
57614
+ // so dropping the prior `payload as EntityRow` cast loses
57615
+ // nothing — it just stops mislabelling the payload as an entity.
57616
+ entity: traitFieldStatesRef.current.get(traitName) ?? {},
57617
+ payload: payload || {},
57618
+ state: previousState
57619
+ };
57620
+ const sharedDeclared = collectDeclaredConfigDefaults(binding.trait);
57621
+ const sharedCallSite = binding.config;
57622
+ if (sharedDeclared || sharedCallSite) {
57623
+ sharedBindings.config = {
57624
+ ...sharedDeclared ?? {},
57625
+ ...sharedCallSite ?? {}
57626
+ };
57627
+ }
57628
+ const serverHandlers = createServerEffectHandlers({
57629
+ persistence,
57630
+ eventBus,
57631
+ entityType: linkedEntity,
57632
+ entityId,
57633
+ bindings: sharedBindings,
57634
+ context: {
57635
+ traitName,
57636
+ state: previousState,
57637
+ transition: `${previousState}->${newState}`,
57638
+ linkedEntity,
57639
+ entityId
57640
+ },
57641
+ source: { trait: traitName },
57642
+ callService: optionsRef.current?.callService
57643
+ });
57644
+ handlers = {
57645
+ ...serverHandlers,
57646
+ emit: clientHandlers.emit,
57647
+ renderUI: clientHandlers.renderUI,
57648
+ navigate: clientHandlers.navigate,
57649
+ notify: clientHandlers.notify
57650
+ };
57651
+ }
57652
+ const baseSet = handlers.set;
57653
+ handlers = {
57654
+ ...handlers,
57655
+ set: async (targetId, field, value) => {
57656
+ let fieldState = traitFieldStatesRef.current.get(traitName);
57657
+ if (!fieldState) {
57658
+ fieldState = {};
57659
+ traitFieldStatesRef.current.set(traitName, fieldState);
57660
+ }
57661
+ fieldState[field] = value;
57662
+ log15.debug("set:write", {
57663
+ traitName,
57664
+ field,
57665
+ value: JSON.stringify(value),
57666
+ transition: `${previousState}->${newState}`
57667
+ });
57668
+ if (baseSet) await baseSet(targetId, field, value);
57506
57669
  }
57670
+ };
57671
+ const entityForBinding = traitFieldStatesRef.current.get(traitName) ?? {};
57672
+ const bindingCtx = {
57673
+ entity: entityForBinding,
57674
+ payload: payload || {},
57675
+ state: previousState
57676
+ };
57677
+ const declaredDefaults = collectDeclaredConfigDefaults(binding.trait);
57678
+ const callSiteConfig = binding.config;
57679
+ if (declaredDefaults || callSiteConfig) {
57680
+ bindingCtx.config = {
57681
+ ...declaredDefaults ?? {},
57682
+ ...callSiteConfig ?? {}
57683
+ };
57507
57684
  }
57508
- for (const [slot, patterns] of pendingSlots) {
57509
- flushSlot(binding.trait.name, slot, patterns, {
57510
- event: `tick:${tick.name}`,
57511
- state: currentState,
57512
- entity: binding.linkedEntity
57685
+ const effectContext = {
57686
+ traitName,
57687
+ state: previousState,
57688
+ transition: `${previousState}->${newState}`,
57689
+ linkedEntity,
57690
+ entityId
57691
+ };
57692
+ const emittedDuringExec = [];
57693
+ const baseEmit = handlers.emit;
57694
+ const trackingHandlers = {
57695
+ ...handlers,
57696
+ emit: (event, eventPayload, source) => {
57697
+ emittedDuringExec.push(event);
57698
+ baseEmit(event, eventPayload, source);
57699
+ }
57700
+ };
57701
+ const executor = new EffectExecutor({ handlers: trackingHandlers, bindings: bindingCtx, context: effectContext });
57702
+ try {
57703
+ await executor.executeAll(effects);
57704
+ log15.debug("effects:executed", () => ({
57705
+ traitName,
57706
+ transition: `${previousState}->${newState}`,
57707
+ event: flushEvent,
57708
+ effectCount: effects.length,
57709
+ emitted: emittedDuringExec.join(","),
57710
+ entityAfter: JSON.stringify(traitFieldStatesRef.current.get(traitName) ?? {}),
57711
+ slotsTouched: Array.from(pendingSlots.keys()).join(",")
57712
+ }));
57713
+ for (const [slot, patterns] of pendingSlots) {
57714
+ log15.debug("flush:slot", {
57715
+ traitName,
57716
+ slot,
57717
+ patternCount: patterns.length,
57718
+ event: flushEvent,
57719
+ transition: `${previousState}->${newState}`,
57720
+ cleared: patterns.length === 0
57721
+ });
57722
+ flushSlot(traitName, slot, patterns, {
57723
+ event: flushEvent,
57724
+ state: previousState,
57725
+ entity: binding.linkedEntity
57726
+ });
57727
+ }
57728
+ } catch (error) {
57729
+ log15.error("effects:error", {
57730
+ traitName,
57731
+ transition: `${previousState}->${newState}`,
57732
+ event: flushEvent,
57733
+ error: error instanceof Error ? error.message : String(error),
57734
+ effectCount: effects.length
57513
57735
  });
57514
57736
  }
57515
- }, [flushSlot]);
57737
+ return emittedDuringExec;
57738
+ }, [eventBus, flushSlot]);
57739
+ const runTickEffects = useCallback((tick, binding) => {
57740
+ const traitName = binding.trait.name;
57741
+ const currentState = traitStatesRef.current.get(traitName)?.currentState ?? "";
57742
+ if (tick.appliesTo.length > 0 && !tick.appliesTo.includes(currentState)) return;
57743
+ if (tick.guard !== void 0) {
57744
+ const guardCtx = {
57745
+ entity: traitFieldStatesRef.current.get(traitName) ?? {},
57746
+ payload: {},
57747
+ state: currentState
57748
+ };
57749
+ if (binding.config) {
57750
+ guardCtx.config = binding.config;
57751
+ }
57752
+ const passed = interpolateValue(tick.guard, createContextFromBindings(guardCtx));
57753
+ if (!passed) {
57754
+ tickLog.debug("guard-blocked", { traitName, tick: tick.name, state: currentState });
57755
+ return;
57756
+ }
57757
+ }
57758
+ void executeTransitionEffects({
57759
+ binding,
57760
+ effects: tick.effects,
57761
+ previousState: currentState,
57762
+ newState: currentState,
57763
+ flushEvent: `tick:${tick.name}`,
57764
+ syncOnly: true,
57765
+ log: tickLog
57766
+ });
57767
+ }, [executeTransitionEffects]);
57516
57768
  useEffect(() => {
57517
57769
  const hasFrameTicks = traitBindingsRef.current.some(
57518
57770
  (b) => b.trait.ticks?.some((t) => t.interval === "frame")
@@ -57623,161 +57875,17 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
57623
57875
  transition: `${result.previousState} -> ${result.newState}`,
57624
57876
  effects: JSON.stringify(result.effects)
57625
57877
  }));
57626
- const linkedEntity = binding.linkedEntity || "";
57627
- const entityId = payload?.entityId;
57628
- const pendingSlots = /* @__PURE__ */ new Map();
57629
- const slotSource = {
57630
- trait: binding.trait.name,
57631
- state: result.previousState,
57632
- transition: `${result.previousState}->${result.newState}`,
57878
+ const emittedDuringExec = await executeTransitionEffects({
57879
+ binding,
57633
57880
  effects: result.effects,
57634
- traitDefinition: binding.trait
57635
- };
57636
- const clientHandlers = createClientEffectHandlers({
57637
- eventBus,
57638
- slotSetter: {
57639
- addPattern: (slot, pattern, props) => {
57640
- const existing = pendingSlots.get(slot) || [];
57641
- existing.push({ pattern, props: props || {} });
57642
- pendingSlots.set(slot, existing);
57643
- },
57644
- clearSlot: (slot) => {
57645
- pendingSlots.set(slot, []);
57646
- }
57647
- },
57648
- navigate: optionsRef.current?.navigate,
57649
- notify: optionsRef.current?.notify,
57650
- callService: optionsRef.current?.callService
57881
+ previousState: result.previousState,
57882
+ newState: result.newState,
57883
+ payload,
57884
+ flushEvent: eventKey,
57885
+ syncOnly: false,
57886
+ log: stateLog
57651
57887
  });
57652
- const persistence = optionsRef.current?.persistence;
57653
- let handlers = clientHandlers;
57654
- if (persistence) {
57655
- const sharedBindings = {
57656
- entity: payload ?? {},
57657
- payload: payload || {},
57658
- state: result.previousState
57659
- };
57660
- const sharedDeclared = collectDeclaredConfigDefaults(
57661
- binding.trait
57662
- );
57663
- const sharedCallSite = binding.config;
57664
- if (sharedDeclared || sharedCallSite) {
57665
- sharedBindings.config = {
57666
- ...sharedDeclared ?? {},
57667
- ...sharedCallSite ?? {}
57668
- };
57669
- }
57670
- const serverHandlers = createServerEffectHandlers({
57671
- persistence,
57672
- eventBus,
57673
- entityType: linkedEntity,
57674
- entityId,
57675
- bindings: sharedBindings,
57676
- context: {
57677
- traitName: binding.trait.name,
57678
- state: result.previousState,
57679
- transition: `${result.previousState}->${result.newState}`,
57680
- linkedEntity,
57681
- entityId
57682
- },
57683
- source: { trait: binding.trait.name },
57684
- callService: optionsRef.current?.callService
57685
- });
57686
- handlers = {
57687
- ...serverHandlers,
57688
- // Client handlers own UI + emit: keep the slot setter
57689
- // and pre-prefixed UI:* emit path intact.
57690
- emit: clientHandlers.emit,
57691
- renderUI: clientHandlers.renderUI,
57692
- navigate: clientHandlers.navigate,
57693
- notify: clientHandlers.notify
57694
- };
57695
- }
57696
- const baseSet = handlers.set;
57697
- handlers = {
57698
- ...handlers,
57699
- set: async (targetId, field, value) => {
57700
- let fieldState = traitFieldStatesRef.current.get(traitName);
57701
- if (!fieldState) {
57702
- fieldState = {};
57703
- traitFieldStatesRef.current.set(traitName, fieldState);
57704
- }
57705
- fieldState[field] = value;
57706
- if (baseSet) await baseSet(targetId, field, value);
57707
- }
57708
- };
57709
- const entityForBinding = traitFieldStatesRef.current.get(traitName) ?? {};
57710
- const bindingCtx = {
57711
- entity: entityForBinding,
57712
- payload: payload || {},
57713
- state: result.previousState
57714
- };
57715
- const declaredDefaults = collectDeclaredConfigDefaults(
57716
- binding.trait
57717
- );
57718
- const callSiteConfig = binding.config;
57719
- if (declaredDefaults || callSiteConfig) {
57720
- bindingCtx.config = {
57721
- ...declaredDefaults ?? {},
57722
- ...callSiteConfig ?? {}
57723
- };
57724
- }
57725
- const effectContext = {
57726
- traitName: binding.trait.name,
57727
- state: result.previousState,
57728
- transition: `${result.previousState}->${result.newState}`,
57729
- linkedEntity,
57730
- entityId
57731
- };
57732
- const emittedDuringExec = [];
57733
57888
  emittedByTrait.set(traitName, emittedDuringExec);
57734
- const baseEmit = handlers.emit;
57735
- const trackingHandlers = {
57736
- ...handlers,
57737
- emit: (event, eventPayload, source) => {
57738
- emittedDuringExec.push(event);
57739
- baseEmit(event, eventPayload, source);
57740
- }
57741
- };
57742
- const executor = new EffectExecutor({ handlers: trackingHandlers, bindings: bindingCtx, context: effectContext });
57743
- try {
57744
- await executor.executeAll(result.effects);
57745
- stateLog.debug("transition:render-ui-dispatched", () => ({
57746
- traitName,
57747
- fromState: result.previousState,
57748
- toState: result.newState,
57749
- event: eventKey,
57750
- slotsTouched: Array.from(pendingSlots.keys()).join(","),
57751
- patternTypes: Array.from(pendingSlots.entries()).map(
57752
- ([slot, patterns]) => `${slot}:[${patterns.map((p2) => p2.pattern?.type ?? "null").join(",")}]`
57753
- ).join(";")
57754
- }));
57755
- void slotSource;
57756
- for (const [slot, patterns] of pendingSlots) {
57757
- stateLog.debug("flush:slot", {
57758
- traitName,
57759
- slot,
57760
- patternCount: patterns.length,
57761
- event: eventKey,
57762
- transition: `${result.previousState}->${result.newState}`,
57763
- cleared: patterns.length === 0
57764
- });
57765
- flushSlot(traitName, slot, patterns, {
57766
- event: eventKey,
57767
- state: result.previousState,
57768
- entity: binding.linkedEntity
57769
- });
57770
- }
57771
- } catch (error) {
57772
- stateLog.error("transition:effect-error", {
57773
- traitName,
57774
- fromState: result.previousState,
57775
- toState: result.newState,
57776
- event: eventKey,
57777
- error: error instanceof Error ? error.message : String(error),
57778
- effectCount: result.effects.length
57779
- });
57780
- }
57781
57889
  } else if (!result.executed) {
57782
57890
  if (result.guardResult === false) {
57783
57891
  stateLog.debug("guard-blocked-transition", {
@@ -58185,9 +58293,175 @@ function ServerBridgeProvider({
58185
58293
  }, [schema, registerSchema, unregisterSchema]);
58186
58294
  return /* @__PURE__ */ jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
58187
58295
  }
58188
-
58189
- // context/OrbitalThemeProvider.tsx
58190
- init_ThemeContext();
58296
+ createLogger("almadar:ui:theme");
58297
+ var BUILT_IN_THEMES = [
58298
+ {
58299
+ name: "wireframe",
58300
+ displayName: "Wireframe",
58301
+ hasLightMode: true,
58302
+ hasDarkMode: true
58303
+ },
58304
+ {
58305
+ name: "minimalist",
58306
+ displayName: "Minimalist",
58307
+ hasLightMode: true,
58308
+ hasDarkMode: true
58309
+ },
58310
+ {
58311
+ name: "almadar",
58312
+ displayName: "Almadar",
58313
+ hasLightMode: true,
58314
+ hasDarkMode: true
58315
+ },
58316
+ {
58317
+ name: "trait-wars",
58318
+ displayName: "Trait Wars",
58319
+ hasLightMode: false,
58320
+ hasDarkMode: true
58321
+ },
58322
+ // Extended themes
58323
+ {
58324
+ name: "ocean",
58325
+ displayName: "Ocean",
58326
+ hasLightMode: true,
58327
+ hasDarkMode: true
58328
+ },
58329
+ {
58330
+ name: "forest",
58331
+ displayName: "Forest",
58332
+ hasLightMode: true,
58333
+ hasDarkMode: true
58334
+ },
58335
+ {
58336
+ name: "sunset",
58337
+ displayName: "Sunset",
58338
+ hasLightMode: true,
58339
+ hasDarkMode: true
58340
+ },
58341
+ {
58342
+ name: "lavender",
58343
+ displayName: "Lavender",
58344
+ hasLightMode: true,
58345
+ hasDarkMode: true
58346
+ },
58347
+ {
58348
+ name: "rose",
58349
+ displayName: "Rose",
58350
+ hasLightMode: true,
58351
+ hasDarkMode: true
58352
+ },
58353
+ {
58354
+ name: "slate",
58355
+ displayName: "Slate",
58356
+ hasLightMode: true,
58357
+ hasDarkMode: true
58358
+ },
58359
+ {
58360
+ name: "ember",
58361
+ displayName: "Ember",
58362
+ hasLightMode: true,
58363
+ hasDarkMode: true
58364
+ },
58365
+ {
58366
+ name: "midnight",
58367
+ displayName: "Midnight",
58368
+ hasLightMode: true,
58369
+ hasDarkMode: true
58370
+ },
58371
+ {
58372
+ name: "sand",
58373
+ displayName: "Sand",
58374
+ hasLightMode: true,
58375
+ hasDarkMode: true
58376
+ },
58377
+ {
58378
+ name: "neon",
58379
+ displayName: "Neon",
58380
+ hasLightMode: true,
58381
+ hasDarkMode: true
58382
+ },
58383
+ {
58384
+ name: "arctic",
58385
+ displayName: "Arctic",
58386
+ hasLightMode: true,
58387
+ hasDarkMode: true
58388
+ },
58389
+ {
58390
+ name: "copper",
58391
+ displayName: "Copper",
58392
+ hasLightMode: true,
58393
+ hasDarkMode: true
58394
+ },
58395
+ // Layer 1 skin axes — truly-unique themes (compact tech / editorial / brutalist dense / display-heavy / touch-first)
58396
+ {
58397
+ name: "prism",
58398
+ displayName: "Prism",
58399
+ hasLightMode: true,
58400
+ hasDarkMode: true
58401
+ },
58402
+ {
58403
+ name: "gazette",
58404
+ displayName: "Gazette",
58405
+ hasLightMode: true,
58406
+ hasDarkMode: true
58407
+ },
58408
+ {
58409
+ name: "terminal",
58410
+ displayName: "Terminal",
58411
+ hasLightMode: true,
58412
+ hasDarkMode: true
58413
+ },
58414
+ {
58415
+ name: "atelier",
58416
+ displayName: "Atelier",
58417
+ hasLightMode: true,
58418
+ hasDarkMode: true
58419
+ },
58420
+ {
58421
+ name: "kiosk",
58422
+ displayName: "Kiosk",
58423
+ hasLightMode: true,
58424
+ hasDarkMode: true
58425
+ },
58426
+ {
58427
+ name: "linear-clean",
58428
+ displayName: "Linear Clean",
58429
+ hasLightMode: true,
58430
+ hasDarkMode: true
58431
+ },
58432
+ {
58433
+ name: "notion-editorial",
58434
+ displayName: "Notion Editorial",
58435
+ hasLightMode: true,
58436
+ hasDarkMode: true
58437
+ },
58438
+ {
58439
+ name: "bloomberg-dense",
58440
+ displayName: "Bloomberg Dense",
58441
+ hasLightMode: true,
58442
+ hasDarkMode: true
58443
+ }
58444
+ ];
58445
+ var ThemeContext = createContext(void 0);
58446
+ function useTheme2() {
58447
+ const context = useContext(ThemeContext);
58448
+ if (context === void 0) {
58449
+ return {
58450
+ theme: "wireframe",
58451
+ mode: "light",
58452
+ resolvedMode: "light",
58453
+ setTheme: () => {
58454
+ },
58455
+ setMode: () => {
58456
+ },
58457
+ toggleMode: () => {
58458
+ },
58459
+ availableThemes: BUILT_IN_THEMES,
58460
+ appliedTheme: "wireframe-light"
58461
+ };
58462
+ }
58463
+ return context;
58464
+ }
58191
58465
 
58192
58466
  // context/themeTokens.ts
58193
58467
  function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
@@ -58406,7 +58680,7 @@ function resolveThemeForRuntime(theme) {
58406
58680
  }
58407
58681
  function OrbitalThemeProvider({ theme, children }) {
58408
58682
  const resolved = resolveThemeForRuntime(theme);
58409
- const { resolvedMode } = useTheme();
58683
+ const { resolvedMode } = useTheme2();
58410
58684
  if (!resolved) {
58411
58685
  return /* @__PURE__ */ jsx(Fragment, { children });
58412
58686
  }
@@ -59203,8 +59477,8 @@ function CanvasDndProvider({
59203
59477
  }) {
59204
59478
  const eventBus = useEventBus();
59205
59479
  const sensors = useAlmadarDndSensors(false);
59206
- const [activePayload, setActivePayload] = React91__default.useState(null);
59207
- const handleDragStart = React91__default.useCallback((e) => {
59480
+ const [activePayload, setActivePayload] = React90__default.useState(null);
59481
+ const handleDragStart = React90__default.useCallback((e) => {
59208
59482
  const data = e.active.data.current;
59209
59483
  const payload = data?.payload;
59210
59484
  if (payload) {
@@ -59215,7 +59489,7 @@ function CanvasDndProvider({
59215
59489
  log13.warn("dragStart:missing-payload", { id: e.active.id });
59216
59490
  }
59217
59491
  }, [eventBus]);
59218
- const handleDragEnd = React91__default.useCallback((e) => {
59492
+ const handleDragEnd = React90__default.useCallback((e) => {
59219
59493
  setActivePayload(null);
59220
59494
  const activeData = e.active.data.current;
59221
59495
  const payload = activeData?.payload;
@@ -59244,7 +59518,7 @@ function CanvasDndProvider({
59244
59518
  const suppressed = onDrop ? onDrop(drop) === true : false;
59245
59519
  if (!suppressed) defaultEmit(eventBus, drop);
59246
59520
  }, [eventBus, onDrop]);
59247
- const handleDragCancel = React91__default.useCallback(() => {
59521
+ const handleDragCancel = React90__default.useCallback(() => {
59248
59522
  setActivePayload(null);
59249
59523
  log13.info("dragCancel");
59250
59524
  }, []);
@@ -59998,7 +60272,7 @@ var OrbPreviewNodeInner = (props) => {
59998
60272
  }
59999
60273
  );
60000
60274
  };
60001
- var OrbPreviewNode = React91__default.memo(OrbPreviewNodeInner);
60275
+ var OrbPreviewNode = React90__default.memo(OrbPreviewNodeInner);
60002
60276
  OrbPreviewNode.displayName = "OrbPreviewNode";
60003
60277
  orbPreviewLog.debug("export-resolved", () => ({
60004
60278
  type: typeof OrbPreviewNode,
@@ -60103,7 +60377,7 @@ var EventFlowEdgeInner = (props) => {
60103
60377
  ) })
60104
60378
  ] });
60105
60379
  };
60106
- var EventFlowEdge = React91__default.memo(EventFlowEdgeInner);
60380
+ var EventFlowEdge = React90__default.memo(EventFlowEdgeInner);
60107
60381
  EventFlowEdge.displayName = "EventFlowEdge";
60108
60382
 
60109
60383
  // components/avl/molecules/BehaviorComposeNode.tsx
@@ -60250,7 +60524,7 @@ var BehaviorComposeNodeInner = (props) => {
60250
60524
  }
60251
60525
  );
60252
60526
  };
60253
- var BehaviorComposeNode = React91__default.memo(BehaviorComposeNodeInner);
60527
+ var BehaviorComposeNode = React90__default.memo(BehaviorComposeNodeInner);
60254
60528
  BehaviorComposeNode.displayName = "BehaviorComposeNode";
60255
60529
 
60256
60530
  // components/avl/molecules/avl-behavior-compose-converter.ts
@@ -61262,7 +61536,7 @@ var TraitCardNodeInner = (props) => {
61262
61536
  }
61263
61537
  );
61264
61538
  };
61265
- var TraitCardNode = React91__default.memo(TraitCardNodeInner);
61539
+ var TraitCardNode = React90__default.memo(TraitCardNodeInner);
61266
61540
  TraitCardNode.displayName = "TraitCardNode";
61267
61541
 
61268
61542
  // components/avl/organisms/FlowCanvas.tsx
@@ -61335,7 +61609,7 @@ function FlowCanvasInner({
61335
61609
  initialOrbital
61336
61610
  );
61337
61611
  const [expandedBehaviorAlias, setExpandedBehaviorAlias] = useState(void 0);
61338
- const screenSizeUserOverrideRef = React91__default.useRef(false);
61612
+ const screenSizeUserOverrideRef = React90__default.useRef(false);
61339
61613
  const [screenSize, setScreenSize] = useState(
61340
61614
  () => typeof window === "undefined" ? "laptop" : detectScreenSize(window.innerWidth)
61341
61615
  );
@@ -61719,7 +61993,7 @@ var ZoomBreadcrumb = ({
61719
61993
  if (eventName && band === "detail") {
61720
61994
  segments.push({ icon: "\u26A1", label: eventName });
61721
61995
  }
61722
- return /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 z-10 flex items-center gap-1 px-2 py-1 rounded-md bg-card/90 border border-border text-xs text-muted-foreground backdrop-blur-sm", children: segments.map((seg, i) => /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
61996
+ return /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 z-10 flex items-center gap-1 px-2 py-1 rounded-md bg-card/90 border border-border text-xs text-muted-foreground backdrop-blur-sm", children: segments.map((seg, i) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
61723
61997
  i > 0 && /* @__PURE__ */ jsx("span", { className: "opacity-40", children: ">" }),
61724
61998
  /* @__PURE__ */ jsx("span", { className: "opacity-60", children: seg.icon }),
61725
61999
  /* @__PURE__ */ jsx("span", { children: seg.label })
@@ -62060,7 +62334,7 @@ var EventWireOverlay = ({
62060
62334
  containerW,
62061
62335
  containerH
62062
62336
  }) => {
62063
- const ids = React91__default.useMemo(() => {
62337
+ const ids = React90__default.useMemo(() => {
62064
62338
  avlOczWireId += 1;
62065
62339
  return { arrow: `avl-ocz-wire-${avlOczWireId}-arrow` };
62066
62340
  }, []);
@@ -62427,7 +62701,7 @@ var AvlOrbitalsCosmicZoom = ({
62427
62701
  borderRadius: 6,
62428
62702
  border: `1px solid ${color}`
62429
62703
  },
62430
- children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxs(React91__default.Fragment, { children: [
62704
+ children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
62431
62705
  i > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", style: { opacity: 0.5, color }, children: "/" }),
62432
62706
  i < breadcrumbs.length - 1 ? /* @__PURE__ */ jsx(
62433
62707
  Box,