@almadar/ui 5.49.0 → 5.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- import * as React82 from 'react';
2
- import React82__default, { createContext, useMemo, useContext, useRef, useEffect, useCallback, Suspense, useState, useSyncExternalStore, useLayoutEffect, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
1
+ import * as React81 from 'react';
2
+ import React81__default, { createContext, useMemo, useContext, useRef, useEffect, useCallback, Suspense, useState, useSyncExternalStore, useLayoutEffect, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
@@ -9,8 +9,8 @@ import * as LucideIcons2 from 'lucide-react';
9
9
  import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ZoomOut, ZoomIn, Download, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, ArrowLeft, HelpCircle, PauseCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, Bug, Send, ChevronUp, ChevronDown, Wrench, Tag, User, DollarSign, Zap, Sword, Move, Heart, Shield } from 'lucide-react';
10
10
  import { createPortal } from 'react-dom';
11
11
  import { useTranslate, useEventBus as useEventBus$1 } from '@almadar/ui/hooks';
12
+ import { useUISlots, UISlotProvider, useTheme } from '@almadar/ui/context';
12
13
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
13
- import { useUISlots, UISlotProvider } from '@almadar/ui/context';
14
14
  import { Link, Outlet, useLocation } from 'react-router-dom';
15
15
  import ELK from 'elkjs/lib/elk.bundled.js';
16
16
  import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light.js';
@@ -41,14 +41,14 @@ import { DndContext, pointerWithin, rectIntersection, closestCorners, useSensors
41
41
  import { useSortable, arrayMove, sortableKeyboardCoordinates, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
42
42
  import { CSS } from '@dnd-kit/utilities';
43
43
  import { useNodeId, ReactFlowProvider, Handle, Position } from '@xyflow/react';
44
- import * as THREE from 'three';
44
+ import * as THREE3 from 'three';
45
45
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
46
46
  import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
47
47
  import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
48
- import { Canvas, useThree } from '@react-three/fiber';
49
- import { Grid as Grid$1, OrbitControls } from '@react-three/drei';
48
+ import { Canvas, useLoader, useFrame, useThree } from '@react-three/fiber';
49
+ import { Billboard, Grid as Grid$1, OrbitControls } from '@react-three/drei';
50
50
  import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
51
- import { StateMachineManager, createContextFromBindings, interpolateValue, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor, InMemoryPersistence } from '@almadar/runtime';
51
+ import { StateMachineManager, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor, interpolateValue, createContextFromBindings, InMemoryPersistence } from '@almadar/runtime';
52
52
  import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
53
53
 
54
54
  var __defProp = Object.defineProperty;
@@ -396,7 +396,7 @@ var init_Box = __esm({
396
396
  fixed: "fixed",
397
397
  sticky: "sticky"
398
398
  };
399
- Box = React82__default.forwardRef(
399
+ Box = React81__default.forwardRef(
400
400
  ({
401
401
  padding,
402
402
  paddingX,
@@ -446,7 +446,7 @@ var init_Box = __esm({
446
446
  onMouseLeave?.(e);
447
447
  }, [hoverEvent, eventBus, onMouseLeave]);
448
448
  const isClickable = action || onClick;
449
- return React82__default.createElement(
449
+ return React81__default.createElement(
450
450
  Component2,
451
451
  {
452
452
  ref,
@@ -541,7 +541,7 @@ function loadLib(key, importer) {
541
541
  return p2;
542
542
  }
543
543
  function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
544
- const Lazy = React82__default.lazy(async () => {
544
+ const Lazy = React81__default.lazy(async () => {
545
545
  const lib = await loadLib(libKey, importer);
546
546
  const Comp = pick(lib);
547
547
  if (!Comp) {
@@ -551,7 +551,7 @@ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
551
551
  return { default: Comp };
552
552
  });
553
553
  const Wrapped = (props) => /* @__PURE__ */ jsx(
554
- React82__default.Suspense,
554
+ React81__default.Suspense,
555
555
  {
556
556
  fallback: /* @__PURE__ */ jsx(
557
557
  "span",
@@ -1277,7 +1277,7 @@ var init_Icon = __esm({
1277
1277
  const directIcon = typeof icon === "string" ? void 0 : icon;
1278
1278
  const effectiveName = typeof icon === "string" ? icon : name;
1279
1279
  const family = useIconFamily();
1280
- const RenderedComponent = React82__default.useMemo(() => {
1280
+ const RenderedComponent = React81__default.useMemo(() => {
1281
1281
  if (directIcon) return null;
1282
1282
  return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
1283
1283
  }, [directIcon, effectiveName, family]);
@@ -1336,7 +1336,7 @@ function resolveIconProp(value, sizeClass) {
1336
1336
  const IconComp = value;
1337
1337
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
1338
1338
  }
1339
- if (React82__default.isValidElement(value)) {
1339
+ if (React81__default.isValidElement(value)) {
1340
1340
  return value;
1341
1341
  }
1342
1342
  if (typeof value === "object" && value !== null && "render" in value) {
@@ -1412,7 +1412,7 @@ var init_Button = __esm({
1412
1412
  md: "h-icon-default w-icon-default",
1413
1413
  lg: "h-icon-default w-icon-default"
1414
1414
  };
1415
- Button = React82__default.forwardRef(
1415
+ Button = React81__default.forwardRef(
1416
1416
  ({
1417
1417
  className,
1418
1418
  variant = "primary",
@@ -1477,7 +1477,7 @@ var Dialog;
1477
1477
  var init_Dialog = __esm({
1478
1478
  "components/core/atoms/Dialog.tsx"() {
1479
1479
  init_cn();
1480
- Dialog = React82__default.forwardRef(
1480
+ Dialog = React81__default.forwardRef(
1481
1481
  ({
1482
1482
  role = "dialog",
1483
1483
  "aria-modal": ariaModal = true,
@@ -2091,7 +2091,7 @@ var init_Badge = __esm({
2091
2091
  md: "px-2.5 py-1 text-sm",
2092
2092
  lg: "px-3 py-1.5 text-base"
2093
2093
  };
2094
- Badge = React82__default.forwardRef(
2094
+ Badge = React81__default.forwardRef(
2095
2095
  ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
2096
2096
  const iconSizes3 = {
2097
2097
  sm: "h-icon-default w-icon-default",
@@ -2427,7 +2427,7 @@ var init_SvgFlow = __esm({
2427
2427
  width = 100,
2428
2428
  height = 100
2429
2429
  }) => {
2430
- const markerId = React82__default.useMemo(() => {
2430
+ const markerId = React81__default.useMemo(() => {
2431
2431
  flowIdCounter += 1;
2432
2432
  return `almadar-flow-arrow-${flowIdCounter}`;
2433
2433
  }, []);
@@ -3020,7 +3020,7 @@ var init_SvgRing = __esm({
3020
3020
  width = 100,
3021
3021
  height = 100
3022
3022
  }) => {
3023
- const gradientId = React82__default.useMemo(() => {
3023
+ const gradientId = React81__default.useMemo(() => {
3024
3024
  ringIdCounter += 1;
3025
3025
  return `almadar-ring-glow-${ringIdCounter}`;
3026
3026
  }, []);
@@ -3201,7 +3201,7 @@ var init_Input = __esm({
3201
3201
  init_cn();
3202
3202
  init_Icon();
3203
3203
  init_useEventBus();
3204
- Input = React82__default.forwardRef(
3204
+ Input = React81__default.forwardRef(
3205
3205
  ({
3206
3206
  className,
3207
3207
  inputType,
@@ -3361,7 +3361,7 @@ var Label;
3361
3361
  var init_Label = __esm({
3362
3362
  "components/core/atoms/Label.tsx"() {
3363
3363
  init_cn();
3364
- Label = React82__default.forwardRef(
3364
+ Label = React81__default.forwardRef(
3365
3365
  ({ className, required, children, ...props }, ref) => {
3366
3366
  return /* @__PURE__ */ jsxs(
3367
3367
  "label",
@@ -3388,7 +3388,7 @@ var init_Textarea = __esm({
3388
3388
  "components/core/atoms/Textarea.tsx"() {
3389
3389
  init_cn();
3390
3390
  init_useEventBus();
3391
- Textarea = React82__default.forwardRef(
3391
+ Textarea = React81__default.forwardRef(
3392
3392
  ({ className, error, onChange, ...props }, ref) => {
3393
3393
  const eventBus = useEventBus();
3394
3394
  const handleChange = (e) => {
@@ -3627,7 +3627,7 @@ var init_Select = __esm({
3627
3627
  init_cn();
3628
3628
  init_Icon();
3629
3629
  init_useEventBus();
3630
- Select = React82__default.forwardRef(
3630
+ Select = React81__default.forwardRef(
3631
3631
  (props, _ref) => {
3632
3632
  const { multiple, searchable, clearable } = props;
3633
3633
  if (multiple || searchable || clearable) {
@@ -3644,7 +3644,7 @@ var init_Checkbox = __esm({
3644
3644
  "components/core/atoms/Checkbox.tsx"() {
3645
3645
  init_cn();
3646
3646
  init_useEventBus();
3647
- Checkbox = React82__default.forwardRef(
3647
+ Checkbox = React81__default.forwardRef(
3648
3648
  ({ className, label, id, onChange, ...props }, ref) => {
3649
3649
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
3650
3650
  const eventBus = useEventBus();
@@ -3698,7 +3698,7 @@ var init_Spinner = __esm({
3698
3698
  md: "h-6 w-6",
3699
3699
  lg: "h-8 w-8"
3700
3700
  };
3701
- Spinner = React82__default.forwardRef(
3701
+ Spinner = React81__default.forwardRef(
3702
3702
  ({ className, size = "md", overlay, ...props }, ref) => {
3703
3703
  if (overlay) {
3704
3704
  return /* @__PURE__ */ jsx(
@@ -3788,7 +3788,7 @@ var init_Card = __esm({
3788
3788
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
3789
3789
  "tile-image-first": "p-0 overflow-hidden"
3790
3790
  };
3791
- Card = React82__default.forwardRef(
3791
+ Card = React81__default.forwardRef(
3792
3792
  ({
3793
3793
  className,
3794
3794
  variant = "bordered",
@@ -3836,9 +3836,9 @@ var init_Card = __esm({
3836
3836
  }
3837
3837
  );
3838
3838
  Card.displayName = "Card";
3839
- CardHeader = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
3839
+ CardHeader = React81__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
3840
3840
  CardHeader.displayName = "CardHeader";
3841
- CardTitle = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3841
+ CardTitle = React81__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3842
3842
  "h3",
3843
3843
  {
3844
3844
  ref,
@@ -3851,11 +3851,11 @@ var init_Card = __esm({
3851
3851
  }
3852
3852
  ));
3853
3853
  CardTitle.displayName = "CardTitle";
3854
- CardContent = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
3854
+ CardContent = React81__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
3855
3855
  CardContent.displayName = "CardContent";
3856
3856
  CardBody = CardContent;
3857
3857
  CardBody.displayName = "CardBody";
3858
- CardFooter = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3858
+ CardFooter = React81__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3859
3859
  "div",
3860
3860
  {
3861
3861
  ref,
@@ -3910,7 +3910,7 @@ var init_FilterPill = __esm({
3910
3910
  md: "w-3.5 h-3.5",
3911
3911
  lg: "w-4 h-4"
3912
3912
  };
3913
- FilterPill = React82__default.forwardRef(
3913
+ FilterPill = React81__default.forwardRef(
3914
3914
  ({
3915
3915
  className,
3916
3916
  variant = "default",
@@ -4039,8 +4039,8 @@ var init_Avatar = __esm({
4039
4039
  actionPayload
4040
4040
  }) => {
4041
4041
  const eventBus = useEventBus();
4042
- const [imgFailed, setImgFailed] = React82__default.useState(false);
4043
- React82__default.useEffect(() => {
4042
+ const [imgFailed, setImgFailed] = React81__default.useState(false);
4043
+ React81__default.useEffect(() => {
4044
4044
  setImgFailed(false);
4045
4045
  }, [src]);
4046
4046
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -4425,7 +4425,7 @@ var init_Radio = __esm({
4425
4425
  md: "w-2.5 h-2.5",
4426
4426
  lg: "w-3 h-3"
4427
4427
  };
4428
- Radio = React82__default.forwardRef(
4428
+ Radio = React81__default.forwardRef(
4429
4429
  ({
4430
4430
  label,
4431
4431
  helperText,
@@ -4442,12 +4442,12 @@ var init_Radio = __esm({
4442
4442
  onChange,
4443
4443
  ...props
4444
4444
  }, ref) => {
4445
- const reactId = React82__default.useId();
4445
+ const reactId = React81__default.useId();
4446
4446
  const baseId = id || `radio-${reactId}`;
4447
4447
  const hasError = !!error;
4448
4448
  const eventBus = useEventBus();
4449
- const [selected, setSelected] = React82__default.useState(value);
4450
- React82__default.useEffect(() => {
4449
+ const [selected, setSelected] = React81__default.useState(value);
4450
+ React81__default.useEffect(() => {
4451
4451
  if (value !== void 0) setSelected(value);
4452
4452
  }, [value]);
4453
4453
  const pick = (next, e) => {
@@ -4629,7 +4629,7 @@ var init_Switch = __esm({
4629
4629
  "components/core/atoms/Switch.tsx"() {
4630
4630
  "use client";
4631
4631
  init_cn();
4632
- Switch = React82.forwardRef(
4632
+ Switch = React81.forwardRef(
4633
4633
  ({
4634
4634
  checked,
4635
4635
  defaultChecked = false,
@@ -4640,10 +4640,10 @@ var init_Switch = __esm({
4640
4640
  name,
4641
4641
  className
4642
4642
  }, ref) => {
4643
- const [isChecked, setIsChecked] = React82.useState(
4643
+ const [isChecked, setIsChecked] = React81.useState(
4644
4644
  checked !== void 0 ? checked : defaultChecked
4645
4645
  );
4646
- React82.useEffect(() => {
4646
+ React81.useEffect(() => {
4647
4647
  if (checked !== void 0) {
4648
4648
  setIsChecked(checked);
4649
4649
  }
@@ -4898,188 +4898,12 @@ var init_TextHighlight = __esm({
4898
4898
  TextHighlight.displayName = "TextHighlight";
4899
4899
  }
4900
4900
  });
4901
- function useTheme() {
4902
- const context = useContext(ThemeContext);
4903
- if (context === void 0) {
4904
- return {
4905
- theme: "wireframe",
4906
- mode: "light",
4907
- resolvedMode: "light",
4908
- setTheme: () => {
4909
- },
4910
- setMode: () => {
4911
- },
4912
- toggleMode: () => {
4913
- },
4914
- availableThemes: BUILT_IN_THEMES,
4915
- appliedTheme: "wireframe-light"
4916
- };
4917
- }
4918
- return context;
4919
- }
4920
- var BUILT_IN_THEMES, ThemeContext;
4921
- var init_ThemeContext = __esm({
4922
- "context/ThemeContext.tsx"() {
4923
- "use client";
4924
- createLogger("almadar:ui:theme");
4925
- BUILT_IN_THEMES = [
4926
- {
4927
- name: "wireframe",
4928
- displayName: "Wireframe",
4929
- hasLightMode: true,
4930
- hasDarkMode: true
4931
- },
4932
- {
4933
- name: "minimalist",
4934
- displayName: "Minimalist",
4935
- hasLightMode: true,
4936
- hasDarkMode: true
4937
- },
4938
- {
4939
- name: "almadar",
4940
- displayName: "Almadar",
4941
- hasLightMode: true,
4942
- hasDarkMode: true
4943
- },
4944
- {
4945
- name: "trait-wars",
4946
- displayName: "Trait Wars",
4947
- hasLightMode: false,
4948
- hasDarkMode: true
4949
- },
4950
- // Extended themes
4951
- {
4952
- name: "ocean",
4953
- displayName: "Ocean",
4954
- hasLightMode: true,
4955
- hasDarkMode: true
4956
- },
4957
- {
4958
- name: "forest",
4959
- displayName: "Forest",
4960
- hasLightMode: true,
4961
- hasDarkMode: true
4962
- },
4963
- {
4964
- name: "sunset",
4965
- displayName: "Sunset",
4966
- hasLightMode: true,
4967
- hasDarkMode: true
4968
- },
4969
- {
4970
- name: "lavender",
4971
- displayName: "Lavender",
4972
- hasLightMode: true,
4973
- hasDarkMode: true
4974
- },
4975
- {
4976
- name: "rose",
4977
- displayName: "Rose",
4978
- hasLightMode: true,
4979
- hasDarkMode: true
4980
- },
4981
- {
4982
- name: "slate",
4983
- displayName: "Slate",
4984
- hasLightMode: true,
4985
- hasDarkMode: true
4986
- },
4987
- {
4988
- name: "ember",
4989
- displayName: "Ember",
4990
- hasLightMode: true,
4991
- hasDarkMode: true
4992
- },
4993
- {
4994
- name: "midnight",
4995
- displayName: "Midnight",
4996
- hasLightMode: true,
4997
- hasDarkMode: true
4998
- },
4999
- {
5000
- name: "sand",
5001
- displayName: "Sand",
5002
- hasLightMode: true,
5003
- hasDarkMode: true
5004
- },
5005
- {
5006
- name: "neon",
5007
- displayName: "Neon",
5008
- hasLightMode: true,
5009
- hasDarkMode: true
5010
- },
5011
- {
5012
- name: "arctic",
5013
- displayName: "Arctic",
5014
- hasLightMode: true,
5015
- hasDarkMode: true
5016
- },
5017
- {
5018
- name: "copper",
5019
- displayName: "Copper",
5020
- hasLightMode: true,
5021
- hasDarkMode: true
5022
- },
5023
- // Layer 1 skin axes — truly-unique themes (compact tech / editorial / brutalist dense / display-heavy / touch-first)
5024
- {
5025
- name: "prism",
5026
- displayName: "Prism",
5027
- hasLightMode: true,
5028
- hasDarkMode: true
5029
- },
5030
- {
5031
- name: "gazette",
5032
- displayName: "Gazette",
5033
- hasLightMode: true,
5034
- hasDarkMode: true
5035
- },
5036
- {
5037
- name: "terminal",
5038
- displayName: "Terminal",
5039
- hasLightMode: true,
5040
- hasDarkMode: true
5041
- },
5042
- {
5043
- name: "atelier",
5044
- displayName: "Atelier",
5045
- hasLightMode: true,
5046
- hasDarkMode: true
5047
- },
5048
- {
5049
- name: "kiosk",
5050
- displayName: "Kiosk",
5051
- hasLightMode: true,
5052
- hasDarkMode: true
5053
- },
5054
- {
5055
- name: "linear-clean",
5056
- displayName: "Linear Clean",
5057
- hasLightMode: true,
5058
- hasDarkMode: true
5059
- },
5060
- {
5061
- name: "notion-editorial",
5062
- displayName: "Notion Editorial",
5063
- hasLightMode: true,
5064
- hasDarkMode: true
5065
- },
5066
- {
5067
- name: "bloomberg-dense",
5068
- displayName: "Bloomberg Dense",
5069
- hasLightMode: true,
5070
- hasDarkMode: true
5071
- }
5072
- ];
5073
- ThemeContext = createContext(void 0);
5074
- }
5075
- });
5076
4901
  var sizeClasses5, iconSizes2, ThemeToggle;
5077
4902
  var init_ThemeToggle = __esm({
5078
4903
  "components/core/atoms/ThemeToggle.tsx"() {
5079
4904
  "use client";
5080
4905
  init_Icon();
5081
4906
  init_cn();
5082
- init_ThemeContext();
5083
4907
  sizeClasses5 = {
5084
4908
  sm: "p-1.5",
5085
4909
  md: "p-2",
@@ -5174,7 +4998,7 @@ var Aside;
5174
4998
  var init_Aside = __esm({
5175
4999
  "components/core/atoms/Aside.tsx"() {
5176
5000
  init_cn();
5177
- Aside = React82__default.forwardRef(
5001
+ Aside = React81__default.forwardRef(
5178
5002
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
5179
5003
  );
5180
5004
  Aside.displayName = "Aside";
@@ -5252,8 +5076,8 @@ var init_LawReferenceTooltip = __esm({
5252
5076
  className
5253
5077
  }) => {
5254
5078
  const { t } = useTranslate();
5255
- const [isVisible, setIsVisible] = React82__default.useState(false);
5256
- const timeoutRef = React82__default.useRef(null);
5079
+ const [isVisible, setIsVisible] = React81__default.useState(false);
5080
+ const timeoutRef = React81__default.useRef(null);
5257
5081
  const handleMouseEnter = () => {
5258
5082
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
5259
5083
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -5262,7 +5086,7 @@ var init_LawReferenceTooltip = __esm({
5262
5086
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
5263
5087
  setIsVisible(false);
5264
5088
  };
5265
- React82__default.useEffect(() => {
5089
+ React81__default.useEffect(() => {
5266
5090
  return () => {
5267
5091
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
5268
5092
  };
@@ -5472,7 +5296,7 @@ var init_StatusDot = __esm({
5472
5296
  md: "w-2.5 h-2.5",
5473
5297
  lg: "w-3 h-3"
5474
5298
  };
5475
- StatusDot = React82__default.forwardRef(
5299
+ StatusDot = React81__default.forwardRef(
5476
5300
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
5477
5301
  return /* @__PURE__ */ jsx(
5478
5302
  "span",
@@ -5526,7 +5350,7 @@ var init_TrendIndicator = __esm({
5526
5350
  down: "trending-down",
5527
5351
  flat: "arrow-right"
5528
5352
  };
5529
- TrendIndicator = React82__default.forwardRef(
5353
+ TrendIndicator = React81__default.forwardRef(
5530
5354
  ({
5531
5355
  className,
5532
5356
  value,
@@ -5593,7 +5417,7 @@ var init_RangeSlider = __esm({
5593
5417
  md: "w-4 h-4",
5594
5418
  lg: "w-5 h-5"
5595
5419
  };
5596
- RangeSlider = React82__default.forwardRef(
5420
+ RangeSlider = React81__default.forwardRef(
5597
5421
  ({
5598
5422
  className,
5599
5423
  min = 0,
@@ -6101,7 +5925,7 @@ var init_ContentSection = __esm({
6101
5925
  md: "py-16",
6102
5926
  lg: "py-24"
6103
5927
  };
6104
- ContentSection = React82__default.forwardRef(
5928
+ ContentSection = React81__default.forwardRef(
6105
5929
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
6106
5930
  return /* @__PURE__ */ jsx(
6107
5931
  Box,
@@ -6635,7 +6459,7 @@ var init_AnimatedReveal = __esm({
6635
6459
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
6636
6460
  "none": {}
6637
6461
  };
6638
- AnimatedReveal = React82__default.forwardRef(
6462
+ AnimatedReveal = React81__default.forwardRef(
6639
6463
  ({
6640
6464
  trigger = "scroll",
6641
6465
  animation = "fade-up",
@@ -6795,7 +6619,7 @@ var init_AnimatedGraphic = __esm({
6795
6619
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
6796
6620
  "use client";
6797
6621
  init_cn();
6798
- AnimatedGraphic = React82__default.forwardRef(
6622
+ AnimatedGraphic = React81__default.forwardRef(
6799
6623
  ({
6800
6624
  src,
6801
6625
  svgContent,
@@ -6818,7 +6642,7 @@ var init_AnimatedGraphic = __esm({
6818
6642
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
6819
6643
  const resolvedSvg = svgContent ?? fetchedSvg;
6820
6644
  const prevAnimateRef = useRef(animate);
6821
- const setRef = React82__default.useCallback(
6645
+ const setRef = React81__default.useCallback(
6822
6646
  (node) => {
6823
6647
  containerRef.current = node;
6824
6648
  if (typeof ref === "function") ref(node);
@@ -7044,9 +6868,9 @@ function ScoreDisplay({
7044
6868
  ...rest
7045
6869
  }) {
7046
6870
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof rest.score === "number" && !Number.isNaN(rest.score) ? rest.score : 0;
7047
- const [displayValue, setDisplayValue] = React82.useState(resolvedValue);
7048
- const [isAnimating, setIsAnimating] = React82.useState(false);
7049
- React82.useEffect(() => {
6871
+ const [displayValue, setDisplayValue] = React81.useState(resolvedValue);
6872
+ const [isAnimating, setIsAnimating] = React81.useState(false);
6873
+ React81.useEffect(() => {
7050
6874
  if (!animated || displayValue === resolvedValue) {
7051
6875
  setDisplayValue(resolvedValue);
7052
6876
  return;
@@ -7129,9 +6953,9 @@ function ControlButton({
7129
6953
  className
7130
6954
  }) {
7131
6955
  const eventBus = useEventBus();
7132
- const [isPressed, setIsPressed] = React82.useState(false);
6956
+ const [isPressed, setIsPressed] = React81.useState(false);
7133
6957
  const actualPressed = pressed ?? isPressed;
7134
- const handlePointerDown = React82.useCallback(
6958
+ const handlePointerDown = React81.useCallback(
7135
6959
  (e) => {
7136
6960
  e.preventDefault();
7137
6961
  if (disabled) return;
@@ -7141,7 +6965,7 @@ function ControlButton({
7141
6965
  },
7142
6966
  [disabled, pressEvent, eventBus, onPress]
7143
6967
  );
7144
- const handlePointerUp = React82.useCallback(
6968
+ const handlePointerUp = React81.useCallback(
7145
6969
  (e) => {
7146
6970
  e.preventDefault();
7147
6971
  if (disabled) return;
@@ -7151,7 +6975,7 @@ function ControlButton({
7151
6975
  },
7152
6976
  [disabled, releaseEvent, eventBus, onRelease]
7153
6977
  );
7154
- const handlePointerLeave = React82.useCallback(
6978
+ const handlePointerLeave = React81.useCallback(
7155
6979
  (e) => {
7156
6980
  if (isPressed) {
7157
6981
  setIsPressed(false);
@@ -7229,6 +7053,52 @@ var init_ControlButton = __esm({
7229
7053
  ControlButton.displayName = "ControlButton";
7230
7054
  }
7231
7055
  });
7056
+
7057
+ // components/game/organisms/utils/spriteAnimation.ts
7058
+ function inferDirection(dx, dy) {
7059
+ if (dx === 0 && dy === 0) return "se";
7060
+ if (dx >= 0 && dy >= 0) return "se";
7061
+ if (dx <= 0 && dy >= 0) return "sw";
7062
+ if (dx >= 0 && dy <= 0) return "ne";
7063
+ return "nw";
7064
+ }
7065
+ function resolveSheetDirection(facing) {
7066
+ switch (facing) {
7067
+ case "se":
7068
+ return { sheetDir: "se", flipX: false };
7069
+ case "sw":
7070
+ return { sheetDir: "sw", flipX: false };
7071
+ case "ne":
7072
+ return { sheetDir: "sw", flipX: true };
7073
+ case "nw":
7074
+ return { sheetDir: "se", flipX: true };
7075
+ }
7076
+ }
7077
+ function frameRect(frame, row, columns, frameWidth, frameHeight) {
7078
+ return {
7079
+ sx: frame % columns * frameWidth,
7080
+ sy: row * frameHeight,
7081
+ sw: frameWidth,
7082
+ sh: frameHeight
7083
+ };
7084
+ }
7085
+ function getCurrentFrameFromDef(def, elapsed) {
7086
+ const frameDuration = 1e3 / def.frameRate;
7087
+ const totalDuration = def.frames * frameDuration;
7088
+ if (def.loop) {
7089
+ const frame2 = Math.floor(elapsed % totalDuration / frameDuration);
7090
+ return { frame: frame2, finished: false };
7091
+ }
7092
+ if (elapsed >= totalDuration) {
7093
+ return { frame: def.frames - 1, finished: true };
7094
+ }
7095
+ const frame = Math.floor(elapsed / frameDuration);
7096
+ return { frame, finished: false };
7097
+ }
7098
+ var init_spriteAnimation = __esm({
7099
+ "components/game/organisms/utils/spriteAnimation.ts"() {
7100
+ }
7101
+ });
7232
7102
  function Sprite({
7233
7103
  spritesheet = "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
7234
7104
  frameWidth = 64,
@@ -7249,12 +7119,8 @@ function Sprite({
7249
7119
  }) {
7250
7120
  const eventBus = useEventBus();
7251
7121
  const sourcePosition = useMemo(() => {
7252
- const frameX = frame % columns;
7253
- const frameY = Math.floor(frame / columns);
7254
- return {
7255
- x: frameX * frameWidth,
7256
- y: frameY * frameHeight
7257
- };
7122
+ const { sx, sy } = frameRect(frame, Math.floor(frame / columns), columns, frameWidth, frameHeight);
7123
+ return { x: sx, y: sy };
7258
7124
  }, [frame, columns, frameWidth, frameHeight]);
7259
7125
  const transform = useMemo(() => {
7260
7126
  const transforms = [
@@ -7302,6 +7168,7 @@ var init_Sprite = __esm({
7302
7168
  "components/game/atoms/Sprite.tsx"() {
7303
7169
  "use client";
7304
7170
  init_useEventBus();
7171
+ init_spriteAnimation();
7305
7172
  }
7306
7173
  });
7307
7174
  function StateIndicator({
@@ -7729,8 +7596,8 @@ function XPBar({
7729
7596
  }) {
7730
7597
  const sizes = sizeMap9[size];
7731
7598
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
7732
- const [fillWidth, setFillWidth] = React82.useState(animated ? 0 : percentage);
7733
- React82.useEffect(() => {
7599
+ const [fillWidth, setFillWidth] = React81.useState(animated ? 0 : percentage);
7600
+ React81.useEffect(() => {
7734
7601
  if (!animated) {
7735
7602
  setFillWidth(percentage);
7736
7603
  return;
@@ -8218,9 +8085,9 @@ function MiniMap({
8218
8085
  viewportRect = DEFAULT_VIEWPORT,
8219
8086
  className
8220
8087
  }) {
8221
- const canvasRef = React82.useRef(null);
8222
- const frameRef = React82.useRef(0);
8223
- React82.useEffect(() => {
8088
+ const canvasRef = React81.useRef(null);
8089
+ const frameRef = React81.useRef(0);
8090
+ React81.useEffect(() => {
8224
8091
  const canvas = canvasRef.current;
8225
8092
  if (!canvas) return;
8226
8093
  const ctx = canvas.getContext("2d");
@@ -8409,7 +8276,7 @@ var init_ErrorBoundary = __esm({
8409
8276
  }
8410
8277
  );
8411
8278
  };
8412
- ErrorBoundary = class extends React82__default.Component {
8279
+ ErrorBoundary = class extends React81__default.Component {
8413
8280
  constructor(props) {
8414
8281
  super(props);
8415
8282
  __publicField(this, "reset", () => {
@@ -9444,8 +9311,8 @@ function ActionButtons({
9444
9311
  disabled
9445
9312
  }) {
9446
9313
  const eventBus = useEventBus();
9447
- const [activeButtons, setActiveButtons] = React82.useState(/* @__PURE__ */ new Set());
9448
- const handlePress = React82.useCallback(
9314
+ const [activeButtons, setActiveButtons] = React81.useState(/* @__PURE__ */ new Set());
9315
+ const handlePress = React81.useCallback(
9449
9316
  (id) => {
9450
9317
  setActiveButtons((prev) => new Set(prev).add(id));
9451
9318
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -9453,7 +9320,7 @@ function ActionButtons({
9453
9320
  },
9454
9321
  [actionEvent, eventBus, onAction]
9455
9322
  );
9456
- const handleRelease = React82.useCallback(
9323
+ const handleRelease = React81.useCallback(
9457
9324
  (id) => {
9458
9325
  setActiveButtons((prev) => {
9459
9326
  const next = new Set(prev);
@@ -10365,7 +10232,7 @@ function recordTransition(trace) {
10365
10232
  ...trace,
10366
10233
  id: `t-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
10367
10234
  };
10368
- log5.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
10235
+ log4.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
10369
10236
  getState().transitions.push(entry);
10370
10237
  if (getState().transitions.length > MAX_TRANSITIONS) {
10371
10238
  getState().transitions.shift();
@@ -10464,7 +10331,7 @@ function getTraitSnapshots() {
10464
10331
  try {
10465
10332
  snapshots.push(getter());
10466
10333
  } catch (err) {
10467
- log5.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
10334
+ log4.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
10468
10335
  }
10469
10336
  }
10470
10337
  return snapshots;
@@ -10563,10 +10430,10 @@ function updateAssetStatus(url, status) {
10563
10430
  window.__orbitalVerification.assetStatus[url] = status;
10564
10431
  }
10565
10432
  }
10566
- var log5, MAX_TRANSITIONS;
10433
+ var log4, MAX_TRANSITIONS;
10567
10434
  var init_verificationRegistry = __esm({
10568
10435
  "lib/verificationRegistry.ts"() {
10569
- log5 = createLogger("almadar:bridge");
10436
+ log4 = createLogger("almadar:bridge");
10570
10437
  MAX_TRANSITIONS = 500;
10571
10438
  exposeOnWindow();
10572
10439
  }
@@ -10693,6 +10560,163 @@ var init_useCamera = __esm({
10693
10560
  "use client";
10694
10561
  }
10695
10562
  });
10563
+ function unitAtlasUrl(unit) {
10564
+ if (unit.spriteSheet) return unit.spriteSheet;
10565
+ const sprite = unit.sprite;
10566
+ if (!sprite) return null;
10567
+ const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
10568
+ if (!match) return null;
10569
+ return `${match[1]}.json`;
10570
+ }
10571
+ function resolveSheetUrl(atlasUrl, relativeSheetPath) {
10572
+ try {
10573
+ return new URL(relativeSheetPath, atlasUrl).toString();
10574
+ } catch {
10575
+ const base = atlasUrl.slice(0, atlasUrl.lastIndexOf("/") + 1);
10576
+ return `${base}${relativeSheetPath.replace(/^\.\//, "")}`;
10577
+ }
10578
+ }
10579
+ function useUnitSpriteAtlas(units) {
10580
+ const atlasCacheRef = useRef(/* @__PURE__ */ new Map());
10581
+ const loadingRef = useRef(/* @__PURE__ */ new Set());
10582
+ const [pendingCount, setPendingCount] = useState(0);
10583
+ const [, forceTick] = useState(0);
10584
+ const animStatesRef = useRef(/* @__PURE__ */ new Map());
10585
+ const lastTickRef = useRef(0);
10586
+ const rafRef = useRef(0);
10587
+ const atlasUrls = useMemo(() => {
10588
+ const set = /* @__PURE__ */ new Set();
10589
+ for (const unit of units) {
10590
+ const url = unitAtlasUrl(unit);
10591
+ if (url) set.add(url);
10592
+ }
10593
+ return [...set];
10594
+ }, [units]);
10595
+ useEffect(() => {
10596
+ const cache = atlasCacheRef.current;
10597
+ const loading = loadingRef.current;
10598
+ const toLoad = atlasUrls.filter((url) => !cache.has(url) && !loading.has(url));
10599
+ if (toLoad.length === 0) return;
10600
+ let cancelled = false;
10601
+ setPendingCount((prev) => prev + toLoad.length);
10602
+ for (const url of toLoad) {
10603
+ loading.add(url);
10604
+ fetch(url).then((res) => res.ok ? res.json() : Promise.reject(new Error(String(res.status)))).then((atlas) => {
10605
+ if (cancelled) return;
10606
+ cache.set(url, atlas);
10607
+ }).catch(() => {
10608
+ }).finally(() => {
10609
+ if (cancelled) return;
10610
+ loading.delete(url);
10611
+ setPendingCount((prev) => Math.max(0, prev - 1));
10612
+ forceTick((n) => n + 1);
10613
+ });
10614
+ }
10615
+ return () => {
10616
+ cancelled = true;
10617
+ };
10618
+ }, [atlasUrls]);
10619
+ const sheetUrls = useMemo(() => {
10620
+ const urls = /* @__PURE__ */ new Set();
10621
+ for (const unit of units) {
10622
+ const atlasUrl = unitAtlasUrl(unit);
10623
+ if (!atlasUrl) continue;
10624
+ const atlas = atlasCacheRef.current.get(atlasUrl);
10625
+ if (!atlas) continue;
10626
+ for (const rel of Object.values(atlas.sheets)) {
10627
+ if (rel) urls.add(resolveSheetUrl(atlasUrl, rel));
10628
+ }
10629
+ }
10630
+ return [...urls];
10631
+ }, [units, pendingCount]);
10632
+ useEffect(() => {
10633
+ const hasAtlasUnits = units.some((u) => unitAtlasUrl(u) !== null);
10634
+ if (!hasAtlasUnits) return;
10635
+ let running = true;
10636
+ const tick = (ts) => {
10637
+ if (!running) return;
10638
+ const last = lastTickRef.current || ts;
10639
+ const delta = ts - last;
10640
+ lastTickRef.current = ts;
10641
+ const states = animStatesRef.current;
10642
+ const currentIds = /* @__PURE__ */ new Set();
10643
+ for (const unit of units) {
10644
+ if (unitAtlasUrl(unit) === null) continue;
10645
+ currentIds.add(unit.id);
10646
+ let state = states.get(unit.id);
10647
+ if (!state) {
10648
+ state = { animation: "idle", direction: "se", elapsed: 0, walkHold: 0, prev: null };
10649
+ states.set(unit.id, state);
10650
+ }
10651
+ const posX = unit.position?.x ?? unit.x ?? 0;
10652
+ const posY = unit.position?.y ?? unit.y ?? 0;
10653
+ if (state.prev) {
10654
+ const dx = posX - state.prev.x;
10655
+ const dy = posY - state.prev.y;
10656
+ if (dx !== 0 || dy !== 0) {
10657
+ state.animation = "walk";
10658
+ state.direction = inferDirection(dx, dy);
10659
+ state.walkHold = WALK_HOLD_MS;
10660
+ } else if (state.animation === "walk") {
10661
+ state.walkHold -= delta;
10662
+ if (state.walkHold <= 0) state.animation = "idle";
10663
+ }
10664
+ }
10665
+ state.prev = { x: posX, y: posY };
10666
+ state.elapsed += delta;
10667
+ }
10668
+ for (const id of states.keys()) {
10669
+ if (!currentIds.has(id)) states.delete(id);
10670
+ }
10671
+ rafRef.current = requestAnimationFrame(tick);
10672
+ };
10673
+ rafRef.current = requestAnimationFrame(tick);
10674
+ return () => {
10675
+ running = false;
10676
+ cancelAnimationFrame(rafRef.current);
10677
+ lastTickRef.current = 0;
10678
+ };
10679
+ }, [units]);
10680
+ const resolveUnitFrame = useCallback((unitId) => {
10681
+ const unit = units.find((u) => u.id === unitId);
10682
+ if (!unit) return null;
10683
+ const atlasUrl = unitAtlasUrl(unit);
10684
+ if (!atlasUrl) return null;
10685
+ const atlas = atlasCacheRef.current.get(atlasUrl);
10686
+ if (!atlas) return null;
10687
+ const state = animStatesRef.current.get(unitId);
10688
+ const animation = state?.animation ?? "idle";
10689
+ const direction = state?.direction ?? "se";
10690
+ const elapsed = state?.elapsed ?? 0;
10691
+ const def = atlas.animations[animation] ?? atlas.animations.idle;
10692
+ if (!def) return null;
10693
+ const { sheetDir, flipX } = resolveSheetDirection(direction);
10694
+ const rel = atlas.sheets[sheetDir] ?? atlas.sheets.se ?? atlas.sheets.sw;
10695
+ if (!rel) return null;
10696
+ const sheetUrl = resolveSheetUrl(atlasUrl, rel);
10697
+ const isIdle = animation === "idle";
10698
+ const frame = isIdle ? 0 : getCurrentFrameFromDef(def, elapsed).frame;
10699
+ const rect = frameRect(frame, def.row, atlas.columns, atlas.frameWidth, atlas.frameHeight);
10700
+ return {
10701
+ sheetUrl,
10702
+ sx: rect.sx,
10703
+ sy: rect.sy,
10704
+ sw: rect.sw,
10705
+ sh: rect.sh,
10706
+ flipX,
10707
+ applyBreathing: isIdle
10708
+ };
10709
+ }, [units]);
10710
+ return { sheetUrls, resolveUnitFrame, pendingCount };
10711
+ }
10712
+ var WALK_HOLD_MS;
10713
+ var init_useUnitSpriteAtlas = __esm({
10714
+ "components/game/molecules/useUnitSpriteAtlas.ts"() {
10715
+ "use client";
10716
+ init_spriteAnimation();
10717
+ WALK_HOLD_MS = 600;
10718
+ }
10719
+ });
10696
10720
 
10697
10721
  // components/game/organisms/utils/isometric.ts
10698
10722
  function isoToScreen(tileX, tileY, scale, baseOffsetX) {
@@ -10807,6 +10831,10 @@ function IsometricCanvas({
10807
10831
  () => unitsProp.map((u) => u.position ? u : { ...u, position: { x: u.x ?? 0, y: u.y ?? 0 } }),
10808
10832
  [unitsProp]
10809
10833
  );
10834
+ const { sheetUrls: atlasSheetUrls, resolveUnitFrame: resolveUnitFrameInternal, pendingCount: atlasPending } = useUnitSpriteAtlas(units);
10835
+ const resolveFrameForUnit = useCallback((unitId) => {
10836
+ return resolveUnitFrame?.(unitId) ?? resolveUnitFrameInternal(unitId);
10837
+ }, [resolveUnitFrame, resolveUnitFrameInternal]);
10810
10838
  const features = useMemo(
10811
10839
  () => featuresProp.map((f3) => {
10812
10840
  if (f3.type) return f3;
@@ -10890,9 +10918,10 @@ function IsometricCanvas({
10890
10918
  }
10891
10919
  }
10892
10920
  if (effectSpriteUrls) urls.push(...effectSpriteUrls);
10921
+ if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
10893
10922
  if (backgroundImage) urls.push(backgroundImage);
10894
10923
  return [...new Set(urls.filter(Boolean))];
10895
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, backgroundImage, assetManifest, resolveManifestUrl]);
10924
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl]);
10896
10925
  const { getImage, pendingCount } = useImageCache(spriteUrls);
10897
10926
  useEffect(() => {
10898
10927
  if (typeof window === "undefined") return;
@@ -11179,7 +11208,7 @@ function IsometricCanvas({
11179
11208
  ctx.lineWidth = 3;
11180
11209
  ctx.stroke();
11181
11210
  }
11182
- const frame = resolveUnitFrame?.(unit.id) ?? null;
11211
+ const frame = resolveFrameForUnit(unit.id);
11183
11212
  const frameImg = frame ? getImage(frame.sheetUrl) : null;
11184
11213
  if (frame && frameImg) {
11185
11214
  const frameAr = frame.sw / frame.sh;
@@ -11289,7 +11318,7 @@ function IsometricCanvas({
11289
11318
  resolveTerrainSpriteUrl,
11290
11319
  resolveFeatureSpriteUrl,
11291
11320
  resolveUnitSpriteUrl,
11292
- resolveUnitFrame,
11321
+ resolveFrameForUnit,
11293
11322
  getImage,
11294
11323
  gridWidth,
11295
11324
  gridHeight,
@@ -11321,7 +11350,7 @@ function IsometricCanvas({
11321
11350
  };
11322
11351
  }, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
11323
11352
  useEffect(() => {
11324
- const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0;
11353
+ const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
11325
11354
  draw(animTimeRef.current);
11326
11355
  if (!hasAnimations) return;
11327
11356
  let running = true;
@@ -11337,7 +11366,7 @@ function IsometricCanvas({
11337
11366
  running = false;
11338
11367
  cancelAnimationFrame(rafIdRef.current);
11339
11368
  };
11340
- }, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, lerpToTarget, targetCameraRef]);
11369
+ }, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, atlasPending, lerpToTarget, targetCameraRef]);
11341
11370
  const handleMouseMoveWithCamera = useCallback((e) => {
11342
11371
  if (enableCamera) {
11343
11372
  const wasPanning = handleMouseMove(e, () => draw(animTimeRef.current));
@@ -11482,6 +11511,7 @@ var init_IsometricCanvas = __esm({
11482
11511
  init_ErrorState();
11483
11512
  init_useImageCache();
11484
11513
  init_useCamera();
11514
+ init_useUnitSpriteAtlas();
11485
11515
  init_verificationRegistry();
11486
11516
  init_isometric();
11487
11517
  IsometricCanvas.displayName = "IsometricCanvas";
@@ -12697,7 +12727,7 @@ var init_avl_elk_layout = __esm({
12697
12727
  elk = new ELK();
12698
12728
  }
12699
12729
  });
12700
- var log6, SWIM_GUTTER, CENTER_W, BehaviorView;
12730
+ var log5, SWIM_GUTTER, CENTER_W, BehaviorView;
12701
12731
  var init_BehaviorView = __esm({
12702
12732
  "components/avl/molecules/BehaviorView.tsx"() {
12703
12733
  "use client";
@@ -12706,7 +12736,7 @@ var init_BehaviorView = __esm({
12706
12736
  init_AvlSwimLane();
12707
12737
  init_types();
12708
12738
  init_avl_elk_layout();
12709
- log6 = createLogger("almadar:ui:avl:behavior-view");
12739
+ log5 = createLogger("almadar:ui:avl:behavior-view");
12710
12740
  SWIM_GUTTER = 120;
12711
12741
  CENTER_W = 360;
12712
12742
  BehaviorView = ({ data }) => {
@@ -12717,7 +12747,7 @@ var init_BehaviorView = __esm({
12717
12747
  const dataKey = useMemo(() => JSON.stringify(traitData), [traitData]);
12718
12748
  useEffect(() => {
12719
12749
  if (!traitData) return;
12720
- computeTraitLayout(traitData).then(setLayout).catch((err) => log6.error("compute-trait-layout-failed", { error: err instanceof Error ? err : String(err) }));
12750
+ computeTraitLayout(traitData).then(setLayout).catch((err) => log5.error("compute-trait-layout-failed", { error: err instanceof Error ? err : String(err) }));
12721
12751
  }, [dataKey]);
12722
12752
  if (!traitData) {
12723
12753
  return /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-[var(--color-border)] bg-[var(--color-card)] p-4 text-center text-[var(--color-muted-foreground)] text-sm", children: t("avl.noTraitData") });
@@ -13128,7 +13158,7 @@ function generateDiff(oldVal, newVal) {
13128
13158
  }
13129
13159
  return diff;
13130
13160
  }
13131
- var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log7, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
13161
+ var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log6, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
13132
13162
  var init_CodeBlock = __esm({
13133
13163
  "components/core/molecules/markdown/CodeBlock.tsx"() {
13134
13164
  init_cn();
@@ -13211,7 +13241,7 @@ var init_CodeBlock = __esm({
13211
13241
  "lolo-op-async": { color: ORB_COLORS.dark.async }
13212
13242
  };
13213
13243
  loloStyle = { ...dark, ...loloStyleOverrides };
13214
- log7 = createLogger("almadar:ui:markdown-code");
13244
+ log6 = createLogger("almadar:ui:markdown-code");
13215
13245
  CODE_LANGUAGES = [
13216
13246
  "text",
13217
13247
  "json",
@@ -13250,7 +13280,7 @@ var init_CodeBlock = __esm({
13250
13280
  };
13251
13281
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
13252
13282
  HIDDEN_LINE_NUMBERS = { display: "none" };
13253
- CodeBlock = React82__default.memo(
13283
+ CodeBlock = React81__default.memo(
13254
13284
  ({
13255
13285
  code: rawCode,
13256
13286
  language = "text",
@@ -13475,7 +13505,7 @@ var init_CodeBlock = __esm({
13475
13505
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: true });
13476
13506
  setTimeout(() => setCopied(false), 2e3);
13477
13507
  } catch (err) {
13478
- log7.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
13508
+ log6.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
13479
13509
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: false });
13480
13510
  }
13481
13511
  };
@@ -13837,7 +13867,7 @@ var init_MarkdownContent = __esm({
13837
13867
  init_Box();
13838
13868
  init_CodeBlock();
13839
13869
  init_cn();
13840
- MarkdownContent = React82__default.memo(
13870
+ MarkdownContent = React81__default.memo(
13841
13871
  ({ content, direction = "ltr", className }) => {
13842
13872
  const { t: _t } = useTranslate();
13843
13873
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -15154,7 +15184,7 @@ var init_StateMachineView = __esm({
15154
15184
  style: { top: title ? 30 : 0 },
15155
15185
  children: [
15156
15186
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
15157
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React82__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
15187
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React81__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
15158
15188
  StateNode,
15159
15189
  {
15160
15190
  state,
@@ -17356,14 +17386,14 @@ function useSafeEventBus2() {
17356
17386
  } };
17357
17387
  }
17358
17388
  }
17359
- var log8, lookStyles4, ButtonGroup;
17389
+ var log7, lookStyles4, ButtonGroup;
17360
17390
  var init_ButtonGroup = __esm({
17361
17391
  "components/core/molecules/ButtonGroup.tsx"() {
17362
17392
  "use client";
17363
17393
  init_cn();
17364
17394
  init_atoms2();
17365
17395
  init_useEventBus();
17366
- log8 = createLogger("almadar:ui:button-group");
17396
+ log7 = createLogger("almadar:ui:button-group");
17367
17397
  lookStyles4 = {
17368
17398
  "right-aligned-buttons": "",
17369
17399
  "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
@@ -17444,7 +17474,7 @@ var init_ButtonGroup = __esm({
17444
17474
  {
17445
17475
  variant: "ghost",
17446
17476
  onClick: () => {
17447
- log8.debug("Filter clicked", { field: filter.field });
17477
+ log7.debug("Filter clicked", { field: filter.field });
17448
17478
  },
17449
17479
  children: filter.label
17450
17480
  },
@@ -21695,7 +21725,7 @@ function CraftingRecipe({
21695
21725
  className
21696
21726
  }) {
21697
21727
  const eventBus = useEventBus();
21698
- const handleCraft = React82.useCallback(() => {
21728
+ const handleCraft = React81.useCallback(() => {
21699
21729
  onCraft?.();
21700
21730
  if (craftEvent) {
21701
21731
  eventBus.emit(craftEvent, { output: output.label });
@@ -21712,7 +21742,7 @@ function CraftingRecipe({
21712
21742
  children: [
21713
21743
  /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap items-center", children: inputs.map((ingredient, index) => {
21714
21744
  const hasSufficient = ingredient.available >= ingredient.required;
21715
- return /* @__PURE__ */ jsxs(React82.Fragment, { children: [
21745
+ return /* @__PURE__ */ jsxs(React81.Fragment, { children: [
21716
21746
  /* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
21717
21747
  ItemSlot,
21718
21748
  {
@@ -21784,8 +21814,8 @@ function DPad({
21784
21814
  }) {
21785
21815
  const eventBus = useEventBus();
21786
21816
  const sizes = sizeMap15[size];
21787
- const [activeDirections, setActiveDirections] = React82.useState(/* @__PURE__ */ new Set());
21788
- const handlePress = React82.useCallback(
21817
+ const [activeDirections, setActiveDirections] = React81.useState(/* @__PURE__ */ new Set());
21818
+ const handlePress = React81.useCallback(
21789
21819
  (direction) => {
21790
21820
  setActiveDirections((prev) => new Set(prev).add(direction));
21791
21821
  if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
@@ -21793,7 +21823,7 @@ function DPad({
21793
21823
  },
21794
21824
  [directionEvent, eventBus, onDirection]
21795
21825
  );
21796
- const handleRelease = React82.useCallback(
21826
+ const handleRelease = React81.useCallback(
21797
21827
  (direction) => {
21798
21828
  setActiveDirections((prev) => {
21799
21829
  const next = new Set(prev);
@@ -22600,8 +22630,8 @@ var init_Menu = __esm({
22600
22630
  "bottom-end": "bottom-start"
22601
22631
  };
22602
22632
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
22603
- const triggerChild = React82__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
22604
- const triggerElement = React82__default.cloneElement(
22633
+ const triggerChild = React81__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
22634
+ const triggerElement = React81__default.cloneElement(
22605
22635
  triggerChild,
22606
22636
  {
22607
22637
  ref: triggerRef,
@@ -22735,14 +22765,14 @@ function useDataDnd(args) {
22735
22765
  const isZone = Boolean(dragGroup || accepts || sortable);
22736
22766
  const enabled = isZone || Boolean(dndRoot);
22737
22767
  const eventBus = useEventBus();
22738
- const parentRoot = React82__default.useContext(RootCtx);
22768
+ const parentRoot = React81__default.useContext(RootCtx);
22739
22769
  const isRoot = enabled && parentRoot === null;
22740
- const zoneId = React82__default.useId();
22770
+ const zoneId = React81__default.useId();
22741
22771
  const ownGroup = dragGroup ?? accepts ?? zoneId;
22742
- const [optimisticOrders, setOptimisticOrders] = React82__default.useState(() => /* @__PURE__ */ new Map());
22743
- const optimisticOrdersRef = React82__default.useRef(optimisticOrders);
22772
+ const [optimisticOrders, setOptimisticOrders] = React81__default.useState(() => /* @__PURE__ */ new Map());
22773
+ const optimisticOrdersRef = React81__default.useRef(optimisticOrders);
22744
22774
  optimisticOrdersRef.current = optimisticOrders;
22745
- const clearOptimisticOrder = React82__default.useCallback((group) => {
22775
+ const clearOptimisticOrder = React81__default.useCallback((group) => {
22746
22776
  setOptimisticOrders((prev) => {
22747
22777
  if (!prev.has(group)) return prev;
22748
22778
  const next = new Map(prev);
@@ -22767,7 +22797,7 @@ function useDataDnd(args) {
22767
22797
  const raw = it[dndItemIdField];
22768
22798
  return String(raw ?? `__idx_${idx}`);
22769
22799
  }).join("|");
22770
- const itemIds = React82__default.useMemo(
22800
+ const itemIds = React81__default.useMemo(
22771
22801
  () => orderedItems.map((it, idx) => {
22772
22802
  const raw = it[dndItemIdField];
22773
22803
  return raw ?? `__idx_${idx}`;
@@ -22775,7 +22805,7 @@ function useDataDnd(args) {
22775
22805
  [itemIdsSignature]
22776
22806
  );
22777
22807
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
22778
- React82__default.useEffect(() => {
22808
+ React81__default.useEffect(() => {
22779
22809
  const root = isRoot ? null : parentRoot;
22780
22810
  if (root) {
22781
22811
  root.clearOptimisticOrder(ownGroup);
@@ -22783,20 +22813,20 @@ function useDataDnd(args) {
22783
22813
  clearOptimisticOrder(ownGroup);
22784
22814
  }
22785
22815
  }, [itemsContentSig, ownGroup]);
22786
- const zonesRef = React82__default.useRef(/* @__PURE__ */ new Map());
22787
- const registerZone = React82__default.useCallback((zoneId2, meta2) => {
22816
+ const zonesRef = React81__default.useRef(/* @__PURE__ */ new Map());
22817
+ const registerZone = React81__default.useCallback((zoneId2, meta2) => {
22788
22818
  zonesRef.current.set(zoneId2, meta2);
22789
22819
  }, []);
22790
- const unregisterZone = React82__default.useCallback((zoneId2) => {
22820
+ const unregisterZone = React81__default.useCallback((zoneId2) => {
22791
22821
  zonesRef.current.delete(zoneId2);
22792
22822
  }, []);
22793
- const [activeDrag, setActiveDrag] = React82__default.useState(null);
22794
- const [overZoneGroup, setOverZoneGroup] = React82__default.useState(null);
22795
- const meta = React82__default.useMemo(
22823
+ const [activeDrag, setActiveDrag] = React81__default.useState(null);
22824
+ const [overZoneGroup, setOverZoneGroup] = React81__default.useState(null);
22825
+ const meta = React81__default.useMemo(
22796
22826
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
22797
22827
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
22798
22828
  );
22799
- React82__default.useEffect(() => {
22829
+ React81__default.useEffect(() => {
22800
22830
  const target = isRoot ? null : parentRoot;
22801
22831
  if (!target) {
22802
22832
  zonesRef.current.set(zoneId, meta);
@@ -22815,7 +22845,7 @@ function useDataDnd(args) {
22815
22845
  }, [parentRoot, isRoot, zoneId, meta]);
22816
22846
  const sensors = useAlmadarDndSensors(true);
22817
22847
  const collisionDetection = almadarDndCollisionDetection;
22818
- const findZoneByItem = React82__default.useCallback(
22848
+ const findZoneByItem = React81__default.useCallback(
22819
22849
  (id) => {
22820
22850
  for (const z of zonesRef.current.values()) {
22821
22851
  if (z.itemIds.includes(id)) return z;
@@ -22824,7 +22854,7 @@ function useDataDnd(args) {
22824
22854
  },
22825
22855
  []
22826
22856
  );
22827
- React82__default.useCallback(
22857
+ React81__default.useCallback(
22828
22858
  (group) => {
22829
22859
  for (const z of zonesRef.current.values()) {
22830
22860
  if (z.group === group) return z;
@@ -22833,7 +22863,7 @@ function useDataDnd(args) {
22833
22863
  },
22834
22864
  []
22835
22865
  );
22836
- const handleDragEnd = React82__default.useCallback(
22866
+ const handleDragEnd = React81__default.useCallback(
22837
22867
  (event) => {
22838
22868
  const { active, over } = event;
22839
22869
  const activeIdStr = String(active.id);
@@ -22924,8 +22954,8 @@ function useDataDnd(args) {
22924
22954
  },
22925
22955
  [eventBus]
22926
22956
  );
22927
- const sortableData = React82__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
22928
- const SortableItem = React82__default.useCallback(
22957
+ const sortableData = React81__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
22958
+ const SortableItem = React81__default.useCallback(
22929
22959
  ({ id, children }) => {
22930
22960
  const {
22931
22961
  attributes,
@@ -22965,7 +22995,7 @@ function useDataDnd(args) {
22965
22995
  id: droppableId,
22966
22996
  data: sortableData
22967
22997
  });
22968
- const ctx = React82__default.useContext(RootCtx);
22998
+ const ctx = React81__default.useContext(RootCtx);
22969
22999
  const activeDrag2 = ctx?.activeDrag ?? null;
22970
23000
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
22971
23001
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -22980,7 +23010,7 @@ function useDataDnd(args) {
22980
23010
  showForeignPlaceholder,
22981
23011
  ctxAvailable: ctx != null
22982
23012
  });
22983
- React82__default.useEffect(() => {
23013
+ React81__default.useEffect(() => {
22984
23014
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
22985
23015
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
22986
23016
  return /* @__PURE__ */ jsx(
@@ -22994,11 +23024,11 @@ function useDataDnd(args) {
22994
23024
  }
22995
23025
  );
22996
23026
  };
22997
- const rootContextValue = React82__default.useMemo(
23027
+ const rootContextValue = React81__default.useMemo(
22998
23028
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
22999
23029
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
23000
23030
  );
23001
- const handleDragStart = React82__default.useCallback((event) => {
23031
+ const handleDragStart = React81__default.useCallback((event) => {
23002
23032
  const sourceZone = findZoneByItem(event.active.id);
23003
23033
  const rect = event.active.rect.current.initial;
23004
23034
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -23017,7 +23047,7 @@ function useDataDnd(args) {
23017
23047
  isRoot
23018
23048
  });
23019
23049
  }, [findZoneByItem, isRoot, zoneId]);
23020
- const handleDragOver = React82__default.useCallback((event) => {
23050
+ const handleDragOver = React81__default.useCallback((event) => {
23021
23051
  const { active, over } = event;
23022
23052
  const overData = over?.data?.current;
23023
23053
  const overGroup = overData?.dndGroup ?? null;
@@ -23087,7 +23117,7 @@ function useDataDnd(args) {
23087
23117
  return next;
23088
23118
  });
23089
23119
  }, []);
23090
- const handleDragCancel = React82__default.useCallback((event) => {
23120
+ const handleDragCancel = React81__default.useCallback((event) => {
23091
23121
  setActiveDrag(null);
23092
23122
  setOverZoneGroup(null);
23093
23123
  dndLog.warn("dragCancel", {
@@ -23095,12 +23125,12 @@ function useDataDnd(args) {
23095
23125
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
23096
23126
  });
23097
23127
  }, []);
23098
- const handleDragEndWithCleanup = React82__default.useCallback((event) => {
23128
+ const handleDragEndWithCleanup = React81__default.useCallback((event) => {
23099
23129
  handleDragEnd(event);
23100
23130
  setActiveDrag(null);
23101
23131
  setOverZoneGroup(null);
23102
23132
  }, [handleDragEnd]);
23103
- const wrapContainer = React82__default.useCallback(
23133
+ const wrapContainer = React81__default.useCallback(
23104
23134
  (children) => {
23105
23135
  if (!enabled) return children;
23106
23136
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -23154,7 +23184,7 @@ var init_useDataDnd = __esm({
23154
23184
  init_useAlmadarDndCollision();
23155
23185
  init_Box();
23156
23186
  dndLog = createLogger("almadar:ui:dnd");
23157
- RootCtx = React82__default.createContext(null);
23187
+ RootCtx = React81__default.createContext(null);
23158
23188
  }
23159
23189
  });
23160
23190
  function renderIconInput(icon, props) {
@@ -23680,7 +23710,7 @@ function DataList({
23680
23710
  }) {
23681
23711
  const eventBus = useEventBus();
23682
23712
  const { t } = useTranslate();
23683
- const [visibleCount, setVisibleCount] = React82__default.useState(pageSize || Infinity);
23713
+ const [visibleCount, setVisibleCount] = React81__default.useState(pageSize || Infinity);
23684
23714
  const fieldDefs = fields ?? columns ?? [];
23685
23715
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
23686
23716
  const dnd = useDataDnd({
@@ -23699,7 +23729,7 @@ function DataList({
23699
23729
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
23700
23730
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
23701
23731
  const hasRenderProp = typeof children === "function";
23702
- React82__default.useEffect(() => {
23732
+ React81__default.useEffect(() => {
23703
23733
  const renderItemTypeOf = typeof schemaRenderItem;
23704
23734
  const childrenTypeOf = typeof children;
23705
23735
  if (data.length > 0 && !hasRenderProp) {
@@ -23804,7 +23834,7 @@ function DataList({
23804
23834
  const items2 = data.map((item) => item);
23805
23835
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
23806
23836
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
23807
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
23837
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React81__default.Fragment, { children: [
23808
23838
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
23809
23839
  group.items.map((itemData, index) => {
23810
23840
  const id = itemData.id || `${gi}-${index}`;
@@ -23945,7 +23975,7 @@ function DataList({
23945
23975
  className
23946
23976
  ),
23947
23977
  children: [
23948
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
23978
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React81__default.Fragment, { children: [
23949
23979
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
23950
23980
  group.items.map(
23951
23981
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -24861,7 +24891,7 @@ var init_Grid = __esm({
24861
24891
  as: Component2 = "div"
24862
24892
  }) => {
24863
24893
  const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
24864
- return React82__default.createElement(
24894
+ return React81__default.createElement(
24865
24895
  Component2,
24866
24896
  {
24867
24897
  className: cn(
@@ -25049,8 +25079,8 @@ var init_Popover = __esm({
25049
25079
  onMouseEnter: handleOpen,
25050
25080
  onMouseLeave: handleClose
25051
25081
  };
25052
- const childElement = React82__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25053
- const triggerElement = React82__default.cloneElement(
25082
+ const childElement = React81__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25083
+ const triggerElement = React81__default.cloneElement(
25054
25084
  childElement,
25055
25085
  {
25056
25086
  ref: triggerRef,
@@ -25106,9 +25136,9 @@ function debug(...args) {
25106
25136
  const [first, ...rest] = args;
25107
25137
  const message = typeof first === "string" ? first : "<debug>";
25108
25138
  if (rest.length === 0 && typeof first === "string") {
25109
- log9.debug(message);
25139
+ log8.debug(message);
25110
25140
  } else {
25111
- log9.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
25141
+ log8.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
25112
25142
  }
25113
25143
  }
25114
25144
  function debugGroup(label) {
@@ -25136,11 +25166,11 @@ function toLogMetaValue(v) {
25136
25166
  }
25137
25167
  return String(v);
25138
25168
  }
25139
- var NAMESPACE, log9;
25169
+ var NAMESPACE, log8;
25140
25170
  var init_debug = __esm({
25141
25171
  "lib/debug.ts"() {
25142
25172
  NAMESPACE = "almadar:ui:debug";
25143
- log9 = createLogger(NAMESPACE);
25173
+ log8 = createLogger(NAMESPACE);
25144
25174
  createLogger("almadar:ui:debug:input");
25145
25175
  createLogger("almadar:ui:debug:collision");
25146
25176
  createLogger("almadar:ui:debug:physics");
@@ -25640,8 +25670,8 @@ var init_Tooltip = __esm({
25640
25670
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
25641
25671
  };
25642
25672
  }, []);
25643
- const triggerElement = React82__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25644
- const trigger = React82__default.cloneElement(triggerElement, {
25673
+ const triggerElement = React81__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25674
+ const trigger = React81__default.cloneElement(triggerElement, {
25645
25675
  ref: triggerRef,
25646
25676
  onMouseEnter: handleMouseEnter,
25647
25677
  onMouseLeave: handleMouseLeave,
@@ -25727,7 +25757,7 @@ var init_WizardProgress = __esm({
25727
25757
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
25728
25758
  const isActive = index === currentStep;
25729
25759
  const isCompleted = index < currentStep;
25730
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
25760
+ return /* @__PURE__ */ jsxs(React81__default.Fragment, { children: [
25731
25761
  /* @__PURE__ */ jsx(
25732
25762
  "button",
25733
25763
  {
@@ -26791,7 +26821,7 @@ function InventoryGrid({
26791
26821
  const eventBus = useEventBus();
26792
26822
  const slotCount = totalSlots ?? items.length;
26793
26823
  const emptySlotCount = Math.max(0, slotCount - items.length);
26794
- const handleSelect = React82.useCallback(
26824
+ const handleSelect = React81.useCallback(
26795
26825
  (id) => {
26796
26826
  onSelect?.(id);
26797
26827
  if (selectEvent) {
@@ -27025,31 +27055,31 @@ function GameCanvas2D({
27025
27055
  assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
27026
27056
  className
27027
27057
  }) {
27028
- const canvasRef = React82.useRef(null);
27029
- const rafRef = React82.useRef(0);
27030
- const frameRef = React82.useRef(0);
27031
- const lastTimeRef = React82.useRef(0);
27032
- const imageCache = React82.useRef(/* @__PURE__ */ new Map());
27058
+ const canvasRef = React81.useRef(null);
27059
+ const rafRef = React81.useRef(0);
27060
+ const frameRef = React81.useRef(0);
27061
+ const lastTimeRef = React81.useRef(0);
27062
+ const imageCache = React81.useRef(/* @__PURE__ */ new Map());
27033
27063
  const emit = useEmitEvent();
27034
- const onDrawRef = React82.useRef(onDraw);
27064
+ const onDrawRef = React81.useRef(onDraw);
27035
27065
  onDrawRef.current = onDraw;
27036
- const onTickRef = React82.useRef(onTick);
27066
+ const onTickRef = React81.useRef(onTick);
27037
27067
  onTickRef.current = onTick;
27038
- const tickEventRef = React82.useRef(tickEvent);
27068
+ const tickEventRef = React81.useRef(tickEvent);
27039
27069
  tickEventRef.current = tickEvent;
27040
- const drawEventRef = React82.useRef(drawEvent);
27070
+ const drawEventRef = React81.useRef(drawEvent);
27041
27071
  drawEventRef.current = drawEvent;
27042
- const emitRef = React82.useRef(emit);
27072
+ const emitRef = React81.useRef(emit);
27043
27073
  emitRef.current = emit;
27044
- const assetBaseUrlRef = React82.useRef(assetBaseUrl);
27074
+ const assetBaseUrlRef = React81.useRef(assetBaseUrl);
27045
27075
  assetBaseUrlRef.current = assetBaseUrl;
27046
- const backgroundImageRef = React82.useRef(backgroundImage);
27076
+ const backgroundImageRef = React81.useRef(backgroundImage);
27047
27077
  backgroundImageRef.current = backgroundImage;
27048
- const widthRef = React82.useRef(width);
27078
+ const widthRef = React81.useRef(width);
27049
27079
  widthRef.current = width;
27050
- const heightRef = React82.useRef(height);
27080
+ const heightRef = React81.useRef(height);
27051
27081
  heightRef.current = height;
27052
- const loadImage = React82.useCallback((url) => {
27082
+ const loadImage = React81.useCallback((url) => {
27053
27083
  const fullUrl = url.startsWith("http") ? url : `${assetBaseUrlRef.current}${url}`;
27054
27084
  const cached = imageCache.current.get(fullUrl);
27055
27085
  if (cached?.complete && cached.naturalWidth > 0) return cached;
@@ -27061,7 +27091,7 @@ function GameCanvas2D({
27061
27091
  }
27062
27092
  return null;
27063
27093
  }, []);
27064
- React82.useEffect(() => {
27094
+ React81.useEffect(() => {
27065
27095
  const canvas = canvasRef.current;
27066
27096
  if (!canvas) return;
27067
27097
  const ctx = canvas.getContext("2d");
@@ -27373,7 +27403,7 @@ function TurnPanel({
27373
27403
  className
27374
27404
  }) {
27375
27405
  const eventBus = useEventBus();
27376
- const handleAction = React82.useCallback(
27406
+ const handleAction = React81.useCallback(
27377
27407
  (event) => {
27378
27408
  if (event) {
27379
27409
  eventBus.emit(event, { turn: currentTurn, phase, activeTeam });
@@ -27542,7 +27572,7 @@ function UnitCommandBar({
27542
27572
  className
27543
27573
  }) {
27544
27574
  const eventBus = useEventBus();
27545
- const handleCommand = React82.useCallback(
27575
+ const handleCommand = React81.useCallback(
27546
27576
  (event) => {
27547
27577
  if (event) {
27548
27578
  eventBus.emit(event, { unitId: selectedUnitId });
@@ -28056,7 +28086,7 @@ function GameMenu({
28056
28086
  } catch {
28057
28087
  }
28058
28088
  const eventBus = eventBusProp || eventBusFromHook;
28059
- const handleOptionClick = React82.useCallback(
28089
+ const handleOptionClick = React81.useCallback(
28060
28090
  (option) => {
28061
28091
  if (option.event && eventBus) {
28062
28092
  eventBus.emit(`UI:${option.event}`, { option });
@@ -28175,7 +28205,7 @@ function GameOverScreen({
28175
28205
  } catch {
28176
28206
  }
28177
28207
  const eventBus = eventBusProp || eventBusFromHook;
28178
- const handleActionClick = React82.useCallback(
28208
+ const handleActionClick = React81.useCallback(
28179
28209
  (action) => {
28180
28210
  if (action.event && eventBus) {
28181
28211
  eventBus.emit(`UI:${action.event}`, { action });
@@ -29064,13 +29094,13 @@ var init_MapView = __esm({
29064
29094
  shadowSize: [41, 41]
29065
29095
  });
29066
29096
  L.Marker.prototype.options.icon = defaultIcon;
29067
- const { useEffect: useEffect80, useRef: useRef74, useCallback: useCallback118, useState: useState112 } = React82__default;
29097
+ const { useEffect: useEffect81, useRef: useRef75, useCallback: useCallback119, useState: useState113 } = React81__default;
29068
29098
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
29069
29099
  const { useEventBus: useEventBus4 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
29070
29100
  function MapUpdater({ centerLat, centerLng, zoom }) {
29071
29101
  const map = useMap();
29072
- const prevRef = useRef74({ centerLat, centerLng, zoom });
29073
- useEffect80(() => {
29102
+ const prevRef = useRef75({ centerLat, centerLng, zoom });
29103
+ useEffect81(() => {
29074
29104
  const prev = prevRef.current;
29075
29105
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
29076
29106
  map.setView([centerLat, centerLng], zoom);
@@ -29081,7 +29111,7 @@ var init_MapView = __esm({
29081
29111
  }
29082
29112
  function MapClickHandler({ onMapClick }) {
29083
29113
  const map = useMap();
29084
- useEffect80(() => {
29114
+ useEffect81(() => {
29085
29115
  if (!onMapClick) return;
29086
29116
  const handler = (e) => {
29087
29117
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -29109,8 +29139,8 @@ var init_MapView = __esm({
29109
29139
  showAttribution = true
29110
29140
  }) {
29111
29141
  const eventBus = useEventBus4();
29112
- const [clickedPosition, setClickedPosition] = useState112(null);
29113
- const handleMapClick = useCallback118((lat, lng) => {
29142
+ const [clickedPosition, setClickedPosition] = useState113(null);
29143
+ const handleMapClick = useCallback119((lat, lng) => {
29114
29144
  if (showClickedPin) {
29115
29145
  setClickedPosition({ lat, lng });
29116
29146
  }
@@ -29119,7 +29149,7 @@ var init_MapView = __esm({
29119
29149
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
29120
29150
  }
29121
29151
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
29122
- const handleMarkerClick = useCallback118((marker) => {
29152
+ const handleMarkerClick = useCallback119((marker) => {
29123
29153
  onMarkerClick?.(marker);
29124
29154
  if (markerClickEvent) {
29125
29155
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -29970,8 +30000,8 @@ function TableView({
29970
30000
  }) {
29971
30001
  const eventBus = useEventBus();
29972
30002
  const { t } = useTranslate();
29973
- const [visibleCount, setVisibleCount] = React82__default.useState(pageSize > 0 ? pageSize : Infinity);
29974
- const [localSelected, setLocalSelected] = React82__default.useState(/* @__PURE__ */ new Set());
30003
+ const [visibleCount, setVisibleCount] = React81__default.useState(pageSize > 0 ? pageSize : Infinity);
30004
+ const [localSelected, setLocalSelected] = React81__default.useState(/* @__PURE__ */ new Set());
29975
30005
  const colDefs = columns ?? fields ?? [];
29976
30006
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
29977
30007
  const dnd = useDataDnd({
@@ -30166,12 +30196,12 @@ function TableView({
30166
30196
  ]
30167
30197
  }
30168
30198
  );
30169
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React82__default.Fragment, { children: rowInner }, id);
30199
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React81__default.Fragment, { children: rowInner }, id);
30170
30200
  };
30171
30201
  const items = data.map((row) => row);
30172
30202
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
30173
30203
  let runningIndex = 0;
30174
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
30204
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React81__default.Fragment, { children: [
30175
30205
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
30176
30206
  group.items.map((row) => renderRow(row, runningIndex++))
30177
30207
  ] }, gi)) });
@@ -31528,7 +31558,7 @@ var init_StepFlow = __esm({
31528
31558
  className
31529
31559
  }) => {
31530
31560
  if (orientation === "vertical") {
31531
- return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React82__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
31561
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React81__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
31532
31562
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
31533
31563
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
31534
31564
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -31539,7 +31569,7 @@ var init_StepFlow = __esm({
31539
31569
  ] })
31540
31570
  ] }) }, index)) });
31541
31571
  }
31542
- return /* @__PURE__ */ jsx(Box, { className: cn("w-full flex flex-col md:flex-row items-start gap-0", className), children: steps.map((step, index) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
31572
+ 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(React81__default.Fragment, { children: [
31543
31573
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
31544
31574
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
31545
31575
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -32524,7 +32554,7 @@ var init_LikertScale = __esm({
32524
32554
  md: "text-base",
32525
32555
  lg: "text-lg"
32526
32556
  };
32527
- LikertScale = React82__default.forwardRef(
32557
+ LikertScale = React81__default.forwardRef(
32528
32558
  ({
32529
32559
  question,
32530
32560
  options = DEFAULT_LIKERT_OPTIONS,
@@ -32536,7 +32566,7 @@ var init_LikertScale = __esm({
32536
32566
  variant = "radios",
32537
32567
  className
32538
32568
  }, ref) => {
32539
- const groupId = React82__default.useId();
32569
+ const groupId = React81__default.useId();
32540
32570
  const eventBus = useEventBus();
32541
32571
  const handleSelect = useCallback(
32542
32572
  (next) => {
@@ -34818,7 +34848,7 @@ var init_DocBreadcrumb = __esm({
34818
34848
  "aria-label": t("aria.breadcrumb"),
34819
34849
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
34820
34850
  const isLast = idx === items.length - 1;
34821
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
34851
+ return /* @__PURE__ */ jsxs(React81__default.Fragment, { children: [
34822
34852
  idx > 0 && /* @__PURE__ */ jsx(
34823
34853
  Icon,
34824
34854
  {
@@ -35687,7 +35717,7 @@ var init_MiniStateMachine = __esm({
35687
35717
  const x = 2 + i * (NODE_W + GAP + ARROW_W + GAP);
35688
35718
  const tc = transitionCounts[s.name] ?? 0;
35689
35719
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
35690
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
35720
+ return /* @__PURE__ */ jsxs(React81__default.Fragment, { children: [
35691
35721
  /* @__PURE__ */ jsx(
35692
35722
  AvlState,
35693
35723
  {
@@ -35891,7 +35921,7 @@ var init_PageHeader = __esm({
35891
35921
  info: "bg-info/10 text-info"
35892
35922
  };
35893
35923
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
35894
- breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
35924
+ 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(React81__default.Fragment, { children: [
35895
35925
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
35896
35926
  crumb.href ? /* @__PURE__ */ jsx(
35897
35927
  "a",
@@ -36620,7 +36650,7 @@ var init_WizardContainer = __esm({
36620
36650
  const isCompleted = index < currentStep;
36621
36651
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
36622
36652
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
36623
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
36653
+ return /* @__PURE__ */ jsxs(React81__default.Fragment, { children: [
36624
36654
  /* @__PURE__ */ jsx(
36625
36655
  Button,
36626
36656
  {
@@ -38955,7 +38985,7 @@ var init_DetailPanel = __esm({
38955
38985
  }
38956
38986
  });
38957
38987
  function extractTitle(children) {
38958
- if (!React82__default.isValidElement(children)) return void 0;
38988
+ if (!React81__default.isValidElement(children)) return void 0;
38959
38989
  const props = children.props;
38960
38990
  if (typeof props.title === "string") {
38961
38991
  return props.title;
@@ -39010,7 +39040,7 @@ function LinearView({
39010
39040
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
39011
39041
  const isDone = i < currentIdx;
39012
39042
  const isCurrent = i === currentIdx;
39013
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
39043
+ return /* @__PURE__ */ jsxs(React81__default.Fragment, { children: [
39014
39044
  i > 0 && /* @__PURE__ */ jsx(
39015
39045
  Typography,
39016
39046
  {
@@ -39960,12 +39990,12 @@ var init_Form = __esm({
39960
39990
  const isSchemaEntity = isOrbitalEntitySchema(entity);
39961
39991
  const resolvedEntity = isSchemaEntity ? entity : void 0;
39962
39992
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
39963
- const normalizedInitialData = React82__default.useMemo(() => {
39993
+ const normalizedInitialData = React81__default.useMemo(() => {
39964
39994
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
39965
39995
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
39966
39996
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
39967
39997
  }, [entity, initialData]);
39968
- const entityDerivedFields = React82__default.useMemo(() => {
39998
+ const entityDerivedFields = React81__default.useMemo(() => {
39969
39999
  if (fields && fields.length > 0) return void 0;
39970
40000
  if (!resolvedEntity) return void 0;
39971
40001
  return resolvedEntity.fields.map(
@@ -39985,16 +40015,16 @@ var init_Form = __esm({
39985
40015
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
39986
40016
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
39987
40017
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
39988
- const [formData, setFormData] = React82__default.useState(
40018
+ const [formData, setFormData] = React81__default.useState(
39989
40019
  normalizedInitialData
39990
40020
  );
39991
- const [collapsedSections, setCollapsedSections] = React82__default.useState(
40021
+ const [collapsedSections, setCollapsedSections] = React81__default.useState(
39992
40022
  /* @__PURE__ */ new Set()
39993
40023
  );
39994
- const [submitError, setSubmitError] = React82__default.useState(null);
39995
- const formRef = React82__default.useRef(null);
40024
+ const [submitError, setSubmitError] = React81__default.useState(null);
40025
+ const formRef = React81__default.useRef(null);
39996
40026
  const formMode = props.mode;
39997
- const mountedRef = React82__default.useRef(false);
40027
+ const mountedRef = React81__default.useRef(false);
39998
40028
  if (!mountedRef.current) {
39999
40029
  mountedRef.current = true;
40000
40030
  debug("forms", "mount", {
@@ -40007,7 +40037,7 @@ var init_Form = __esm({
40007
40037
  });
40008
40038
  }
40009
40039
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
40010
- const evalContext = React82__default.useMemo(
40040
+ const evalContext = React81__default.useMemo(
40011
40041
  () => ({
40012
40042
  formValues: formData,
40013
40043
  globalVariables: externalContext?.globalVariables ?? {},
@@ -40016,7 +40046,7 @@ var init_Form = __esm({
40016
40046
  }),
40017
40047
  [formData, externalContext]
40018
40048
  );
40019
- React82__default.useEffect(() => {
40049
+ React81__default.useEffect(() => {
40020
40050
  debug("forms", "initialData-sync", {
40021
40051
  mode: formMode,
40022
40052
  normalizedInitialData,
@@ -40027,7 +40057,7 @@ var init_Form = __esm({
40027
40057
  setFormData(normalizedInitialData);
40028
40058
  }
40029
40059
  }, [normalizedInitialData]);
40030
- const processCalculations = React82__default.useCallback(
40060
+ const processCalculations = React81__default.useCallback(
40031
40061
  (changedFieldId, newFormData) => {
40032
40062
  if (!hiddenCalculations.length) return;
40033
40063
  const context = {
@@ -40052,7 +40082,7 @@ var init_Form = __esm({
40052
40082
  },
40053
40083
  [hiddenCalculations, externalContext, eventBus]
40054
40084
  );
40055
- const checkViolations = React82__default.useCallback(
40085
+ const checkViolations = React81__default.useCallback(
40056
40086
  (changedFieldId, newFormData) => {
40057
40087
  if (!violationTriggers.length) return;
40058
40088
  const context = {
@@ -40090,7 +40120,7 @@ var init_Form = __esm({
40090
40120
  processCalculations(name, newFormData);
40091
40121
  checkViolations(name, newFormData);
40092
40122
  };
40093
- const isFieldVisible = React82__default.useCallback(
40123
+ const isFieldVisible = React81__default.useCallback(
40094
40124
  (fieldName) => {
40095
40125
  const condition = conditionalFields[fieldName];
40096
40126
  if (!condition) return true;
@@ -40098,7 +40128,7 @@ var init_Form = __esm({
40098
40128
  },
40099
40129
  [conditionalFields, evalContext]
40100
40130
  );
40101
- const isSectionVisible = React82__default.useCallback(
40131
+ const isSectionVisible = React81__default.useCallback(
40102
40132
  (section) => {
40103
40133
  if (!section.condition) return true;
40104
40134
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -40174,7 +40204,7 @@ var init_Form = __esm({
40174
40204
  eventBus.emit(`UI:${onCancel}`);
40175
40205
  }
40176
40206
  };
40177
- const renderField = React82__default.useCallback(
40207
+ const renderField = React81__default.useCallback(
40178
40208
  (field) => {
40179
40209
  const fieldName = field.name || field.field;
40180
40210
  if (!fieldName) return null;
@@ -40195,7 +40225,7 @@ var init_Form = __esm({
40195
40225
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
40196
40226
  );
40197
40227
  const effectiveFields = entityDerivedFields ?? fields;
40198
- const normalizedFields = React82__default.useMemo(() => {
40228
+ const normalizedFields = React81__default.useMemo(() => {
40199
40229
  if (!effectiveFields || effectiveFields.length === 0) return [];
40200
40230
  return effectiveFields.map((field) => {
40201
40231
  if (typeof field === "string") {
@@ -40218,7 +40248,7 @@ var init_Form = __esm({
40218
40248
  return field;
40219
40249
  });
40220
40250
  }, [effectiveFields, resolvedEntity]);
40221
- const schemaFields = React82__default.useMemo(() => {
40251
+ const schemaFields = React81__default.useMemo(() => {
40222
40252
  if (normalizedFields.length === 0) return null;
40223
40253
  if (isDebugEnabled()) {
40224
40254
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -40228,7 +40258,7 @@ var init_Form = __esm({
40228
40258
  }
40229
40259
  return normalizedFields.map(renderField).filter(Boolean);
40230
40260
  }, [normalizedFields, renderField, entityName, conditionalFields]);
40231
- const sectionElements = React82__default.useMemo(() => {
40261
+ const sectionElements = React81__default.useMemo(() => {
40232
40262
  if (!sections || sections.length === 0) return null;
40233
40263
  return sections.map((section) => {
40234
40264
  if (!isSectionVisible(section)) {
@@ -40837,7 +40867,7 @@ var init_AssetLoader = __esm({
40837
40867
  __publicField(this, "textureCache");
40838
40868
  __publicField(this, "loadingPromises");
40839
40869
  this.objLoader = new OBJLoader();
40840
- this.textureLoader = new THREE.TextureLoader();
40870
+ this.textureLoader = new THREE3.TextureLoader();
40841
40871
  this.modelCache = /* @__PURE__ */ new Map();
40842
40872
  this.textureCache = /* @__PURE__ */ new Map();
40843
40873
  this.loadingPromises = /* @__PURE__ */ new Map();
@@ -40911,7 +40941,7 @@ var init_AssetLoader = __esm({
40911
40941
  return this.loadingPromises.get(`texture:${url}`);
40912
40942
  }
40913
40943
  const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
40914
- texture.colorSpace = THREE.SRGBColorSpace;
40944
+ texture.colorSpace = THREE3.SRGBColorSpace;
40915
40945
  this.textureCache.set(url, texture);
40916
40946
  this.loadingPromises.delete(`texture:${url}`);
40917
40947
  return texture;
@@ -40985,7 +41015,7 @@ var init_AssetLoader = __esm({
40985
41015
  });
40986
41016
  this.modelCache.forEach((model) => {
40987
41017
  model.scene.traverse((child) => {
40988
- if (child instanceof THREE.Mesh) {
41018
+ if (child instanceof THREE3.Mesh) {
40989
41019
  child.geometry.dispose();
40990
41020
  if (Array.isArray(child.material)) {
40991
41021
  child.material.forEach((m) => m.dispose());
@@ -41398,11 +41428,11 @@ var init_Canvas3DErrorBoundary = __esm({
41398
41428
  "components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
41399
41429
  }
41400
41430
  });
41401
- var log10, Canvas3DErrorBoundary;
41431
+ var log9, Canvas3DErrorBoundary;
41402
41432
  var init_Canvas3DErrorBoundary2 = __esm({
41403
41433
  "components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
41404
41434
  init_Canvas3DErrorBoundary();
41405
- log10 = createLogger("almadar:ui:game:canvas3d:error-boundary");
41435
+ log9 = createLogger("almadar:ui:game:canvas3d:error-boundary");
41406
41436
  Canvas3DErrorBoundary = class extends Component {
41407
41437
  constructor(props) {
41408
41438
  super(props);
@@ -41430,8 +41460,8 @@ var init_Canvas3DErrorBoundary2 = __esm({
41430
41460
  componentDidCatch(error, errorInfo) {
41431
41461
  this.setState({ errorInfo });
41432
41462
  this.props.onError?.(error, errorInfo);
41433
- log10.error("Error caught", { error });
41434
- log10.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
41463
+ log9.error("Error caught", { error });
41464
+ log9.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
41435
41465
  }
41436
41466
  render() {
41437
41467
  if (this.state.hasError) {
@@ -41494,7 +41524,7 @@ function useGLTFModel(url, resourceBasePath) {
41494
41524
  setState({ model: null, isLoading: false, error: null });
41495
41525
  return;
41496
41526
  }
41497
- log11.debug("Loading", { url });
41527
+ log10.debug("Loading", { url });
41498
41528
  setState((prev) => ({ ...prev, isLoading: true, error: null }));
41499
41529
  const assetRoot = resourceBasePath || detectAssetRoot2(url);
41500
41530
  const loader = new GLTFLoader$1();
@@ -41502,7 +41532,7 @@ function useGLTFModel(url, resourceBasePath) {
41502
41532
  loader.load(
41503
41533
  url,
41504
41534
  (gltf) => {
41505
- log11.debug("Loaded", { url });
41535
+ log10.debug("Loaded", { url });
41506
41536
  setState({
41507
41537
  model: gltf.scene,
41508
41538
  isLoading: false,
@@ -41511,7 +41541,7 @@ function useGLTFModel(url, resourceBasePath) {
41511
41541
  },
41512
41542
  void 0,
41513
41543
  (err) => {
41514
- log11.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
41544
+ log10.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
41515
41545
  setState({
41516
41546
  model: null,
41517
41547
  isLoading: false,
@@ -41541,7 +41571,7 @@ function ModelLoader({
41541
41571
  if (!loadedModel) return null;
41542
41572
  const cloned = loadedModel.clone();
41543
41573
  cloned.traverse((child) => {
41544
- if (child instanceof THREE.Mesh) {
41574
+ if (child instanceof THREE3.Mesh) {
41545
41575
  child.castShadow = castShadow;
41546
41576
  child.receiveShadow = receiveShadow;
41547
41577
  }
@@ -41627,11 +41657,11 @@ function ModelLoader({
41627
41657
  }
41628
41658
  );
41629
41659
  }
41630
- var log11;
41660
+ var log10;
41631
41661
  var init_ModelLoader = __esm({
41632
41662
  "components/game/molecules/three/components/ModelLoader.tsx"() {
41633
41663
  "use client";
41634
- log11 = createLogger("almadar:ui:game:model-loader");
41664
+ log10 = createLogger("almadar:ui:game:model-loader");
41635
41665
  }
41636
41666
  });
41637
41667
 
@@ -41655,6 +41685,47 @@ function CameraController({
41655
41685
  }, [camera.position, onCameraChange]);
41656
41686
  return null;
41657
41687
  }
41688
+ function UnitSpriteBillboard({
41689
+ sheetUrl,
41690
+ resolveFrame,
41691
+ height = 1.2
41692
+ }) {
41693
+ const texture = useLoader(THREE3.TextureLoader, sheetUrl);
41694
+ const meshRef = useRef(null);
41695
+ const matRef = useRef(null);
41696
+ const [aspect, setAspect] = useState(1);
41697
+ useFrame(() => {
41698
+ const frame = resolveFrame();
41699
+ if (!frame || !texture.image) return;
41700
+ const imgW = texture.image.width;
41701
+ const imgH = texture.image.height;
41702
+ if (!imgW || !imgH) return;
41703
+ texture.repeat.set((frame.flipX ? -1 : 1) * (frame.sw / imgW), frame.sh / imgH);
41704
+ texture.offset.set(
41705
+ frame.flipX ? (frame.sx + frame.sw) / imgW : frame.sx / imgW,
41706
+ 1 - (frame.sy + frame.sh) / imgH
41707
+ );
41708
+ texture.magFilter = THREE3.NearestFilter;
41709
+ texture.minFilter = THREE3.NearestFilter;
41710
+ texture.needsUpdate = true;
41711
+ const nextAspect = frame.sw / frame.sh;
41712
+ if (Math.abs(nextAspect - aspect) > 1e-3) setAspect(nextAspect);
41713
+ if (matRef.current) matRef.current.needsUpdate = true;
41714
+ });
41715
+ return /* @__PURE__ */ jsxs("mesh", { ref: meshRef, position: [0, height / 2, 0], children: [
41716
+ /* @__PURE__ */ jsx("planeGeometry", { args: [height * aspect, height] }),
41717
+ /* @__PURE__ */ jsx(
41718
+ "meshBasicMaterial",
41719
+ {
41720
+ ref: matRef,
41721
+ map: texture,
41722
+ transparent: true,
41723
+ alphaTest: 0.1,
41724
+ side: THREE3.DoubleSide
41725
+ }
41726
+ )
41727
+ ] });
41728
+ }
41658
41729
  var DEFAULT_GRID_CONFIG, GameCanvas3D;
41659
41730
  var init_GameCanvas3D2 = __esm({
41660
41731
  "components/game/molecules/GameCanvas3D.tsx"() {
@@ -41665,6 +41736,7 @@ var init_GameCanvas3D2 = __esm({
41665
41736
  init_Canvas3DLoadingState2();
41666
41737
  init_Canvas3DErrorBoundary2();
41667
41738
  init_ModelLoader();
41739
+ init_useUnitSpriteAtlas();
41668
41740
  init_cn();
41669
41741
  init_GameCanvas3D();
41670
41742
  DEFAULT_GRID_CONFIG = {
@@ -41721,8 +41793,10 @@ var init_GameCanvas3D2 = __esm({
41721
41793
  const controlsRef = useRef(null);
41722
41794
  const [hoveredTile, setHoveredTile] = useState(null);
41723
41795
  const [internalError, setInternalError] = useState(null);
41796
+ const { sheetUrls: atlasSheetUrls, resolveUnitFrame } = useUnitSpriteAtlas(units);
41797
+ const preloadUrls = useMemo(() => [...preloadAssets, ...atlasSheetUrls], [preloadAssets, atlasSheetUrls]);
41724
41798
  const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
41725
- preloadUrls: preloadAssets,
41799
+ preloadUrls,
41726
41800
  loader: customAssetLoader
41727
41801
  });
41728
41802
  const eventHandlers = useGameCanvas3DEvents({
@@ -41781,7 +41855,7 @@ var init_GameCanvas3D2 = __esm({
41781
41855
  getCameraPosition: () => {
41782
41856
  if (controlsRef.current) {
41783
41857
  const pos = controlsRef.current.object.position;
41784
- return new THREE.Vector3(pos.x, pos.y, pos.z);
41858
+ return new THREE3.Vector3(pos.x, pos.y, pos.z);
41785
41859
  }
41786
41860
  return null;
41787
41861
  },
@@ -41933,6 +42007,8 @@ var init_GameCanvas3D2 = __esm({
41933
42007
  ({ unit, position }) => {
41934
42008
  const isSelected = selectedUnitId === unit.id;
41935
42009
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
42010
+ const hasAtlas = unitAtlasUrl(unit) !== null;
42011
+ const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
41936
42012
  return /* @__PURE__ */ jsxs(
41937
42013
  "group",
41938
42014
  {
@@ -41944,7 +42020,16 @@ var init_GameCanvas3D2 = __esm({
41944
42020
  /* @__PURE__ */ jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
41945
42021
  /* @__PURE__ */ jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
41946
42022
  ] }),
41947
- unit.modelUrl ? (
42023
+ hasAtlas && initialFrame ? (
42024
+ /* Animated sprite-sheet billboard — single cropped frame, by state */
42025
+ /* @__PURE__ */ jsx(Billboard, { children: /* @__PURE__ */ jsx(
42026
+ UnitSpriteBillboard,
42027
+ {
42028
+ sheetUrl: initialFrame.sheetUrl,
42029
+ resolveFrame: () => resolveUnitFrame(unit.id)
42030
+ }
42031
+ ) })
42032
+ ) : unit.modelUrl ? (
41948
42033
  /* GLB unit model (box fallback while loading / on error) */
41949
42034
  /* @__PURE__ */ jsx(
41950
42035
  ModelLoader,
@@ -41998,7 +42083,7 @@ var init_GameCanvas3D2 = __esm({
41998
42083
  }
41999
42084
  );
42000
42085
  },
42001
- [selectedUnitId, handleUnitClick]
42086
+ [selectedUnitId, handleUnitClick, resolveUnitFrame]
42002
42087
  );
42003
42088
  const DefaultFeatureRenderer = useCallback(
42004
42089
  ({
@@ -43065,7 +43150,7 @@ var init_List = __esm({
43065
43150
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
43066
43151
  return [];
43067
43152
  }, [entity]);
43068
- const getItemActions = React82__default.useCallback(
43153
+ const getItemActions = React81__default.useCallback(
43069
43154
  (item) => {
43070
43155
  if (!itemActions) return [];
43071
43156
  if (typeof itemActions === "function") {
@@ -43541,7 +43626,7 @@ var init_MediaGallery = __esm({
43541
43626
  [selectable, selectedItems, selectionEvent, eventBus]
43542
43627
  );
43543
43628
  const entityData = Array.isArray(entity) ? entity : [];
43544
- const items = React82__default.useMemo(() => {
43629
+ const items = React81__default.useMemo(() => {
43545
43630
  if (propItems) return propItems;
43546
43631
  if (entityData.length === 0) return [];
43547
43632
  return entityData.map((record, idx) => ({
@@ -43702,7 +43787,7 @@ var init_MediaGallery = __esm({
43702
43787
  }
43703
43788
  });
43704
43789
  function extractTitle2(children) {
43705
- if (!React82__default.isValidElement(children)) return void 0;
43790
+ if (!React81__default.isValidElement(children)) return void 0;
43706
43791
  const props = children.props;
43707
43792
  if (typeof props.title === "string") {
43708
43793
  return props.title;
@@ -44726,7 +44811,7 @@ var init_debugRegistry = __esm({
44726
44811
  }
44727
44812
  });
44728
44813
  function useDebugData() {
44729
- const [data, setData] = React82.useState(() => ({
44814
+ const [data, setData] = React81.useState(() => ({
44730
44815
  traits: [],
44731
44816
  ticks: [],
44732
44817
  guards: [],
@@ -44740,7 +44825,7 @@ function useDebugData() {
44740
44825
  },
44741
44826
  lastUpdate: Date.now()
44742
44827
  }));
44743
- React82.useEffect(() => {
44828
+ React81.useEffect(() => {
44744
44829
  const updateData = () => {
44745
44830
  setData({
44746
44831
  traits: getAllTraits(),
@@ -44849,12 +44934,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
44849
44934
  return positions;
44850
44935
  }
44851
44936
  function WalkMinimap() {
44852
- const [walkStep, setWalkStep] = React82.useState(null);
44853
- const [traits2, setTraits] = React82.useState([]);
44854
- const [coveredEdges, setCoveredEdges] = React82.useState([]);
44855
- const [completedTraits, setCompletedTraits] = React82.useState(/* @__PURE__ */ new Set());
44856
- const prevTraitRef = React82.useRef(null);
44857
- React82.useEffect(() => {
44937
+ const [walkStep, setWalkStep] = React81.useState(null);
44938
+ const [traits2, setTraits] = React81.useState([]);
44939
+ const [coveredEdges, setCoveredEdges] = React81.useState([]);
44940
+ const [completedTraits, setCompletedTraits] = React81.useState(/* @__PURE__ */ new Set());
44941
+ const prevTraitRef = React81.useRef(null);
44942
+ React81.useEffect(() => {
44858
44943
  const interval = setInterval(() => {
44859
44944
  const w = window;
44860
44945
  const step = w.__orbitalWalkStep;
@@ -45290,15 +45375,15 @@ var init_EntitiesTab = __esm({
45290
45375
  });
45291
45376
  function EventFlowTab({ events: events2 }) {
45292
45377
  const { t } = useTranslate();
45293
- const [filter, setFilter] = React82.useState("all");
45294
- const containerRef = React82.useRef(null);
45295
- const [autoScroll, setAutoScroll] = React82.useState(true);
45296
- React82.useEffect(() => {
45378
+ const [filter, setFilter] = React81.useState("all");
45379
+ const containerRef = React81.useRef(null);
45380
+ const [autoScroll, setAutoScroll] = React81.useState(true);
45381
+ React81.useEffect(() => {
45297
45382
  if (autoScroll && containerRef.current) {
45298
45383
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
45299
45384
  }
45300
45385
  }, [events2.length, autoScroll]);
45301
- const filteredEvents = React82.useMemo(() => {
45386
+ const filteredEvents = React81.useMemo(() => {
45302
45387
  if (filter === "all") return events2;
45303
45388
  return events2.filter((e) => e.type === filter);
45304
45389
  }, [events2, filter]);
@@ -45414,7 +45499,7 @@ var init_EventFlowTab = __esm({
45414
45499
  });
45415
45500
  function GuardsPanel({ guards }) {
45416
45501
  const { t } = useTranslate();
45417
- const [filter, setFilter] = React82.useState("all");
45502
+ const [filter, setFilter] = React81.useState("all");
45418
45503
  if (guards.length === 0) {
45419
45504
  return /* @__PURE__ */ jsx(
45420
45505
  EmptyState,
@@ -45427,7 +45512,7 @@ function GuardsPanel({ guards }) {
45427
45512
  }
45428
45513
  const passedCount = guards.filter((g) => g.result).length;
45429
45514
  const failedCount = guards.length - passedCount;
45430
- const filteredGuards = React82.useMemo(() => {
45515
+ const filteredGuards = React81.useMemo(() => {
45431
45516
  if (filter === "all") return guards;
45432
45517
  if (filter === "passed") return guards.filter((g) => g.result);
45433
45518
  return guards.filter((g) => !g.result);
@@ -45590,10 +45675,10 @@ function EffectBadge({ effect }) {
45590
45675
  }
45591
45676
  function TransitionTimeline({ transitions }) {
45592
45677
  const { t } = useTranslate();
45593
- const containerRef = React82.useRef(null);
45594
- const [autoScroll, setAutoScroll] = React82.useState(true);
45595
- const [expandedId, setExpandedId] = React82.useState(null);
45596
- React82.useEffect(() => {
45678
+ const containerRef = React81.useRef(null);
45679
+ const [autoScroll, setAutoScroll] = React81.useState(true);
45680
+ const [expandedId, setExpandedId] = React81.useState(null);
45681
+ React81.useEffect(() => {
45597
45682
  if (autoScroll && containerRef.current) {
45598
45683
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
45599
45684
  }
@@ -45873,9 +45958,9 @@ function getAllEvents(traits2) {
45873
45958
  function EventDispatcherTab({ traits: traits2, schema }) {
45874
45959
  const eventBus = useEventBus();
45875
45960
  const { t } = useTranslate();
45876
- const [log14, setLog] = React82.useState([]);
45877
- const prevStatesRef = React82.useRef(/* @__PURE__ */ new Map());
45878
- React82.useEffect(() => {
45961
+ const [log14, setLog] = React81.useState([]);
45962
+ const prevStatesRef = React81.useRef(/* @__PURE__ */ new Map());
45963
+ React81.useEffect(() => {
45879
45964
  for (const trait of traits2) {
45880
45965
  const prev = prevStatesRef.current.get(trait.id);
45881
45966
  if (prev && prev !== trait.currentState) {
@@ -46044,10 +46129,10 @@ function VerifyModePanel({
46044
46129
  localCount
46045
46130
  }) {
46046
46131
  const { t } = useTranslate();
46047
- const [expanded, setExpanded] = React82.useState(true);
46048
- const scrollRef = React82.useRef(null);
46049
- const prevCountRef = React82.useRef(0);
46050
- React82.useEffect(() => {
46132
+ const [expanded, setExpanded] = React81.useState(true);
46133
+ const scrollRef = React81.useRef(null);
46134
+ const prevCountRef = React81.useRef(0);
46135
+ React81.useEffect(() => {
46051
46136
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
46052
46137
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
46053
46138
  }
@@ -46104,10 +46189,10 @@ function RuntimeDebugger({
46104
46189
  schema
46105
46190
  }) {
46106
46191
  const { t } = useTranslate();
46107
- const [isCollapsed, setIsCollapsed] = React82.useState(mode === "verify" ? true : defaultCollapsed);
46108
- const [isVisible, setIsVisible] = React82.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
46192
+ const [isCollapsed, setIsCollapsed] = React81.useState(mode === "verify" ? true : defaultCollapsed);
46193
+ const [isVisible, setIsVisible] = React81.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
46109
46194
  const debugData = useDebugData();
46110
- React82.useEffect(() => {
46195
+ React81.useEffect(() => {
46111
46196
  if (mode === "inline") return;
46112
46197
  return onDebugToggle((enabled) => {
46113
46198
  setIsVisible(enabled);
@@ -46116,7 +46201,7 @@ function RuntimeDebugger({
46116
46201
  }
46117
46202
  });
46118
46203
  }, [mode]);
46119
- React82.useEffect(() => {
46204
+ React81.useEffect(() => {
46120
46205
  if (mode === "inline") return;
46121
46206
  const handleKeyDown = (e) => {
46122
46207
  if (e.key === "`" && isVisible) {
@@ -46676,7 +46761,7 @@ function SequenceBar({
46676
46761
  onSlotRemove(index);
46677
46762
  }, [onSlotRemove, playing]);
46678
46763
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
46679
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
46764
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React81__default.Fragment, { children: [
46680
46765
  i > 0 && /* @__PURE__ */ jsx(
46681
46766
  Typography,
46682
46767
  {
@@ -47565,7 +47650,7 @@ var init_StatCard = __esm({
47565
47650
  const labelToUse = propLabel ?? propTitle;
47566
47651
  const eventBus = useEventBus();
47567
47652
  const { t } = useTranslate();
47568
- const handleActionClick = React82__default.useCallback(() => {
47653
+ const handleActionClick = React81__default.useCallback(() => {
47569
47654
  if (action?.event) {
47570
47655
  eventBus.emit(`UI:${action.event}`, {});
47571
47656
  }
@@ -47576,7 +47661,7 @@ var init_StatCard = __esm({
47576
47661
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
47577
47662
  const isLoading = externalLoading ?? false;
47578
47663
  const error = externalError;
47579
- const computeMetricValue = React82__default.useCallback(
47664
+ const computeMetricValue = React81__default.useCallback(
47580
47665
  (metric, items) => {
47581
47666
  if (metric.value !== void 0) {
47582
47667
  return metric.value;
@@ -47615,7 +47700,7 @@ var init_StatCard = __esm({
47615
47700
  },
47616
47701
  []
47617
47702
  );
47618
- const schemaStats = React82__default.useMemo(() => {
47703
+ const schemaStats = React81__default.useMemo(() => {
47619
47704
  if (!metrics || metrics.length === 0) return null;
47620
47705
  return metrics.map((metric) => ({
47621
47706
  label: metric.label,
@@ -47623,7 +47708,7 @@ var init_StatCard = __esm({
47623
47708
  format: metric.format
47624
47709
  }));
47625
47710
  }, [metrics, data, computeMetricValue]);
47626
- const calculatedTrend = React82__default.useMemo(() => {
47711
+ const calculatedTrend = React81__default.useMemo(() => {
47627
47712
  if (manualTrend !== void 0) return manualTrend;
47628
47713
  if (previousValue === void 0 || currentValue === void 0)
47629
47714
  return void 0;
@@ -48589,7 +48674,7 @@ var init_Timeline = __esm({
48589
48674
  }) => {
48590
48675
  const { t } = useTranslate();
48591
48676
  const entityData = Array.isArray(entity) ? entity : [];
48592
- const items = React82__default.useMemo(() => {
48677
+ const items = React81__default.useMemo(() => {
48593
48678
  if (propItems) return propItems;
48594
48679
  if (entityData.length === 0) return [];
48595
48680
  return entityData.map((record, idx) => {
@@ -48696,7 +48781,7 @@ var init_Timeline = __esm({
48696
48781
  }
48697
48782
  });
48698
48783
  function extractToastProps(children) {
48699
- if (!React82__default.isValidElement(children)) {
48784
+ if (!React81__default.isValidElement(children)) {
48700
48785
  if (typeof children === "string") {
48701
48786
  return { message: children };
48702
48787
  }
@@ -48734,7 +48819,7 @@ var init_ToastSlot = __esm({
48734
48819
  eventBus.emit("UI:CLOSE");
48735
48820
  };
48736
48821
  if (!isVisible) return null;
48737
- const isCustomContent = React82__default.isValidElement(children) && !message;
48822
+ const isCustomContent = React81__default.isValidElement(children) && !message;
48738
48823
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
48739
48824
  Toast,
48740
48825
  {
@@ -49603,7 +49688,7 @@ var init_WorldMapTemplate = __esm({
49603
49688
  }
49604
49689
  });
49605
49690
  function lazyThree(name, loader) {
49606
- const Lazy = React82__default.lazy(
49691
+ const Lazy = React81__default.lazy(
49607
49692
  () => loader().then((m) => {
49608
49693
  const Resolved = m[name];
49609
49694
  if (!Resolved) {
@@ -49615,13 +49700,13 @@ function lazyThree(name, loader) {
49615
49700
  })
49616
49701
  );
49617
49702
  function ThreeWrapper(props) {
49618
- return React82__default.createElement(
49703
+ return React81__default.createElement(
49619
49704
  ThreeBoundary,
49620
49705
  { name },
49621
- React82__default.createElement(
49622
- React82__default.Suspense,
49706
+ React81__default.createElement(
49707
+ React81__default.Suspense,
49623
49708
  { fallback: null },
49624
- React82__default.createElement(Lazy, props)
49709
+ React81__default.createElement(Lazy, props)
49625
49710
  )
49626
49711
  );
49627
49712
  }
@@ -49919,7 +50004,7 @@ var init_component_registry_generated = __esm({
49919
50004
  init_WorldMapBoard();
49920
50005
  init_WorldMapTemplate();
49921
50006
  init_XPBar();
49922
- ThreeBoundary = class extends React82__default.Component {
50007
+ ThreeBoundary = class extends React81__default.Component {
49923
50008
  constructor() {
49924
50009
  super(...arguments);
49925
50010
  __publicField(this, "state", { failed: false });
@@ -49929,7 +50014,7 @@ var init_component_registry_generated = __esm({
49929
50014
  }
49930
50015
  render() {
49931
50016
  if (this.state.failed) {
49932
- return React82__default.createElement(
50017
+ return React81__default.createElement(
49933
50018
  "div",
49934
50019
  {
49935
50020
  "data-testid": "three-unavailable",
@@ -50270,7 +50355,7 @@ function SuspenseConfigProvider({
50270
50355
  config,
50271
50356
  children
50272
50357
  }) {
50273
- return React82__default.createElement(
50358
+ return React81__default.createElement(
50274
50359
  SuspenseConfigContext.Provider,
50275
50360
  { value: config },
50276
50361
  children
@@ -50760,7 +50845,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
50760
50845
  const key = `${parentId}-${index}-trait:${traitName}`;
50761
50846
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
50762
50847
  }
50763
- return /* @__PURE__ */ jsx(React82__default.Fragment, { children: child }, `${parentId}-${index}`);
50848
+ return /* @__PURE__ */ jsx(React81__default.Fragment, { children: child }, `${parentId}-${index}`);
50764
50849
  }
50765
50850
  if (!child || typeof child !== "object") return null;
50766
50851
  const childId = `${parentId}-${index}`;
@@ -50800,14 +50885,14 @@ function isPatternConfig(value) {
50800
50885
  if (value === null || value === void 0) return false;
50801
50886
  if (typeof value !== "object") return false;
50802
50887
  if (Array.isArray(value)) return false;
50803
- if (React82__default.isValidElement(value)) return false;
50888
+ if (React81__default.isValidElement(value)) return false;
50804
50889
  if (value instanceof Date) return false;
50805
50890
  if (typeof value === "function") return false;
50806
50891
  const record = value;
50807
50892
  return "type" in record && typeof record.type === "string";
50808
50893
  }
50809
50894
  function isPlainConfigObject(value) {
50810
- if (React82__default.isValidElement(value)) return false;
50895
+ if (React81__default.isValidElement(value)) return false;
50811
50896
  if (value instanceof Date) return false;
50812
50897
  const proto = Object.getPrototypeOf(value);
50813
50898
  return proto === Object.prototype || proto === null;
@@ -51235,7 +51320,7 @@ function resolveLambdaBindings(body, params, item, index) {
51235
51320
  if (Array.isArray(body)) {
51236
51321
  return body.map((b) => recur(b));
51237
51322
  }
51238
- if (body !== null && typeof body === "object" && !React82__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
51323
+ if (body !== null && typeof body === "object" && !React81__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
51239
51324
  const out = {};
51240
51325
  for (const [k, v] of Object.entries(body)) {
51241
51326
  out[k] = recur(v);
@@ -51254,7 +51339,7 @@ function getSlotContentRenderer2() {
51254
51339
  function makeLambdaFn(params, lambdaBody, callerKey) {
51255
51340
  return (item, index) => {
51256
51341
  const resolvedBody = resolveLambdaBindings(lambdaBody, params, item, index);
51257
- if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React82__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
51342
+ if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React81__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
51258
51343
  return null;
51259
51344
  }
51260
51345
  const record = resolvedBody;
@@ -51273,7 +51358,7 @@ function makeLambdaFn(params, lambdaBody, callerKey) {
51273
51358
  props: childProps,
51274
51359
  priority: 0
51275
51360
  };
51276
- return React82__default.createElement(SlotContentRenderer2, { content: childContent });
51361
+ return React81__default.createElement(SlotContentRenderer2, { content: childContent });
51277
51362
  };
51278
51363
  }
51279
51364
  function convertNode(node, callerKey) {
@@ -51292,7 +51377,7 @@ function convertNode(node, callerKey) {
51292
51377
  });
51293
51378
  return anyChanged ? mapped : node;
51294
51379
  }
51295
- if (typeof node === "object" && !React82__default.isValidElement(node) && !(node instanceof Date)) {
51380
+ if (typeof node === "object" && !React81__default.isValidElement(node) && !(node instanceof Date)) {
51296
51381
  return convertObjectProps(node);
51297
51382
  }
51298
51383
  return node;
@@ -51327,6 +51412,27 @@ init_verificationRegistry();
51327
51412
  var crossTraitLog = createLogger("almadar:ui:cross-trait");
51328
51413
  var flushLog = createLogger("almadar:ui:slot-flush");
51329
51414
  var stateLog = createLogger("almadar:ui:state-transitions");
51415
+ var tickLog = createLogger("almadar:ui:tick-effects");
51416
+ var SYNC_TICK_OPERATORS = /* @__PURE__ */ new Set([
51417
+ "set",
51418
+ "emit",
51419
+ "render-ui",
51420
+ "render",
51421
+ "navigate",
51422
+ "notify",
51423
+ "log",
51424
+ // Synchronous structural forms that wrap sync effects. A tick authored as
51425
+ // a single top-level `(let ((..)) (do (set ..) (render-ui ..)))` or
51426
+ // `(if cond (set ..) ..)` is one of these at its head — the EffectExecutor
51427
+ // resolves the binding values / condition through the canonical evaluator
51428
+ // and runs the wrapped sync effects. Without these in the allow-list the
51429
+ // whole tick is filtered out (its head op isn't `set`/`emit`/...), so the
51430
+ // physics/gameflow/AI tick never runs.
51431
+ "let",
51432
+ "if",
51433
+ "do",
51434
+ "when"
51435
+ ]);
51330
51436
  function toTraitDefinition(binding) {
51331
51437
  return {
51332
51438
  name: binding.trait.name,
@@ -51523,50 +51629,196 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
51523
51629
  for (const unreg of snapshotUnregs) unreg();
51524
51630
  };
51525
51631
  }, [traitBindings]);
51526
- const runTickEffects = useCallback((tick, binding) => {
51527
- const currentState = traitStatesRef.current.get(binding.trait.name)?.currentState ?? "";
51528
- if (tick.appliesTo.length > 0 && !tick.appliesTo.includes(currentState)) return;
51529
- const bindingCtx = { entity: {}, payload: {}, state: currentState };
51530
- if (binding.config) {
51531
- bindingCtx.config = binding.config;
51532
- }
51533
- const evalCtx = createContextFromBindings(bindingCtx);
51534
- if (tick.guard !== void 0) {
51535
- const passed = interpolateValue(tick.guard, evalCtx);
51536
- if (!passed) return;
51537
- }
51632
+ const executeTransitionEffects = useCallback(async (params) => {
51633
+ const { binding, previousState, newState, payload, flushEvent, syncOnly, log: log14 } = params;
51634
+ const traitName = binding.trait.name;
51635
+ const linkedEntity = binding.linkedEntity || "";
51636
+ const entityId = payload?.entityId;
51637
+ const effects = syncOnly ? params.effects.filter(
51638
+ (e) => Array.isArray(e) && SYNC_TICK_OPERATORS.has(String(e[0]))
51639
+ ) : params.effects;
51640
+ if (effects.length === 0) return [];
51538
51641
  const pendingSlots = /* @__PURE__ */ new Map();
51539
51642
  ({
51540
- trait: binding.trait.name,
51541
- transition: `${currentState}->tick:${tick.name}`,
51542
- effects: tick.effects,
51543
51643
  traitDefinition: binding.trait
51544
51644
  });
51545
- for (const effect of tick.effects) {
51546
- if (!Array.isArray(effect)) continue;
51547
- const op = effect[0];
51548
- if (op === "render-ui" || op === "render") {
51549
- const slot = effect[1];
51550
- const rawPattern = effect[2];
51551
- if (rawPattern === null || rawPattern === void 0) {
51645
+ const clientHandlers = createClientEffectHandlers({
51646
+ eventBus,
51647
+ slotSetter: {
51648
+ addPattern: (slot, pattern, props) => {
51649
+ const existing = pendingSlots.get(slot) || [];
51650
+ existing.push({ pattern, props: props || {} });
51651
+ pendingSlots.set(slot, existing);
51652
+ },
51653
+ clearSlot: (slot) => {
51552
51654
  pendingSlots.set(slot, []);
51553
- continue;
51554
51655
  }
51555
- const updatedCtx = createContextFromBindings(bindingCtx);
51556
- const resolved = interpolateValue(rawPattern, updatedCtx);
51557
- const existing = pendingSlots.get(slot) ?? [];
51558
- existing.push({ pattern: resolved, props: {} });
51559
- pendingSlots.set(slot, existing);
51656
+ },
51657
+ navigate: optionsRef.current?.navigate,
51658
+ notify: optionsRef.current?.notify,
51659
+ callService: optionsRef.current?.callService
51660
+ });
51661
+ const persistence = syncOnly ? void 0 : optionsRef.current?.persistence;
51662
+ let handlers = clientHandlers;
51663
+ if (persistence) {
51664
+ const sharedBindings = {
51665
+ // Seed `@entity` from the trait's scalar field state (a real
51666
+ // EntityRow), the same source the executor's own bindingCtx
51667
+ // uses below. `@payload.*` resolves from `payload` separately,
51668
+ // so dropping the prior `payload as EntityRow` cast loses
51669
+ // nothing — it just stops mislabelling the payload as an entity.
51670
+ entity: traitFieldStatesRef.current.get(traitName) ?? {},
51671
+ payload: payload || {},
51672
+ state: previousState
51673
+ };
51674
+ const sharedDeclared = collectDeclaredConfigDefaults(binding.trait);
51675
+ const sharedCallSite = binding.config;
51676
+ if (sharedDeclared || sharedCallSite) {
51677
+ sharedBindings.config = {
51678
+ ...sharedDeclared ?? {},
51679
+ ...sharedCallSite ?? {}
51680
+ };
51560
51681
  }
51682
+ const serverHandlers = createServerEffectHandlers({
51683
+ persistence,
51684
+ eventBus,
51685
+ entityType: linkedEntity,
51686
+ entityId,
51687
+ bindings: sharedBindings,
51688
+ context: {
51689
+ traitName,
51690
+ state: previousState,
51691
+ transition: `${previousState}->${newState}`,
51692
+ linkedEntity,
51693
+ entityId
51694
+ },
51695
+ source: { trait: traitName },
51696
+ callService: optionsRef.current?.callService
51697
+ });
51698
+ handlers = {
51699
+ ...serverHandlers,
51700
+ emit: clientHandlers.emit,
51701
+ renderUI: clientHandlers.renderUI,
51702
+ navigate: clientHandlers.navigate,
51703
+ notify: clientHandlers.notify
51704
+ };
51561
51705
  }
51562
- for (const [slot, patterns] of pendingSlots) {
51563
- flushSlot(binding.trait.name, slot, patterns, {
51564
- event: `tick:${tick.name}`,
51565
- state: currentState,
51566
- entity: binding.linkedEntity
51706
+ const baseSet = handlers.set;
51707
+ handlers = {
51708
+ ...handlers,
51709
+ set: async (targetId, field, value) => {
51710
+ let fieldState = traitFieldStatesRef.current.get(traitName);
51711
+ if (!fieldState) {
51712
+ fieldState = {};
51713
+ traitFieldStatesRef.current.set(traitName, fieldState);
51714
+ }
51715
+ fieldState[field] = value;
51716
+ log14.debug("set:write", {
51717
+ traitName,
51718
+ field,
51719
+ value: JSON.stringify(value),
51720
+ transition: `${previousState}->${newState}`
51721
+ });
51722
+ if (baseSet) await baseSet(targetId, field, value);
51723
+ }
51724
+ };
51725
+ const entityForBinding = traitFieldStatesRef.current.get(traitName) ?? {};
51726
+ const bindingCtx = {
51727
+ entity: entityForBinding,
51728
+ payload: payload || {},
51729
+ state: previousState
51730
+ };
51731
+ const declaredDefaults = collectDeclaredConfigDefaults(binding.trait);
51732
+ const callSiteConfig = binding.config;
51733
+ if (declaredDefaults || callSiteConfig) {
51734
+ bindingCtx.config = {
51735
+ ...declaredDefaults ?? {},
51736
+ ...callSiteConfig ?? {}
51737
+ };
51738
+ }
51739
+ const effectContext = {
51740
+ traitName,
51741
+ state: previousState,
51742
+ transition: `${previousState}->${newState}`,
51743
+ linkedEntity,
51744
+ entityId
51745
+ };
51746
+ const emittedDuringExec = [];
51747
+ const baseEmit = handlers.emit;
51748
+ const trackingHandlers = {
51749
+ ...handlers,
51750
+ emit: (event, eventPayload, source) => {
51751
+ emittedDuringExec.push(event);
51752
+ baseEmit(event, eventPayload, source);
51753
+ }
51754
+ };
51755
+ const executor = new EffectExecutor({ handlers: trackingHandlers, bindings: bindingCtx, context: effectContext });
51756
+ try {
51757
+ await executor.executeAll(effects);
51758
+ log14.debug("effects:executed", () => ({
51759
+ traitName,
51760
+ transition: `${previousState}->${newState}`,
51761
+ event: flushEvent,
51762
+ effectCount: effects.length,
51763
+ emitted: emittedDuringExec.join(","),
51764
+ entityAfter: JSON.stringify(traitFieldStatesRef.current.get(traitName) ?? {}),
51765
+ slotsTouched: Array.from(pendingSlots.keys()).join(",")
51766
+ }));
51767
+ for (const [slot, patterns] of pendingSlots) {
51768
+ log14.debug("flush:slot", {
51769
+ traitName,
51770
+ slot,
51771
+ patternCount: patterns.length,
51772
+ event: flushEvent,
51773
+ transition: `${previousState}->${newState}`,
51774
+ cleared: patterns.length === 0
51775
+ });
51776
+ flushSlot(traitName, slot, patterns, {
51777
+ event: flushEvent,
51778
+ state: previousState,
51779
+ entity: binding.linkedEntity
51780
+ });
51781
+ }
51782
+ } catch (error) {
51783
+ log14.error("effects:error", {
51784
+ traitName,
51785
+ transition: `${previousState}->${newState}`,
51786
+ event: flushEvent,
51787
+ error: error instanceof Error ? error.message : String(error),
51788
+ effectCount: effects.length
51567
51789
  });
51568
51790
  }
51569
- }, [flushSlot]);
51791
+ return emittedDuringExec;
51792
+ }, [eventBus, flushSlot]);
51793
+ const runTickEffects = useCallback((tick, binding) => {
51794
+ const traitName = binding.trait.name;
51795
+ const currentState = traitStatesRef.current.get(traitName)?.currentState ?? "";
51796
+ if (tick.appliesTo.length > 0 && !tick.appliesTo.includes(currentState)) return;
51797
+ if (tick.guard !== void 0) {
51798
+ const guardCtx = {
51799
+ entity: traitFieldStatesRef.current.get(traitName) ?? {},
51800
+ payload: {},
51801
+ state: currentState
51802
+ };
51803
+ if (binding.config) {
51804
+ guardCtx.config = binding.config;
51805
+ }
51806
+ const passed = interpolateValue(tick.guard, createContextFromBindings(guardCtx));
51807
+ if (!passed) {
51808
+ tickLog.debug("guard-blocked", { traitName, tick: tick.name, state: currentState });
51809
+ return;
51810
+ }
51811
+ }
51812
+ void executeTransitionEffects({
51813
+ binding,
51814
+ effects: tick.effects,
51815
+ previousState: currentState,
51816
+ newState: currentState,
51817
+ flushEvent: `tick:${tick.name}`,
51818
+ syncOnly: true,
51819
+ log: tickLog
51820
+ });
51821
+ }, [executeTransitionEffects]);
51570
51822
  useEffect(() => {
51571
51823
  const hasFrameTicks = traitBindingsRef.current.some(
51572
51824
  (b) => b.trait.ticks?.some((t) => t.interval === "frame")
@@ -51677,161 +51929,17 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
51677
51929
  transition: `${result.previousState} -> ${result.newState}`,
51678
51930
  effects: JSON.stringify(result.effects)
51679
51931
  }));
51680
- const linkedEntity = binding.linkedEntity || "";
51681
- const entityId = payload?.entityId;
51682
- const pendingSlots = /* @__PURE__ */ new Map();
51683
- const slotSource = {
51684
- trait: binding.trait.name,
51685
- state: result.previousState,
51686
- transition: `${result.previousState}->${result.newState}`,
51932
+ const emittedDuringExec = await executeTransitionEffects({
51933
+ binding,
51687
51934
  effects: result.effects,
51688
- traitDefinition: binding.trait
51689
- };
51690
- const clientHandlers = createClientEffectHandlers({
51691
- eventBus,
51692
- slotSetter: {
51693
- addPattern: (slot, pattern, props) => {
51694
- const existing = pendingSlots.get(slot) || [];
51695
- existing.push({ pattern, props: props || {} });
51696
- pendingSlots.set(slot, existing);
51697
- },
51698
- clearSlot: (slot) => {
51699
- pendingSlots.set(slot, []);
51700
- }
51701
- },
51702
- navigate: optionsRef.current?.navigate,
51703
- notify: optionsRef.current?.notify,
51704
- callService: optionsRef.current?.callService
51935
+ previousState: result.previousState,
51936
+ newState: result.newState,
51937
+ payload,
51938
+ flushEvent: eventKey,
51939
+ syncOnly: false,
51940
+ log: stateLog
51705
51941
  });
51706
- const persistence = optionsRef.current?.persistence;
51707
- let handlers = clientHandlers;
51708
- if (persistence) {
51709
- const sharedBindings = {
51710
- entity: payload ?? {},
51711
- payload: payload || {},
51712
- state: result.previousState
51713
- };
51714
- const sharedDeclared = collectDeclaredConfigDefaults(
51715
- binding.trait
51716
- );
51717
- const sharedCallSite = binding.config;
51718
- if (sharedDeclared || sharedCallSite) {
51719
- sharedBindings.config = {
51720
- ...sharedDeclared ?? {},
51721
- ...sharedCallSite ?? {}
51722
- };
51723
- }
51724
- const serverHandlers = createServerEffectHandlers({
51725
- persistence,
51726
- eventBus,
51727
- entityType: linkedEntity,
51728
- entityId,
51729
- bindings: sharedBindings,
51730
- context: {
51731
- traitName: binding.trait.name,
51732
- state: result.previousState,
51733
- transition: `${result.previousState}->${result.newState}`,
51734
- linkedEntity,
51735
- entityId
51736
- },
51737
- source: { trait: binding.trait.name },
51738
- callService: optionsRef.current?.callService
51739
- });
51740
- handlers = {
51741
- ...serverHandlers,
51742
- // Client handlers own UI + emit: keep the slot setter
51743
- // and pre-prefixed UI:* emit path intact.
51744
- emit: clientHandlers.emit,
51745
- renderUI: clientHandlers.renderUI,
51746
- navigate: clientHandlers.navigate,
51747
- notify: clientHandlers.notify
51748
- };
51749
- }
51750
- const baseSet = handlers.set;
51751
- handlers = {
51752
- ...handlers,
51753
- set: async (targetId, field, value) => {
51754
- let fieldState = traitFieldStatesRef.current.get(traitName);
51755
- if (!fieldState) {
51756
- fieldState = {};
51757
- traitFieldStatesRef.current.set(traitName, fieldState);
51758
- }
51759
- fieldState[field] = value;
51760
- if (baseSet) await baseSet(targetId, field, value);
51761
- }
51762
- };
51763
- const entityForBinding = traitFieldStatesRef.current.get(traitName) ?? {};
51764
- const bindingCtx = {
51765
- entity: entityForBinding,
51766
- payload: payload || {},
51767
- state: result.previousState
51768
- };
51769
- const declaredDefaults = collectDeclaredConfigDefaults(
51770
- binding.trait
51771
- );
51772
- const callSiteConfig = binding.config;
51773
- if (declaredDefaults || callSiteConfig) {
51774
- bindingCtx.config = {
51775
- ...declaredDefaults ?? {},
51776
- ...callSiteConfig ?? {}
51777
- };
51778
- }
51779
- const effectContext = {
51780
- traitName: binding.trait.name,
51781
- state: result.previousState,
51782
- transition: `${result.previousState}->${result.newState}`,
51783
- linkedEntity,
51784
- entityId
51785
- };
51786
- const emittedDuringExec = [];
51787
51942
  emittedByTrait.set(traitName, emittedDuringExec);
51788
- const baseEmit = handlers.emit;
51789
- const trackingHandlers = {
51790
- ...handlers,
51791
- emit: (event, eventPayload, source) => {
51792
- emittedDuringExec.push(event);
51793
- baseEmit(event, eventPayload, source);
51794
- }
51795
- };
51796
- const executor = new EffectExecutor({ handlers: trackingHandlers, bindings: bindingCtx, context: effectContext });
51797
- try {
51798
- await executor.executeAll(result.effects);
51799
- stateLog.debug("transition:render-ui-dispatched", () => ({
51800
- traitName,
51801
- fromState: result.previousState,
51802
- toState: result.newState,
51803
- event: eventKey,
51804
- slotsTouched: Array.from(pendingSlots.keys()).join(","),
51805
- patternTypes: Array.from(pendingSlots.entries()).map(
51806
- ([slot, patterns]) => `${slot}:[${patterns.map((p2) => p2.pattern?.type ?? "null").join(",")}]`
51807
- ).join(";")
51808
- }));
51809
- void slotSource;
51810
- for (const [slot, patterns] of pendingSlots) {
51811
- stateLog.debug("flush:slot", {
51812
- traitName,
51813
- slot,
51814
- patternCount: patterns.length,
51815
- event: eventKey,
51816
- transition: `${result.previousState}->${result.newState}`,
51817
- cleared: patterns.length === 0
51818
- });
51819
- flushSlot(traitName, slot, patterns, {
51820
- event: eventKey,
51821
- state: result.previousState,
51822
- entity: binding.linkedEntity
51823
- });
51824
- }
51825
- } catch (error) {
51826
- stateLog.error("transition:effect-error", {
51827
- traitName,
51828
- fromState: result.previousState,
51829
- toState: result.newState,
51830
- event: eventKey,
51831
- error: error instanceof Error ? error.message : String(error),
51832
- effectCount: result.effects.length
51833
- });
51834
- }
51835
51943
  } else if (!result.executed) {
51836
51944
  if (result.guardResult === false) {
51837
51945
  stateLog.debug("guard-blocked-transition", {
@@ -52126,7 +52234,7 @@ function clearSchemaCache() {
52126
52234
 
52127
52235
  // runtime/index.ts
52128
52236
  init_EntitySchemaContext();
52129
- var log12 = createLogger("almadar:ui:trait-provider");
52237
+ var log11 = createLogger("almadar:ui:trait-provider");
52130
52238
  var TraitContext = createContext(null);
52131
52239
  function TraitProvider({
52132
52240
  traits: traitBindings,
@@ -52143,7 +52251,7 @@ function TraitProvider({
52143
52251
  currentState: stateName,
52144
52252
  availableEvents: trait.transitions.filter((t) => t.from === stateName).map((t) => t.event),
52145
52253
  dispatch: (eventKey, payload) => {
52146
- log12.debug("Dispatch", () => ({
52254
+ log11.debug("Dispatch", () => ({
52147
52255
  trait: trait.name,
52148
52256
  event: eventKey,
52149
52257
  payloadKeys: payload ? Object.keys(payload) : []
@@ -52486,9 +52594,175 @@ function ServerBridgeProvider({
52486
52594
  }, [schema, registerSchema, unregisterSchema]);
52487
52595
  return /* @__PURE__ */ jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
52488
52596
  }
52489
-
52490
- // context/OrbitalThemeProvider.tsx
52491
- init_ThemeContext();
52597
+ createLogger("almadar:ui:theme");
52598
+ var BUILT_IN_THEMES = [
52599
+ {
52600
+ name: "wireframe",
52601
+ displayName: "Wireframe",
52602
+ hasLightMode: true,
52603
+ hasDarkMode: true
52604
+ },
52605
+ {
52606
+ name: "minimalist",
52607
+ displayName: "Minimalist",
52608
+ hasLightMode: true,
52609
+ hasDarkMode: true
52610
+ },
52611
+ {
52612
+ name: "almadar",
52613
+ displayName: "Almadar",
52614
+ hasLightMode: true,
52615
+ hasDarkMode: true
52616
+ },
52617
+ {
52618
+ name: "trait-wars",
52619
+ displayName: "Trait Wars",
52620
+ hasLightMode: false,
52621
+ hasDarkMode: true
52622
+ },
52623
+ // Extended themes
52624
+ {
52625
+ name: "ocean",
52626
+ displayName: "Ocean",
52627
+ hasLightMode: true,
52628
+ hasDarkMode: true
52629
+ },
52630
+ {
52631
+ name: "forest",
52632
+ displayName: "Forest",
52633
+ hasLightMode: true,
52634
+ hasDarkMode: true
52635
+ },
52636
+ {
52637
+ name: "sunset",
52638
+ displayName: "Sunset",
52639
+ hasLightMode: true,
52640
+ hasDarkMode: true
52641
+ },
52642
+ {
52643
+ name: "lavender",
52644
+ displayName: "Lavender",
52645
+ hasLightMode: true,
52646
+ hasDarkMode: true
52647
+ },
52648
+ {
52649
+ name: "rose",
52650
+ displayName: "Rose",
52651
+ hasLightMode: true,
52652
+ hasDarkMode: true
52653
+ },
52654
+ {
52655
+ name: "slate",
52656
+ displayName: "Slate",
52657
+ hasLightMode: true,
52658
+ hasDarkMode: true
52659
+ },
52660
+ {
52661
+ name: "ember",
52662
+ displayName: "Ember",
52663
+ hasLightMode: true,
52664
+ hasDarkMode: true
52665
+ },
52666
+ {
52667
+ name: "midnight",
52668
+ displayName: "Midnight",
52669
+ hasLightMode: true,
52670
+ hasDarkMode: true
52671
+ },
52672
+ {
52673
+ name: "sand",
52674
+ displayName: "Sand",
52675
+ hasLightMode: true,
52676
+ hasDarkMode: true
52677
+ },
52678
+ {
52679
+ name: "neon",
52680
+ displayName: "Neon",
52681
+ hasLightMode: true,
52682
+ hasDarkMode: true
52683
+ },
52684
+ {
52685
+ name: "arctic",
52686
+ displayName: "Arctic",
52687
+ hasLightMode: true,
52688
+ hasDarkMode: true
52689
+ },
52690
+ {
52691
+ name: "copper",
52692
+ displayName: "Copper",
52693
+ hasLightMode: true,
52694
+ hasDarkMode: true
52695
+ },
52696
+ // Layer 1 skin axes — truly-unique themes (compact tech / editorial / brutalist dense / display-heavy / touch-first)
52697
+ {
52698
+ name: "prism",
52699
+ displayName: "Prism",
52700
+ hasLightMode: true,
52701
+ hasDarkMode: true
52702
+ },
52703
+ {
52704
+ name: "gazette",
52705
+ displayName: "Gazette",
52706
+ hasLightMode: true,
52707
+ hasDarkMode: true
52708
+ },
52709
+ {
52710
+ name: "terminal",
52711
+ displayName: "Terminal",
52712
+ hasLightMode: true,
52713
+ hasDarkMode: true
52714
+ },
52715
+ {
52716
+ name: "atelier",
52717
+ displayName: "Atelier",
52718
+ hasLightMode: true,
52719
+ hasDarkMode: true
52720
+ },
52721
+ {
52722
+ name: "kiosk",
52723
+ displayName: "Kiosk",
52724
+ hasLightMode: true,
52725
+ hasDarkMode: true
52726
+ },
52727
+ {
52728
+ name: "linear-clean",
52729
+ displayName: "Linear Clean",
52730
+ hasLightMode: true,
52731
+ hasDarkMode: true
52732
+ },
52733
+ {
52734
+ name: "notion-editorial",
52735
+ displayName: "Notion Editorial",
52736
+ hasLightMode: true,
52737
+ hasDarkMode: true
52738
+ },
52739
+ {
52740
+ name: "bloomberg-dense",
52741
+ displayName: "Bloomberg Dense",
52742
+ hasLightMode: true,
52743
+ hasDarkMode: true
52744
+ }
52745
+ ];
52746
+ var ThemeContext = createContext(void 0);
52747
+ function useTheme2() {
52748
+ const context = useContext(ThemeContext);
52749
+ if (context === void 0) {
52750
+ return {
52751
+ theme: "wireframe",
52752
+ mode: "light",
52753
+ resolvedMode: "light",
52754
+ setTheme: () => {
52755
+ },
52756
+ setMode: () => {
52757
+ },
52758
+ toggleMode: () => {
52759
+ },
52760
+ availableThemes: BUILT_IN_THEMES,
52761
+ appliedTheme: "wireframe-light"
52762
+ };
52763
+ }
52764
+ return context;
52765
+ }
52492
52766
 
52493
52767
  // context/themeTokens.ts
52494
52768
  function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
@@ -52707,7 +52981,7 @@ function resolveThemeForRuntime(theme) {
52707
52981
  }
52708
52982
  function OrbitalThemeProvider({ theme, children }) {
52709
52983
  const resolved = resolveThemeForRuntime(theme);
52710
- const { resolvedMode } = useTheme();
52984
+ const { resolvedMode } = useTheme2();
52711
52985
  if (!resolved) {
52712
52986
  return /* @__PURE__ */ jsx(Fragment, { children });
52713
52987
  }