@almadar/ui 5.21.12 → 5.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/avl/index.cjs +919 -631
  2. package/dist/avl/index.js +919 -631
  3. package/dist/components/core/molecules/CalendarGrid.d.ts +3 -10
  4. package/dist/components/core/molecules/ContentRenderer.d.ts +2 -2
  5. package/dist/components/core/molecules/DataGrid.d.ts +11 -20
  6. package/dist/components/core/molecules/DataList.d.ts +9 -15
  7. package/dist/components/core/molecules/FormSection.d.ts +4 -4
  8. package/dist/components/core/molecules/PositionedCanvas.d.ts +4 -17
  9. package/dist/components/core/molecules/ReplyTree.d.ts +2 -13
  10. package/dist/components/core/molecules/RichBlockEditor.d.ts +3 -6
  11. package/dist/components/core/molecules/SortableList.d.ts +7 -5
  12. package/dist/components/core/molecules/TableView.d.ts +7 -7
  13. package/dist/components/core/molecules/index.d.ts +3 -3
  14. package/dist/components/core/molecules/useDataDnd.d.ts +5 -5
  15. package/dist/components/core/organisms/CardGrid.d.ts +5 -2
  16. package/dist/components/core/organisms/CaseStudyOrganism.d.ts +4 -3
  17. package/dist/components/core/organisms/DataTable.d.ts +4 -2
  18. package/dist/components/core/organisms/DetailPanel.d.ts +6 -6
  19. package/dist/components/core/organisms/FeatureGridOrganism.d.ts +4 -3
  20. package/dist/components/core/organisms/HeroOrganism.d.ts +4 -5
  21. package/dist/components/core/organisms/List.d.ts +5 -2
  22. package/dist/components/core/organisms/MasterDetail.d.ts +4 -2
  23. package/dist/components/core/organisms/MediaGallery.d.ts +4 -2
  24. package/dist/components/core/organisms/ShowcaseOrganism.d.ts +4 -3
  25. package/dist/components/core/organisms/StatCard.d.ts +5 -2
  26. package/dist/components/core/organisms/StepFlowOrganism.d.ts +4 -3
  27. package/dist/components/core/organisms/Timeline.d.ts +2 -2
  28. package/dist/components/core/organisms/book/index.d.ts +1 -1
  29. package/dist/components/core/organisms/book/types.d.ts +28 -48
  30. package/dist/components/core/organisms/index.d.ts +1 -2
  31. package/dist/components/core/organisms/layout/DashboardGrid.d.ts +2 -2
  32. package/dist/components/core/organisms/marketing-types.d.ts +5 -94
  33. package/dist/components/core/organisms/types.d.ts +9 -27
  34. package/dist/components/core/templates/index.d.ts +6 -6
  35. package/dist/components/game/organisms/BattleBoard.d.ts +14 -90
  36. package/dist/components/game/organisms/CastleBoard.d.ts +7 -21
  37. package/dist/components/game/organisms/UncontrolledBattleBoard.d.ts +2 -7
  38. package/dist/components/game/organisms/WorldMapBoard.d.ts +13 -59
  39. package/dist/components/game/organisms/boardEntity.d.ts +44 -0
  40. package/dist/components/game/organisms/hooks/useBattleState.d.ts +7 -7
  41. package/dist/components/game/organisms/index.d.ts +3 -3
  42. package/dist/components/game/organisms/puzzles/builder/BuilderBoard.d.ts +7 -20
  43. package/dist/components/game/organisms/puzzles/builder/index.d.ts +1 -1
  44. package/dist/components/game/organisms/puzzles/classifier/ClassifierBoard.d.ts +7 -20
  45. package/dist/components/game/organisms/puzzles/classifier/index.d.ts +1 -1
  46. package/dist/components/game/organisms/puzzles/debugger/DebuggerBoard.d.ts +6 -22
  47. package/dist/components/game/organisms/puzzles/debugger/index.d.ts +1 -1
  48. package/dist/components/game/organisms/puzzles/event-handler/EventHandlerBoard.d.ts +6 -33
  49. package/dist/components/game/organisms/puzzles/event-handler/ObjectRulePanel.d.ts +3 -21
  50. package/dist/components/game/organisms/puzzles/event-handler/index.d.ts +2 -2
  51. package/dist/components/game/organisms/puzzles/event-handler/puzzleObject.d.ts +21 -0
  52. package/dist/components/game/organisms/puzzles/negotiator/NegotiatorBoard.d.ts +8 -24
  53. package/dist/components/game/organisms/puzzles/negotiator/index.d.ts +1 -1
  54. package/dist/components/game/organisms/puzzles/sequencer/ActionTile.d.ts +2 -2
  55. package/dist/components/game/organisms/puzzles/sequencer/SequencerBoard.d.ts +7 -36
  56. package/dist/components/game/organisms/puzzles/sequencer/index.d.ts +1 -1
  57. package/dist/components/game/organisms/puzzles/simulator/SimulatorBoard.d.ts +6 -25
  58. package/dist/components/game/organisms/puzzles/simulator/index.d.ts +1 -1
  59. package/dist/components/game/organisms/puzzles/state-architect/StateArchitectBoard.d.ts +7 -40
  60. package/dist/components/game/organisms/puzzles/state-architect/VariablePanel.d.ts +3 -9
  61. package/dist/components/game/organisms/puzzles/state-architect/index.d.ts +2 -2
  62. package/dist/components/game/organisms/three/index.cjs +35 -21
  63. package/dist/components/game/organisms/three/index.js +35 -21
  64. package/dist/components/game/templates/BattleTemplate.d.ts +2 -3
  65. package/dist/components/game/templates/CastleTemplate.d.ts +2 -3
  66. package/dist/components/game/templates/GameCanvas3DBattleTemplate.d.ts +1 -16
  67. package/dist/components/game/templates/GameCanvas3DCastleTemplate.d.ts +1 -18
  68. package/dist/components/game/templates/GameCanvas3DWorldMapTemplate.d.ts +1 -14
  69. package/dist/components/game/templates/GameTemplate.d.ts +1 -6
  70. package/dist/components/game/templates/WorldMapTemplate.d.ts +2 -3
  71. package/dist/components/index.cjs +2016 -1668
  72. package/dist/components/index.js +1128 -780
  73. package/dist/components/marketing/organisms/PricingOrganism.d.ts +4 -3
  74. package/dist/components/marketing/organisms/StatsOrganism.d.ts +4 -3
  75. package/dist/components/marketing/organisms/TeamOrganism.d.ts +4 -3
  76. package/dist/components/marketing/organisms/book/BookChapterView.d.ts +5 -2
  77. package/dist/components/marketing/organisms/book/BookTableOfContents.d.ts +3 -2
  78. package/dist/components/marketing/organisms/book/BookViewer.d.ts +4 -4
  79. package/dist/components/marketing/templates/AboutPageTemplate.d.ts +32 -6
  80. package/dist/components/marketing/templates/FeatureDetailPageTemplate.d.ts +14 -4
  81. package/dist/components/marketing/templates/LandingPageTemplate.d.ts +47 -9
  82. package/dist/components/marketing/templates/PricingPageTemplate.d.ts +23 -5
  83. package/dist/providers/index.cjs +912 -624
  84. package/dist/providers/index.js +912 -624
  85. package/dist/runtime/index.cjs +914 -626
  86. package/dist/runtime/index.js +914 -626
  87. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import * as React79 from 'react';
3
- import React79__default, { useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState, lazy, createContext, useLayoutEffect, useId, useSyncExternalStore } from 'react';
2
+ import * as React80 from 'react';
3
+ import React80__default, { useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState, lazy, createContext, useLayoutEffect, useId, useSyncExternalStore } from 'react';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { EventBusContext, useTraitScope, TraitScopeProvider } from '@almadar/ui/providers';
@@ -211,7 +211,7 @@ var init_SvgFlow = __esm({
211
211
  opacity = 1,
212
212
  className
213
213
  }) => {
214
- const markerId = React79__default.useMemo(() => {
214
+ const markerId = React80__default.useMemo(() => {
215
215
  flowIdCounter += 1;
216
216
  return `almadar-flow-arrow-${flowIdCounter}`;
217
217
  }, []);
@@ -260,7 +260,7 @@ var init_SvgGrid = __esm({
260
260
  x,
261
261
  y,
262
262
  cols = 4,
263
- rows = 3,
263
+ rows: rows2 = 3,
264
264
  spacing = 20,
265
265
  nodeRadius = 3,
266
266
  color = "var(--color-primary)",
@@ -269,7 +269,7 @@ var init_SvgGrid = __esm({
269
269
  highlights = []
270
270
  }) => {
271
271
  const highlightSet = new Set(highlights);
272
- return /* @__PURE__ */ jsx("g", { className, opacity, children: Array.from({ length: rows }).map(
272
+ return /* @__PURE__ */ jsx("g", { className, opacity, children: Array.from({ length: rows2 }).map(
273
273
  (_, row) => Array.from({ length: cols }).map((_2, col) => {
274
274
  const index = row * cols + col;
275
275
  const isHighlighted = highlightSet.has(index);
@@ -754,7 +754,7 @@ var init_SvgRing = __esm({
754
754
  className,
755
755
  label
756
756
  }) => {
757
- const gradientId = React79__default.useMemo(() => {
757
+ const gradientId = React80__default.useMemo(() => {
758
758
  ringIdCounter += 1;
759
759
  return `almadar-ring-glow-${ringIdCounter}`;
760
760
  }, []);
@@ -1836,7 +1836,7 @@ var init_Icon = __esm({
1836
1836
  const directIcon = typeof icon === "string" ? void 0 : icon;
1837
1837
  const effectiveName = typeof icon === "string" ? icon : name;
1838
1838
  const family = useIconFamily();
1839
- const RenderedComponent = React79__default.useMemo(() => {
1839
+ const RenderedComponent = React80__default.useMemo(() => {
1840
1840
  if (directIcon) return null;
1841
1841
  return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
1842
1842
  }, [directIcon, effectiveName, family]);
@@ -1894,7 +1894,7 @@ function resolveIconProp(value, sizeClass) {
1894
1894
  const IconComp = value;
1895
1895
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
1896
1896
  }
1897
- if (React79__default.isValidElement(value)) {
1897
+ if (React80__default.isValidElement(value)) {
1898
1898
  return value;
1899
1899
  }
1900
1900
  if (typeof value === "object" && value !== null && "render" in value) {
@@ -1970,7 +1970,7 @@ var init_Button = __esm({
1970
1970
  md: "h-icon-default w-icon-default",
1971
1971
  lg: "h-icon-default w-icon-default"
1972
1972
  };
1973
- Button = React79__default.forwardRef(
1973
+ Button = React80__default.forwardRef(
1974
1974
  ({
1975
1975
  className,
1976
1976
  variant = "primary",
@@ -2036,7 +2036,7 @@ var init_Input = __esm({
2036
2036
  "components/core/atoms/Input.tsx"() {
2037
2037
  init_cn();
2038
2038
  init_Icon();
2039
- Input = React79__default.forwardRef(
2039
+ Input = React80__default.forwardRef(
2040
2040
  ({
2041
2041
  className,
2042
2042
  inputType,
@@ -2049,7 +2049,7 @@ var init_Input = __esm({
2049
2049
  onClear,
2050
2050
  value,
2051
2051
  options,
2052
- rows = 3,
2052
+ rows: rows2 = 3,
2053
2053
  onChange,
2054
2054
  ...props
2055
2055
  }, ref) => {
@@ -2099,7 +2099,7 @@ var init_Input = __esm({
2099
2099
  ref,
2100
2100
  value,
2101
2101
  onChange,
2102
- rows,
2102
+ rows: rows2,
2103
2103
  className: baseClassName,
2104
2104
  ...props
2105
2105
  }
@@ -2157,7 +2157,7 @@ var Label;
2157
2157
  var init_Label = __esm({
2158
2158
  "components/core/atoms/Label.tsx"() {
2159
2159
  init_cn();
2160
- Label = React79__default.forwardRef(
2160
+ Label = React80__default.forwardRef(
2161
2161
  ({ className, required, children, ...props }, ref) => {
2162
2162
  return /* @__PURE__ */ jsxs(
2163
2163
  "label",
@@ -2183,7 +2183,7 @@ var Textarea;
2183
2183
  var init_Textarea = __esm({
2184
2184
  "components/core/atoms/Textarea.tsx"() {
2185
2185
  init_cn();
2186
- Textarea = React79__default.forwardRef(
2186
+ Textarea = React80__default.forwardRef(
2187
2187
  ({ className, error, ...props }, ref) => {
2188
2188
  return /* @__PURE__ */ jsx(
2189
2189
  "textarea",
@@ -2213,7 +2213,7 @@ var init_Select = __esm({
2213
2213
  "components/core/atoms/Select.tsx"() {
2214
2214
  init_cn();
2215
2215
  init_Icon();
2216
- Select = React79__default.forwardRef(
2216
+ Select = React80__default.forwardRef(
2217
2217
  ({ className, options, placeholder, error, ...props }, ref) => {
2218
2218
  return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2219
2219
  /* @__PURE__ */ jsxs(
@@ -2255,7 +2255,7 @@ var Checkbox;
2255
2255
  var init_Checkbox = __esm({
2256
2256
  "components/core/atoms/Checkbox.tsx"() {
2257
2257
  init_cn();
2258
- Checkbox = React79__default.forwardRef(
2258
+ Checkbox = React80__default.forwardRef(
2259
2259
  ({ className, label, id, ...props }, ref) => {
2260
2260
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
2261
2261
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
@@ -2346,7 +2346,7 @@ var init_Card = __esm({
2346
2346
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
2347
2347
  "tile-image-first": "p-0 overflow-hidden"
2348
2348
  };
2349
- Card = React79__default.forwardRef(
2349
+ Card = React80__default.forwardRef(
2350
2350
  ({
2351
2351
  className,
2352
2352
  variant = "bordered",
@@ -2384,9 +2384,9 @@ var init_Card = __esm({
2384
2384
  }
2385
2385
  );
2386
2386
  Card.displayName = "Card";
2387
- CardHeader = React79__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
2387
+ CardHeader = React80__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
2388
2388
  CardHeader.displayName = "CardHeader";
2389
- CardTitle = React79__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2389
+ CardTitle = React80__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2390
2390
  "h3",
2391
2391
  {
2392
2392
  ref,
@@ -2399,11 +2399,11 @@ var init_Card = __esm({
2399
2399
  }
2400
2400
  ));
2401
2401
  CardTitle.displayName = "CardTitle";
2402
- CardContent = React79__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
2402
+ CardContent = React80__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
2403
2403
  CardContent.displayName = "CardContent";
2404
2404
  CardBody = CardContent;
2405
2405
  CardBody.displayName = "CardBody";
2406
- CardFooter = React79__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2406
+ CardFooter = React80__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2407
2407
  "div",
2408
2408
  {
2409
2409
  ref,
@@ -2456,7 +2456,7 @@ var init_Badge = __esm({
2456
2456
  md: "px-2.5 py-1 text-sm",
2457
2457
  lg: "px-3 py-1.5 text-base"
2458
2458
  };
2459
- Badge = React79__default.forwardRef(
2459
+ Badge = React80__default.forwardRef(
2460
2460
  ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
2461
2461
  const iconSizes3 = {
2462
2462
  sm: "h-icon-default w-icon-default",
@@ -2549,7 +2549,7 @@ var init_FilterPill = __esm({
2549
2549
  md: "w-3.5 h-3.5",
2550
2550
  lg: "w-4 h-4"
2551
2551
  };
2552
- FilterPill = React79__default.forwardRef(
2552
+ FilterPill = React80__default.forwardRef(
2553
2553
  ({
2554
2554
  className,
2555
2555
  variant = "default",
@@ -2626,7 +2626,7 @@ var init_Spinner = __esm({
2626
2626
  md: "h-6 w-6",
2627
2627
  lg: "h-8 w-8"
2628
2628
  };
2629
- Spinner = React79__default.forwardRef(
2629
+ Spinner = React80__default.forwardRef(
2630
2630
  ({ className, size = "md", ...props }, ref) => {
2631
2631
  return /* @__PURE__ */ jsx(
2632
2632
  "div",
@@ -2910,7 +2910,7 @@ var init_Box = __esm({
2910
2910
  fixed: "fixed",
2911
2911
  sticky: "sticky"
2912
2912
  };
2913
- Box = React79__default.forwardRef(
2913
+ Box = React80__default.forwardRef(
2914
2914
  ({
2915
2915
  padding,
2916
2916
  paddingX,
@@ -2960,7 +2960,7 @@ var init_Box = __esm({
2960
2960
  onMouseLeave?.(e);
2961
2961
  }, [hoverEvent, eventBus, onMouseLeave]);
2962
2962
  const isClickable = action || onClick;
2963
- return React79__default.createElement(
2963
+ return React80__default.createElement(
2964
2964
  Component,
2965
2965
  {
2966
2966
  ref,
@@ -3282,7 +3282,7 @@ var init_Radio = __esm({
3282
3282
  md: "w-2.5 h-2.5",
3283
3283
  lg: "w-3 h-3"
3284
3284
  };
3285
- Radio = React79__default.forwardRef(
3285
+ Radio = React80__default.forwardRef(
3286
3286
  ({
3287
3287
  label,
3288
3288
  helperText,
@@ -3299,12 +3299,12 @@ var init_Radio = __esm({
3299
3299
  onChange,
3300
3300
  ...props
3301
3301
  }, ref) => {
3302
- const reactId = React79__default.useId();
3302
+ const reactId = React80__default.useId();
3303
3303
  const baseId = id || `radio-${reactId}`;
3304
3304
  const hasError = !!error;
3305
3305
  const eventBus = useEventBus();
3306
- const [selected, setSelected] = React79__default.useState(value);
3307
- React79__default.useEffect(() => {
3306
+ const [selected, setSelected] = React80__default.useState(value);
3307
+ React80__default.useEffect(() => {
3308
3308
  if (value !== void 0) setSelected(value);
3309
3309
  }, [value]);
3310
3310
  const pick = (next, e) => {
@@ -3486,7 +3486,7 @@ var init_Switch = __esm({
3486
3486
  "components/core/atoms/Switch.tsx"() {
3487
3487
  "use client";
3488
3488
  init_cn();
3489
- Switch = React79.forwardRef(
3489
+ Switch = React80.forwardRef(
3490
3490
  ({
3491
3491
  checked,
3492
3492
  defaultChecked = false,
@@ -3497,10 +3497,10 @@ var init_Switch = __esm({
3497
3497
  name,
3498
3498
  className
3499
3499
  }, ref) => {
3500
- const [isChecked, setIsChecked] = React79.useState(
3500
+ const [isChecked, setIsChecked] = React80.useState(
3501
3501
  checked !== void 0 ? checked : defaultChecked
3502
3502
  );
3503
- React79.useEffect(() => {
3503
+ React80.useEffect(() => {
3504
3504
  if (checked !== void 0) {
3505
3505
  setIsChecked(checked);
3506
3506
  }
@@ -4371,7 +4371,7 @@ var Dialog;
4371
4371
  var init_Dialog = __esm({
4372
4372
  "components/core/atoms/Dialog.tsx"() {
4373
4373
  init_cn();
4374
- Dialog = React79__default.forwardRef(
4374
+ Dialog = React80__default.forwardRef(
4375
4375
  ({
4376
4376
  role = "dialog",
4377
4377
  "aria-modal": ariaModal = true,
@@ -4397,7 +4397,7 @@ var Aside;
4397
4397
  var init_Aside = __esm({
4398
4398
  "components/core/atoms/Aside.tsx"() {
4399
4399
  init_cn();
4400
- Aside = React79__default.forwardRef(
4400
+ Aside = React80__default.forwardRef(
4401
4401
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
4402
4402
  );
4403
4403
  Aside.displayName = "Aside";
@@ -4475,8 +4475,8 @@ var init_LawReferenceTooltip = __esm({
4475
4475
  className
4476
4476
  }) => {
4477
4477
  const { t } = useTranslate();
4478
- const [isVisible, setIsVisible] = React79__default.useState(false);
4479
- const timeoutRef = React79__default.useRef(null);
4478
+ const [isVisible, setIsVisible] = React80__default.useState(false);
4479
+ const timeoutRef = React80__default.useRef(null);
4480
4480
  const handleMouseEnter = () => {
4481
4481
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
4482
4482
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -4485,7 +4485,7 @@ var init_LawReferenceTooltip = __esm({
4485
4485
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
4486
4486
  setIsVisible(false);
4487
4487
  };
4488
- React79__default.useEffect(() => {
4488
+ React80__default.useEffect(() => {
4489
4489
  return () => {
4490
4490
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
4491
4491
  };
@@ -4695,7 +4695,7 @@ var init_StatusDot = __esm({
4695
4695
  md: "w-2.5 h-2.5",
4696
4696
  lg: "w-3 h-3"
4697
4697
  };
4698
- StatusDot = React79__default.forwardRef(
4698
+ StatusDot = React80__default.forwardRef(
4699
4699
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
4700
4700
  return /* @__PURE__ */ jsx(
4701
4701
  "span",
@@ -4749,7 +4749,7 @@ var init_TrendIndicator = __esm({
4749
4749
  down: "trending-down",
4750
4750
  flat: "arrow-right"
4751
4751
  };
4752
- TrendIndicator = React79__default.forwardRef(
4752
+ TrendIndicator = React80__default.forwardRef(
4753
4753
  ({
4754
4754
  className,
4755
4755
  value,
@@ -4816,7 +4816,7 @@ var init_RangeSlider = __esm({
4816
4816
  md: "w-4 h-4",
4817
4817
  lg: "w-5 h-5"
4818
4818
  };
4819
- RangeSlider = React79__default.forwardRef(
4819
+ RangeSlider = React80__default.forwardRef(
4820
4820
  ({
4821
4821
  className,
4822
4822
  min = 0,
@@ -5412,7 +5412,7 @@ var init_ContentSection = __esm({
5412
5412
  md: "py-16",
5413
5413
  lg: "py-24"
5414
5414
  };
5415
- ContentSection = React79__default.forwardRef(
5415
+ ContentSection = React80__default.forwardRef(
5416
5416
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
5417
5417
  return /* @__PURE__ */ jsx(
5418
5418
  Box,
@@ -5946,7 +5946,7 @@ var init_AnimatedReveal = __esm({
5946
5946
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
5947
5947
  "none": {}
5948
5948
  };
5949
- AnimatedReveal = React79__default.forwardRef(
5949
+ AnimatedReveal = React80__default.forwardRef(
5950
5950
  ({
5951
5951
  trigger = "scroll",
5952
5952
  animation = "fade-up",
@@ -6106,7 +6106,7 @@ var init_AnimatedGraphic = __esm({
6106
6106
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
6107
6107
  "use client";
6108
6108
  init_cn();
6109
- AnimatedGraphic = React79__default.forwardRef(
6109
+ AnimatedGraphic = React80__default.forwardRef(
6110
6110
  ({
6111
6111
  src,
6112
6112
  svgContent,
@@ -6129,7 +6129,7 @@ var init_AnimatedGraphic = __esm({
6129
6129
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
6130
6130
  const resolvedSvg = svgContent ?? fetchedSvg;
6131
6131
  const prevAnimateRef = useRef(animate);
6132
- const setRef = React79__default.useCallback(
6132
+ const setRef = React80__default.useCallback(
6133
6133
  (node) => {
6134
6134
  containerRef.current = node;
6135
6135
  if (typeof ref === "function") ref(node);
@@ -6819,7 +6819,7 @@ var init_ErrorBoundary = __esm({
6819
6819
  }
6820
6820
  );
6821
6821
  };
6822
- ErrorBoundary = class extends React79__default.Component {
6822
+ ErrorBoundary = class extends React80__default.Component {
6823
6823
  constructor(props) {
6824
6824
  super(props);
6825
6825
  __publicField(this, "reset", () => {
@@ -6864,15 +6864,15 @@ function HeaderSkeleton({ className }) {
6864
6864
  ] })
6865
6865
  ] });
6866
6866
  }
6867
- function TableSkeleton({ rows = 5, columns = 4, className }) {
6867
+ function TableSkeleton({ rows: rows2 = 5, columns = 4, className }) {
6868
6868
  return /* @__PURE__ */ jsxs(VStack, { gap: "none", className: cn("border border-border rounded-lg overflow-hidden", className), children: [
6869
6869
  /* @__PURE__ */ jsx(HStack, { className: "px-4 py-3 bg-muted/30 border-b border-border", children: Array.from({ length: columns }).map((_, i) => /* @__PURE__ */ jsx(SkeletonBlock, { className: "h-4 flex-1 mx-2" }, i)) }),
6870
- Array.from({ length: rows }).map((_, rowIdx) => /* @__PURE__ */ jsx(
6870
+ Array.from({ length: rows2 }).map((_, rowIdx) => /* @__PURE__ */ jsx(
6871
6871
  HStack,
6872
6872
  {
6873
6873
  className: cn(
6874
6874
  "px-4 py-3",
6875
- rowIdx < rows - 1 && "border-b border-border"
6875
+ rowIdx < rows2 - 1 && "border-b border-border"
6876
6876
  ),
6877
6877
  children: Array.from({ length: columns }).map((_2, colIdx) => /* @__PURE__ */ jsx(SkeletonLine, { className: "flex-1 mx-2" }, colIdx))
6878
6878
  },
@@ -6920,18 +6920,18 @@ function CardSkeleton({ className }) {
6920
6920
  }
6921
6921
  );
6922
6922
  }
6923
- function TextSkeleton({ rows = 3, className }) {
6924
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className, children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsx(
6923
+ function TextSkeleton({ rows: rows2 = 3, className }) {
6924
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className, children: Array.from({ length: rows2 }).map((_, i) => /* @__PURE__ */ jsx(
6925
6925
  SkeletonLine,
6926
6926
  {
6927
- className: i === rows - 1 ? "w-2/3" : "w-full"
6927
+ className: i === rows2 - 1 ? "w-2/3" : "w-full"
6928
6928
  },
6929
6929
  i
6930
6930
  )) });
6931
6931
  }
6932
6932
  function Skeleton({
6933
6933
  variant = "text",
6934
- rows,
6934
+ rows: rows2,
6935
6935
  columns,
6936
6936
  fields,
6937
6937
  className
@@ -6941,15 +6941,15 @@ function Skeleton({
6941
6941
  case "header":
6942
6942
  return /* @__PURE__ */ jsx(HeaderSkeleton, { className });
6943
6943
  case "table":
6944
- return /* @__PURE__ */ jsx(TableSkeleton, { rows, columns, className });
6944
+ return /* @__PURE__ */ jsx(TableSkeleton, { rows: rows2, columns, className });
6945
6945
  case "form":
6946
6946
  return /* @__PURE__ */ jsx(FormSkeleton, { fields, className });
6947
6947
  case "card":
6948
6948
  return /* @__PURE__ */ jsx(CardSkeleton, { className });
6949
6949
  case "text":
6950
- return /* @__PURE__ */ jsx(TextSkeleton, { rows, className });
6950
+ return /* @__PURE__ */ jsx(TextSkeleton, { rows: rows2, className });
6951
6951
  default:
6952
- return /* @__PURE__ */ jsx(TextSkeleton, { rows, className });
6952
+ return /* @__PURE__ */ jsx(TextSkeleton, { rows: rows2, className });
6953
6953
  }
6954
6954
  }
6955
6955
  var pulseClass;
@@ -7858,8 +7858,8 @@ var init_Tooltip = __esm({
7858
7858
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
7859
7859
  };
7860
7860
  }, []);
7861
- const triggerElement = React79__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
7862
- const trigger = React79__default.cloneElement(triggerElement, {
7861
+ const triggerElement = React80__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
7862
+ const trigger = React80__default.cloneElement(triggerElement, {
7863
7863
  ref: triggerRef,
7864
7864
  onMouseEnter: handleMouseEnter,
7865
7865
  onMouseLeave: handleMouseLeave,
@@ -8014,8 +8014,8 @@ var init_Popover = __esm({
8014
8014
  onMouseEnter: handleOpen,
8015
8015
  onMouseLeave: handleClose
8016
8016
  };
8017
- const childElement = React79__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
8018
- const triggerElement = React79__default.cloneElement(
8017
+ const childElement = React80__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
8018
+ const triggerElement = React80__default.cloneElement(
8019
8019
  childElement,
8020
8020
  {
8021
8021
  ref: triggerRef,
@@ -8142,8 +8142,8 @@ var init_Menu = __esm({
8142
8142
  };
8143
8143
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
8144
8144
  const subMenuSideClass = direction === "rtl" ? "right-full mr-2" : "left-full ml-2";
8145
- const triggerChild = React79__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
8146
- const triggerElement = React79__default.cloneElement(
8145
+ const triggerChild = React80__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
8146
+ const triggerElement = React80__default.cloneElement(
8147
8147
  triggerChild,
8148
8148
  {
8149
8149
  ref: triggerRef,
@@ -8550,13 +8550,13 @@ var init_MapView = __esm({
8550
8550
  shadowSize: [41, 41]
8551
8551
  });
8552
8552
  L.Marker.prototype.options.icon = defaultIcon;
8553
- const { useEffect: useEffect69, useRef: useRef66, useCallback: useCallback113, useState: useState99 } = React79__default;
8553
+ const { useEffect: useEffect70, useRef: useRef67, useCallback: useCallback114, useState: useState100 } = React80__default;
8554
8554
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
8555
8555
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
8556
8556
  function MapUpdater({ centerLat, centerLng, zoom }) {
8557
8557
  const map = useMap();
8558
- const prevRef = useRef66({ centerLat, centerLng, zoom });
8559
- useEffect69(() => {
8558
+ const prevRef = useRef67({ centerLat, centerLng, zoom });
8559
+ useEffect70(() => {
8560
8560
  const prev = prevRef.current;
8561
8561
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
8562
8562
  map.setView([centerLat, centerLng], zoom);
@@ -8567,7 +8567,7 @@ var init_MapView = __esm({
8567
8567
  }
8568
8568
  function MapClickHandler({ onMapClick }) {
8569
8569
  const map = useMap();
8570
- useEffect69(() => {
8570
+ useEffect70(() => {
8571
8571
  if (!onMapClick) return;
8572
8572
  const handler = (e) => {
8573
8573
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -8595,8 +8595,8 @@ var init_MapView = __esm({
8595
8595
  showAttribution = true
8596
8596
  }) {
8597
8597
  const eventBus = useEventBus2();
8598
- const [clickedPosition, setClickedPosition] = useState99(null);
8599
- const handleMapClick = useCallback113((lat, lng) => {
8598
+ const [clickedPosition, setClickedPosition] = useState100(null);
8599
+ const handleMapClick = useCallback114((lat, lng) => {
8600
8600
  if (showClickedPin) {
8601
8601
  setClickedPosition({ lat, lng });
8602
8602
  }
@@ -8605,7 +8605,7 @@ var init_MapView = __esm({
8605
8605
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
8606
8606
  }
8607
8607
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
8608
- const handleMarkerClick = useCallback113((marker) => {
8608
+ const handleMarkerClick = useCallback114((marker) => {
8609
8609
  onMarkerClick?.(marker);
8610
8610
  if (markerClickEvent) {
8611
8611
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -8796,7 +8796,7 @@ function InputPattern({
8796
8796
  fieldName
8797
8797
  }) {
8798
8798
  const { emit } = useEventBus();
8799
- const [localValue, setLocalValue] = React79__default.useState(value);
8799
+ const [localValue, setLocalValue] = React80__default.useState(value);
8800
8800
  const handleChange = (e) => {
8801
8801
  setLocalValue(e.target.value);
8802
8802
  if (onChange) {
@@ -8826,7 +8826,7 @@ function InputPattern({
8826
8826
  function TextareaPattern({
8827
8827
  value = "",
8828
8828
  placeholder,
8829
- rows = 4,
8829
+ rows: rows2 = 4,
8830
8830
  disabled = false,
8831
8831
  fieldError,
8832
8832
  onChange,
@@ -8834,7 +8834,7 @@ function TextareaPattern({
8834
8834
  fieldName
8835
8835
  }) {
8836
8836
  const { emit } = useEventBus();
8837
- const [localValue, setLocalValue] = React79__default.useState(value);
8837
+ const [localValue, setLocalValue] = React80__default.useState(value);
8838
8838
  const handleChange = (e) => {
8839
8839
  setLocalValue(e.target.value);
8840
8840
  if (onChange) {
@@ -8846,7 +8846,7 @@ function TextareaPattern({
8846
8846
  {
8847
8847
  value: localValue,
8848
8848
  placeholder,
8849
- rows,
8849
+ rows: rows2,
8850
8850
  disabled,
8851
8851
  error: fieldError,
8852
8852
  onChange: handleChange,
@@ -8866,7 +8866,7 @@ function SelectPattern({
8866
8866
  fieldName
8867
8867
  }) {
8868
8868
  const { emit } = useEventBus();
8869
- const [localValue, setLocalValue] = React79__default.useState(value);
8869
+ const [localValue, setLocalValue] = React80__default.useState(value);
8870
8870
  const handleChange = (e) => {
8871
8871
  setLocalValue(e.target.value);
8872
8872
  if (onChange) {
@@ -8895,7 +8895,7 @@ function CheckboxPattern({
8895
8895
  className
8896
8896
  }) {
8897
8897
  const { emit } = useEventBus();
8898
- const [localChecked, setLocalChecked] = React79__default.useState(checked);
8898
+ const [localChecked, setLocalChecked] = React80__default.useState(checked);
8899
8899
  const handleChange = (e) => {
8900
8900
  setLocalChecked(e.target.checked);
8901
8901
  if (onChange) {
@@ -9208,9 +9208,9 @@ function ControlButton({
9208
9208
  className
9209
9209
  }) {
9210
9210
  const eventBus = useEventBus();
9211
- const [isPressed, setIsPressed] = React79.useState(false);
9211
+ const [isPressed, setIsPressed] = React80.useState(false);
9212
9212
  const actualPressed = pressed ?? isPressed;
9213
- const handlePointerDown = React79.useCallback(
9213
+ const handlePointerDown = React80.useCallback(
9214
9214
  (e) => {
9215
9215
  e.preventDefault();
9216
9216
  if (disabled) return;
@@ -9220,7 +9220,7 @@ function ControlButton({
9220
9220
  },
9221
9221
  [disabled, pressEvent, eventBus, onPress]
9222
9222
  );
9223
- const handlePointerUp = React79.useCallback(
9223
+ const handlePointerUp = React80.useCallback(
9224
9224
  (e) => {
9225
9225
  e.preventDefault();
9226
9226
  if (disabled) return;
@@ -9230,7 +9230,7 @@ function ControlButton({
9230
9230
  },
9231
9231
  [disabled, releaseEvent, eventBus, onRelease]
9232
9232
  );
9233
- const handlePointerLeave = React79.useCallback(
9233
+ const handlePointerLeave = React80.useCallback(
9234
9234
  (e) => {
9235
9235
  if (isPressed) {
9236
9236
  setIsPressed(false);
@@ -9307,8 +9307,8 @@ function ActionButtons({
9307
9307
  disabled
9308
9308
  }) {
9309
9309
  const eventBus = useEventBus();
9310
- const [activeButtons, setActiveButtons] = React79.useState(/* @__PURE__ */ new Set());
9311
- const handlePress = React79.useCallback(
9310
+ const [activeButtons, setActiveButtons] = React80.useState(/* @__PURE__ */ new Set());
9311
+ const handlePress = React80.useCallback(
9312
9312
  (id) => {
9313
9313
  setActiveButtons((prev) => new Set(prev).add(id));
9314
9314
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -9316,7 +9316,7 @@ function ActionButtons({
9316
9316
  },
9317
9317
  [actionEvent, eventBus, onAction]
9318
9318
  );
9319
- const handleRelease = React79.useCallback(
9319
+ const handleRelease = React80.useCallback(
9320
9320
  (id) => {
9321
9321
  setActiveButtons((prev) => {
9322
9322
  const next = new Set(prev);
@@ -9512,6 +9512,91 @@ var init_ActionPalette = __esm({
9512
9512
  ActionPalette.displayName = "ActionPalette";
9513
9513
  }
9514
9514
  });
9515
+ function parseValue(value) {
9516
+ if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
9517
+ const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
9518
+ if (!match) {
9519
+ return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
9520
+ }
9521
+ const numStr = match[2];
9522
+ const decimalIdx = numStr.indexOf(".");
9523
+ const decimals = decimalIdx >= 0 ? numStr.length - decimalIdx - 1 : 0;
9524
+ return {
9525
+ prefix: match[1],
9526
+ num: parseFloat(numStr),
9527
+ suffix: match[3],
9528
+ decimals
9529
+ };
9530
+ }
9531
+ var AnimatedCounter2;
9532
+ var init_AnimatedCounter2 = __esm({
9533
+ "components/core/molecules/AnimatedCounter.tsx"() {
9534
+ "use client";
9535
+ init_cn();
9536
+ init_Box();
9537
+ init_Typography();
9538
+ AnimatedCounter2 = ({
9539
+ value,
9540
+ label,
9541
+ duration = 1500,
9542
+ className
9543
+ }) => {
9544
+ const ref = useRef(null);
9545
+ const [displayValue, setDisplayValue] = useState("0");
9546
+ const [hasAnimated, setHasAnimated] = useState(false);
9547
+ const animate = useCallback(() => {
9548
+ const { num: num2, prefix, suffix, decimals } = parseValue(value);
9549
+ if (num2 === 0) {
9550
+ setDisplayValue(String(value));
9551
+ return;
9552
+ }
9553
+ const startTime = performance.now();
9554
+ const tick = (now) => {
9555
+ const elapsed = now - startTime;
9556
+ const progress = Math.min(elapsed / duration, 1);
9557
+ const eased = 1 - Math.pow(1 - progress, 3);
9558
+ const current = eased * num2;
9559
+ setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
9560
+ if (progress < 1) {
9561
+ requestAnimationFrame(tick);
9562
+ } else {
9563
+ setDisplayValue(String(value));
9564
+ }
9565
+ };
9566
+ requestAnimationFrame(tick);
9567
+ }, [value, duration]);
9568
+ useEffect(() => {
9569
+ if (hasAnimated) return;
9570
+ const el = ref.current;
9571
+ if (!el) return;
9572
+ const observer2 = new IntersectionObserver(
9573
+ (entries) => {
9574
+ if (entries[0].isIntersecting) {
9575
+ setHasAnimated(true);
9576
+ animate();
9577
+ observer2.disconnect();
9578
+ }
9579
+ },
9580
+ { threshold: 0.3 }
9581
+ );
9582
+ observer2.observe(el);
9583
+ return () => observer2.disconnect();
9584
+ }, [hasAnimated, animate]);
9585
+ return /* @__PURE__ */ jsxs(Box, { ref, className: cn("flex flex-col items-center gap-1 p-4", className), children: [
9586
+ /* @__PURE__ */ jsx(
9587
+ Typography,
9588
+ {
9589
+ variant: "h2",
9590
+ className: "text-primary font-bold tabular-nums",
9591
+ children: hasAnimated ? displayValue : "0"
9592
+ }
9593
+ ),
9594
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "muted", className: "text-center", children: label })
9595
+ ] });
9596
+ };
9597
+ AnimatedCounter2.displayName = "AnimatedCounter";
9598
+ }
9599
+ });
9515
9600
  var AuthLayout;
9516
9601
  var init_AuthLayout = __esm({
9517
9602
  "components/core/templates/AuthLayout.tsx"() {
@@ -10764,6 +10849,39 @@ var init_IsometricCanvas2 = __esm({
10764
10849
  init_IsometricCanvas();
10765
10850
  }
10766
10851
  });
10852
+
10853
+ // components/game/organisms/boardEntity.ts
10854
+ function boardEntity(entity) {
10855
+ if (!entity) return void 0;
10856
+ return Array.isArray(entity) ? entity[0] : entity;
10857
+ }
10858
+ function str(v) {
10859
+ return v == null ? "" : String(v);
10860
+ }
10861
+ function num(v, fallback = 0) {
10862
+ const n = Number(v);
10863
+ return Number.isFinite(n) ? n : fallback;
10864
+ }
10865
+ function rows(v) {
10866
+ return Array.isArray(v) ? v : [];
10867
+ }
10868
+ function vec2(v) {
10869
+ const o = v ?? {};
10870
+ return { x: num(o.x), y: num(o.y) };
10871
+ }
10872
+ function unitPosition(u) {
10873
+ return vec2(u.position);
10874
+ }
10875
+ function unitTeam(u) {
10876
+ return str(u.team);
10877
+ }
10878
+ function unitHealth(u) {
10879
+ return num(u.health);
10880
+ }
10881
+ var init_boardEntity = __esm({
10882
+ "components/game/organisms/boardEntity.ts"() {
10883
+ }
10884
+ });
10767
10885
  function BattleBoard({
10768
10886
  entity,
10769
10887
  scale = 0.45,
@@ -10790,43 +10908,49 @@ function BattleBoard({
10790
10908
  attackEvent,
10791
10909
  className
10792
10910
  }) {
10793
- const tiles = entity.tiles;
10794
- const features = entity.features ?? [];
10795
- const boardWidth = entity.boardWidth ?? 8;
10796
- const boardHeight = entity.boardHeight ?? 6;
10797
- const assetManifest = entity.assetManifest;
10798
- const backgroundImage = entity.backgroundImage;
10799
- const units = entity.units;
10800
- const selectedUnitId = entity.selectedUnitId;
10801
- const currentPhase = entity.phase;
10802
- const currentTurn = entity.turn;
10803
- const gameResult = entity.gameResult;
10911
+ const board = boardEntity(entity) ?? {};
10912
+ const tiles = Array.isArray(board.tiles) ? board.tiles : [];
10913
+ const features = Array.isArray(board.features) ? board.features : [];
10914
+ const boardWidth = num(board.boardWidth, 8);
10915
+ const boardHeight = num(board.boardHeight, 6);
10916
+ const assetManifest = board.assetManifest;
10917
+ const backgroundImage = board.backgroundImage;
10918
+ const units = rows(board.units);
10919
+ const selectedUnitId = board.selectedUnitId ?? null;
10920
+ const currentPhase = str(board.phase) || "observation";
10921
+ const currentTurn = num(board.turn, 1);
10922
+ const gameResult = board.gameResult ?? null;
10804
10923
  const eventBus = useEventBus();
10805
10924
  const { t } = useTranslate();
10806
10925
  const [hoveredTile, setHoveredTile] = useState(null);
10807
10926
  const [isShaking, setIsShaking] = useState(false);
10808
10927
  const selectedUnit = useMemo(
10809
- () => units.find((u) => u.id === selectedUnitId) ?? null,
10928
+ () => units.find((u) => str(u.id) === selectedUnitId) ?? null,
10810
10929
  [units, selectedUnitId]
10811
10930
  );
10812
10931
  const hoveredUnit = useMemo(() => {
10813
10932
  if (!hoveredTile) return null;
10814
- return units.find(
10815
- (u) => u.position.x === hoveredTile.x && u.position.y === hoveredTile.y && u.health > 0
10816
- ) ?? null;
10933
+ return units.find((u) => {
10934
+ const p2 = unitPosition(u);
10935
+ return p2.x === hoveredTile.x && p2.y === hoveredTile.y && unitHealth(u) > 0;
10936
+ }) ?? null;
10817
10937
  }, [hoveredTile, units]);
10818
- const playerUnits = useMemo(() => units.filter((u) => u.team === "player" && u.health > 0), [units]);
10819
- const enemyUnits = useMemo(() => units.filter((u) => u.team === "enemy" && u.health > 0), [units]);
10938
+ const playerUnits = useMemo(() => units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0), [units]);
10939
+ const enemyUnits = useMemo(() => units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0), [units]);
10820
10940
  const validMoves = useMemo(() => {
10821
10941
  if (!selectedUnit || currentPhase !== "movement") return [];
10822
10942
  const moves = [];
10823
- const range = selectedUnit.movement;
10943
+ const range = num(selectedUnit.movement);
10944
+ const origin = unitPosition(selectedUnit);
10824
10945
  for (let dy = -range; dy <= range; dy++) {
10825
10946
  for (let dx = -range; dx <= range; dx++) {
10826
- const nx = selectedUnit.position.x + dx;
10827
- const ny = selectedUnit.position.y + dy;
10947
+ const nx = origin.x + dx;
10948
+ const ny = origin.y + dy;
10828
10949
  const dist = Math.abs(dx) + Math.abs(dy);
10829
- if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) => u.position.x === nx && u.position.y === ny && u.health > 0)) {
10950
+ if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) => {
10951
+ const p2 = unitPosition(u);
10952
+ return p2.x === nx && p2.y === ny && unitHealth(u) > 0;
10953
+ })) {
10830
10954
  moves.push({ x: nx, y: ny });
10831
10955
  }
10832
10956
  }
@@ -10835,11 +10959,14 @@ function BattleBoard({
10835
10959
  }, [selectedUnit, currentPhase, units, boardWidth, boardHeight]);
10836
10960
  const attackTargets = useMemo(() => {
10837
10961
  if (!selectedUnit || currentPhase !== "action") return [];
10838
- return units.filter((u) => u.team !== selectedUnit.team && u.health > 0).filter((u) => {
10839
- const dx = Math.abs(u.position.x - selectedUnit.position.x);
10840
- const dy = Math.abs(u.position.y - selectedUnit.position.y);
10962
+ const sp = unitPosition(selectedUnit);
10963
+ const sTeam = unitTeam(selectedUnit);
10964
+ return units.filter((u) => unitTeam(u) !== sTeam && unitHealth(u) > 0).filter((u) => {
10965
+ const p2 = unitPosition(u);
10966
+ const dx = Math.abs(p2.x - sp.x);
10967
+ const dy = Math.abs(p2.y - sp.y);
10841
10968
  return dx <= 1 && dy <= 1 && dx + dy > 0;
10842
- }).map((u) => u.position);
10969
+ }).map((u) => unitPosition(u));
10843
10970
  }, [selectedUnit, currentPhase, units]);
10844
10971
  const MOVE_SPEED_MS_PER_TILE = 300;
10845
10972
  const movementAnimRef = useRef(null);
@@ -10879,23 +11006,25 @@ function BattleBoard({
10879
11006
  return () => clearInterval(interval);
10880
11007
  }, []);
10881
11008
  const isoUnits = useMemo(() => {
10882
- return units.filter((u) => u.health > 0).map((unit) => {
10883
- const pos = movingPositions.get(unit.id) ?? unit.position;
11009
+ return units.filter((u) => unitHealth(u) > 0).map((unit) => {
11010
+ const id = str(unit.id);
11011
+ const pos = movingPositions.get(id) ?? unitPosition(unit);
11012
+ const unitTraits = Array.isArray(unit.traits) ? unit.traits : void 0;
10884
11013
  return {
10885
- id: unit.id,
11014
+ id,
10886
11015
  position: pos,
10887
- name: unit.name,
10888
- team: unit.team,
10889
- health: unit.health,
10890
- maxHealth: unit.maxHealth,
10891
- unitType: unit.unitType,
10892
- heroId: unit.heroId,
10893
- sprite: unit.sprite,
10894
- traits: unit.traits?.map((t2) => ({
10895
- name: t2.name,
10896
- currentState: t2.currentState,
10897
- states: t2.states,
10898
- cooldown: t2.cooldown ?? 0
11016
+ name: str(unit.name),
11017
+ team: unitTeam(unit),
11018
+ health: unitHealth(unit),
11019
+ maxHealth: num(unit.maxHealth),
11020
+ unitType: unit.unitType == null ? void 0 : str(unit.unitType),
11021
+ heroId: unit.heroId == null ? void 0 : str(unit.heroId),
11022
+ sprite: unit.sprite == null ? void 0 : str(unit.sprite),
11023
+ traits: unitTraits?.map((tr) => ({
11024
+ name: tr.name,
11025
+ currentState: tr.currentState,
11026
+ states: tr.states,
11027
+ cooldown: tr.cooldown ?? 0
10899
11028
  }))
10900
11029
  };
10901
11030
  });
@@ -10907,8 +11036,8 @@ function BattleBoard({
10907
11036
  [scale, baseOffsetX]
10908
11037
  );
10909
11038
  const checkGameEnd = useCallback(() => {
10910
- const pa = units.filter((u) => u.team === "player" && u.health > 0);
10911
- const ea = units.filter((u) => u.team === "enemy" && u.health > 0);
11039
+ const pa = units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
11040
+ const ea = units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
10912
11041
  if (pa.length === 0) {
10913
11042
  onGameEnd?.("defeat");
10914
11043
  if (gameEndEvent) {
@@ -10922,21 +11051,22 @@ function BattleBoard({
10922
11051
  }
10923
11052
  }, [units, onGameEnd, gameEndEvent, eventBus]);
10924
11053
  const handleUnitClick = useCallback((unitId) => {
10925
- const unit = units.find((u) => u.id === unitId);
11054
+ const unit = units.find((u) => str(u.id) === unitId);
10926
11055
  if (!unit) return;
10927
11056
  if (unitClickEvent) {
10928
11057
  eventBus.emit(`UI:${unitClickEvent}`, { unitId });
10929
11058
  }
10930
11059
  if (currentPhase === "action" && selectedUnit) {
10931
- if (unit.team === "enemy" && attackTargets.some((t2) => t2.x === unit.position.x && t2.y === unit.position.y)) {
10932
- const damage = calculateDamage2 ? calculateDamage2(selectedUnit, unit) : Math.max(1, selectedUnit.attack - unit.defense);
11060
+ const up = unitPosition(unit);
11061
+ if (unitTeam(unit) === "enemy" && attackTargets.some((t2) => t2.x === up.x && t2.y === up.y)) {
11062
+ const damage = calculateDamage2 ? calculateDamage2(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
10933
11063
  setIsShaking(true);
10934
11064
  setTimeout(() => setIsShaking(false), 300);
10935
11065
  onAttack?.(selectedUnit, unit, damage);
10936
11066
  if (attackEvent) {
10937
11067
  eventBus.emit(`UI:${attackEvent}`, {
10938
- attackerId: selectedUnit.id,
10939
- targetId: unit.id,
11068
+ attackerId: str(selectedUnit.id),
11069
+ targetId: str(unit.id),
10940
11070
  damage
10941
11071
  });
10942
11072
  }
@@ -10951,9 +11081,9 @@ function BattleBoard({
10951
11081
  if (currentPhase === "movement" && selectedUnit) {
10952
11082
  if (movementAnimRef.current) return;
10953
11083
  if (validMoves.some((m) => m.x === x && m.y === y)) {
10954
- const from = { ...selectedUnit.position };
11084
+ const from = { ...unitPosition(selectedUnit) };
10955
11085
  const to = { x, y };
10956
- startMoveAnimation(selectedUnit.id, from, to, () => {
11086
+ startMoveAnimation(str(selectedUnit.id), from, to, () => {
10957
11087
  onUnitMove?.(selectedUnit, to);
10958
11088
  });
10959
11089
  }
@@ -11111,6 +11241,7 @@ var init_BattleBoard = __esm({
11111
11241
  init_Typography();
11112
11242
  init_Stack();
11113
11243
  init_IsometricCanvas2();
11244
+ init_boardEntity();
11114
11245
  init_isometric();
11115
11246
  BattleBoard.displayName = "BattleBoard";
11116
11247
  }
@@ -12191,7 +12322,7 @@ var init_CodeBlock = __esm({
12191
12322
  log5 = createLogger("almadar:ui:markdown-code");
12192
12323
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
12193
12324
  HIDDEN_LINE_NUMBERS = { display: "none" };
12194
- CodeBlock = React79__default.memo(
12325
+ CodeBlock = React80__default.memo(
12195
12326
  ({
12196
12327
  code: rawCode,
12197
12328
  language = "text",
@@ -12333,24 +12464,24 @@ var init_CodeBlock = __esm({
12333
12464
  return;
12334
12465
  }
12335
12466
  lineEls.forEach((el) => {
12336
- const num = parseInt(el.getAttribute("data-line") ?? "-1", 10);
12337
- if (hiddenLines.has(num)) {
12467
+ const num2 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
12468
+ if (hiddenLines.has(num2)) {
12338
12469
  el.style.display = "none";
12339
12470
  return;
12340
12471
  }
12341
12472
  el.style.display = "";
12342
12473
  el.style.position = "relative";
12343
12474
  el.style.paddingLeft = "1.2em";
12344
- const region = foldStartMap.get(num);
12475
+ const region = foldStartMap.get(num2);
12345
12476
  if (!region) return;
12346
- const isCollapsed = collapsed.has(num);
12477
+ const isCollapsed = collapsed.has(num2);
12347
12478
  const toggle = document.createElement("span");
12348
12479
  toggle.className = "fold-toggle";
12349
12480
  toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
12350
12481
  toggle.style.cssText = "position:absolute;left:0;top:0;width:1.2em;text-align:center;cursor:pointer;color:#858585;font-size:10px;user-select:none;line-height:inherit;height:100%";
12351
12482
  toggle.addEventListener("click", (e) => {
12352
12483
  e.stopPropagation();
12353
- toggleFoldRef.current(num);
12484
+ toggleFoldRef.current(num2);
12354
12485
  });
12355
12486
  el.insertBefore(toggle, el.firstChild);
12356
12487
  if (isCollapsed) {
@@ -12628,7 +12759,7 @@ var init_MarkdownContent = __esm({
12628
12759
  init_Box();
12629
12760
  init_CodeBlock();
12630
12761
  init_cn();
12631
- MarkdownContent = React79__default.memo(
12762
+ MarkdownContent = React80__default.memo(
12632
12763
  ({ content, direction, className }) => {
12633
12764
  const { t: _t } = useTranslate();
12634
12765
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -13724,7 +13855,7 @@ var init_StateMachineView = __esm({
13724
13855
  style: { top: title ? 30 : 0 },
13725
13856
  children: [
13726
13857
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
13727
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React79__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
13858
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React80__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
13728
13859
  StateNode,
13729
13860
  {
13730
13861
  state,
@@ -14603,10 +14734,13 @@ var init_BookChapterView = __esm({
14603
14734
  init_cn();
14604
14735
  BookChapterView = ({
14605
14736
  chapter,
14737
+ orbitalSchema,
14606
14738
  direction,
14607
14739
  className
14608
14740
  }) => {
14609
14741
  const { t: _t } = useTranslate();
14742
+ const title = String(chapter.title ?? "");
14743
+ const content = String(chapter.content ?? "");
14610
14744
  return /* @__PURE__ */ jsxs(
14611
14745
  VStack,
14612
14746
  {
@@ -14614,16 +14748,16 @@ var init_BookChapterView = __esm({
14614
14748
  className: cn("px-6 py-8 max-w-4xl mx-auto w-full", className),
14615
14749
  style: { direction },
14616
14750
  children: [
14617
- /* @__PURE__ */ jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children: chapter.title }),
14751
+ /* @__PURE__ */ jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children: title }),
14618
14752
  /* @__PURE__ */ jsx(Divider, {}),
14619
- !!chapter.orbitalSchema && /* @__PURE__ */ jsx(ScaledDiagram, { children: /* @__PURE__ */ jsx(
14753
+ !!orbitalSchema && /* @__PURE__ */ jsx(ScaledDiagram, { children: /* @__PURE__ */ jsx(
14620
14754
  JazariStateMachine,
14621
14755
  {
14622
- schema: chapter.orbitalSchema,
14756
+ schema: orbitalSchema,
14623
14757
  direction
14624
14758
  }
14625
14759
  ) }),
14626
- /* @__PURE__ */ jsx(ContentRenderer, { content: chapter.content, direction })
14760
+ /* @__PURE__ */ jsx(ContentRenderer, { content, direction })
14627
14761
  ]
14628
14762
  }
14629
14763
  );
@@ -14721,7 +14855,7 @@ var init_BookNavBar = __esm({
14721
14855
  BookNavBar = ({
14722
14856
  currentPage,
14723
14857
  totalPages,
14724
- chapterTitle,
14858
+ chapterTitle: chapterTitle2,
14725
14859
  direction,
14726
14860
  className
14727
14861
  }) => {
@@ -14762,12 +14896,12 @@ var init_BookNavBar = __esm({
14762
14896
  )
14763
14897
  ] }),
14764
14898
  /* @__PURE__ */ jsxs(Box, { className: "flex-1 mx-4 max-w-md", children: [
14765
- chapterTitle && /* @__PURE__ */ jsx(
14899
+ chapterTitle2 && /* @__PURE__ */ jsx(
14766
14900
  Typography,
14767
14901
  {
14768
14902
  variant: "caption",
14769
14903
  className: "text-center block truncate text-muted-foreground",
14770
- children: chapterTitle
14904
+ children: chapterTitle2
14771
14905
  }
14772
14906
  ),
14773
14907
  /* @__PURE__ */ jsx(ProgressBar, { value: progress, size: "sm", variant: "primary" })
@@ -14834,31 +14968,35 @@ var init_BookTableOfContents = __esm({
14834
14968
  style: { direction },
14835
14969
  children: [
14836
14970
  /* @__PURE__ */ jsx(Typography, { variant: "h1", className: "text-3xl font-bold text-center mb-4", children: t("book.tableOfContents") }),
14837
- parts.map((part, partIdx) => /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
14838
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "center", children: [
14839
- /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: t("book.partNumber", { number: String(partIdx + 1) }) }),
14840
- /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "font-semibold", children: part.title })
14841
- ] }),
14842
- /* @__PURE__ */ jsx(VStack, { gap: "xs", className: direction === "rtl" ? "pr-6" : "pl-6", children: part.chapters.map((chapter) => {
14843
- const isCurrent = chapter.id === currentChapterId;
14844
- return /* @__PURE__ */ jsx(
14845
- Button,
14846
- {
14847
- variant: "ghost",
14848
- size: "sm",
14849
- action: "BOOK_NAVIGATE",
14850
- actionPayload: { chapterId: chapter.id },
14851
- className: cn(
14852
- "justify-start text-left w-full",
14853
- direction === "rtl" && "text-right",
14854
- isCurrent && "bg-blue-50 dark:bg-blue-950 text-blue-600 dark:text-blue-400"
14855
- ),
14856
- children: /* @__PURE__ */ jsx(Box, { className: "truncate", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: chapter.title }) })
14857
- },
14858
- chapter.id
14859
- );
14860
- }) })
14861
- ] }, partIdx))
14971
+ parts.map((part, partIdx) => {
14972
+ const chapters = Array.isArray(part.chapters) ? part.chapters : [];
14973
+ return /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
14974
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "center", children: [
14975
+ /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: t("book.partNumber", { number: String(partIdx + 1) }) }),
14976
+ /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "font-semibold", children: String(part.title ?? "") })
14977
+ ] }),
14978
+ /* @__PURE__ */ jsx(VStack, { gap: "xs", className: direction === "rtl" ? "pr-6" : "pl-6", children: chapters.map((chapter) => {
14979
+ const id = chapter.id == null ? "" : String(chapter.id);
14980
+ const isCurrent = id === currentChapterId;
14981
+ return /* @__PURE__ */ jsx(
14982
+ Button,
14983
+ {
14984
+ variant: "ghost",
14985
+ size: "sm",
14986
+ action: "BOOK_NAVIGATE",
14987
+ actionPayload: { chapterId: id },
14988
+ className: cn(
14989
+ "justify-start text-left w-full",
14990
+ direction === "rtl" && "text-right",
14991
+ isCurrent && "bg-blue-50 dark:bg-blue-950 text-blue-600 dark:text-blue-400"
14992
+ ),
14993
+ children: /* @__PURE__ */ jsx(Box, { className: "truncate", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: String(chapter.title ?? "") }) })
14994
+ },
14995
+ id
14996
+ );
14997
+ }) })
14998
+ ] }, partIdx);
14999
+ })
14862
15000
  ]
14863
15001
  }
14864
15002
  );
@@ -14980,27 +15118,41 @@ function resolveFieldMap(fieldMap) {
14980
15118
  function get(obj, key) {
14981
15119
  return obj[key];
14982
15120
  }
15121
+ function asStr(v) {
15122
+ return v == null ? "" : String(v);
15123
+ }
14983
15124
  function mapBookData(raw, fields = IDENTITY_BOOK_FIELDS) {
14984
15125
  const rawParts = get(raw, fields.parts) ?? [];
14985
- return {
14986
- title: get(raw, fields.title) ?? "",
14987
- subtitle: get(raw, fields.subtitle),
14988
- author: get(raw, fields.author),
14989
- coverImageUrl: get(raw, fields.coverImageUrl),
14990
- direction: get(raw, fields.direction) ?? void 0,
14991
- parts: rawParts.map((part) => {
14992
- const rawChapters = get(part, fields.chapters) ?? [];
14993
- return {
14994
- title: get(part, fields.partTitle) ?? "",
14995
- chapters: rawChapters.map((ch) => ({
14996
- id: get(ch, fields.chapterId) ?? "",
14997
- title: get(ch, fields.chapterTitle) ?? "",
14998
- content: get(ch, fields.chapterContent) ?? "",
14999
- orbitalSchema: get(ch, fields.chapterOrbitalSchema)
15000
- }))
15001
- };
15002
- })
15126
+ const direction = get(raw, fields.direction) ?? "ltr";
15127
+ const cover = {
15128
+ title: asStr(get(raw, fields.title)),
15129
+ subtitle: asStr(get(raw, fields.subtitle)),
15130
+ author: asStr(get(raw, fields.author)),
15131
+ coverImageUrl: asStr(get(raw, fields.coverImageUrl)),
15132
+ direction
15003
15133
  };
15134
+ const schemaByChapterId = {};
15135
+ const chapters = [];
15136
+ const parts = rawParts.map((part) => {
15137
+ const rawChapters = get(part, fields.chapters) ?? [];
15138
+ const chapterRows = rawChapters.map((ch) => {
15139
+ const id = asStr(get(ch, fields.chapterId));
15140
+ const schema = get(ch, fields.chapterOrbitalSchema);
15141
+ if (schema) schemaByChapterId[id] = schema;
15142
+ const row = {
15143
+ id,
15144
+ title: asStr(get(ch, fields.chapterTitle)),
15145
+ content: asStr(get(ch, fields.chapterContent))
15146
+ };
15147
+ chapters.push(row);
15148
+ return row;
15149
+ });
15150
+ return {
15151
+ title: asStr(get(part, fields.partTitle)),
15152
+ chapters: chapterRows
15153
+ };
15154
+ });
15155
+ return { cover, direction, parts, chapters, schemaByChapterId };
15004
15156
  }
15005
15157
  var IDENTITY_BOOK_FIELDS, AR_BOOK_FIELDS, FIELD_MAP_REGISTRY;
15006
15158
  var init_types2 = __esm({
@@ -15038,10 +15190,7 @@ var init_types2 = __esm({
15038
15190
  };
15039
15191
  }
15040
15192
  });
15041
- function flattenChapters(book) {
15042
- return book.parts.flatMap((part) => part.chapters);
15043
- }
15044
- var PRINT_STYLES, BookViewer;
15193
+ var chapterId, chapterTitle, PRINT_STYLES, BookViewer;
15045
15194
  var init_BookViewer = __esm({
15046
15195
  "components/marketing/organisms/book/BookViewer.tsx"() {
15047
15196
  init_Box();
@@ -15054,6 +15203,8 @@ var init_BookViewer = __esm({
15054
15203
  init_BookNavBar();
15055
15204
  init_EmptyState();
15056
15205
  init_types2();
15206
+ chapterId = (ch) => ch?.id == null ? void 0 : String(ch.id);
15207
+ chapterTitle = (ch) => ch?.title == null ? void 0 : String(ch.title);
15057
15208
  PRINT_STYLES = `
15058
15209
  @media print {
15059
15210
  .book-viewer-page {
@@ -15082,14 +15233,14 @@ var init_BookViewer = __esm({
15082
15233
  return mapBookData(raw, resolvedFieldMap);
15083
15234
  }, [entity, resolvedFieldMap]);
15084
15235
  const direction = book?.direction ?? "ltr";
15085
- const chapters = useMemo(() => book ? flattenChapters(book) : [], [book]);
15236
+ const chapters = useMemo(() => book ? book.chapters : [], [book]);
15086
15237
  const totalPages = 2 + chapters.length;
15087
15238
  const navigateTo = useCallback(
15088
15239
  (page) => {
15089
15240
  const clamped = Math.max(0, Math.min(page, totalPages - 1));
15090
15241
  setCurrentPage(clamped);
15091
- const chapterId = clamped >= 2 ? chapters[clamped - 2]?.id : void 0;
15092
- eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId });
15242
+ const id = clamped >= 2 ? chapterId(chapters[clamped - 2]) : void 0;
15243
+ eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId: id });
15093
15244
  },
15094
15245
  [totalPages, chapters, eventBus]
15095
15246
  );
@@ -15101,8 +15252,8 @@ var init_BookViewer = __esm({
15101
15252
  eventBus.on("UI:BOOK_PAGE_NEXT", () => navigateTo(currentPage + 1)),
15102
15253
  eventBus.on("UI:BOOK_PRINT", () => window.print()),
15103
15254
  eventBus.on("UI:BOOK_NAVIGATE", (event) => {
15104
- const chapterId = event.payload?.chapterId;
15105
- const idx = chapters.findIndex((ch) => ch.id === chapterId);
15255
+ const targetId = event.payload?.chapterId;
15256
+ const idx = chapters.findIndex((ch) => chapterId(ch) === targetId);
15106
15257
  if (idx >= 0) navigateTo(idx + 2);
15107
15258
  })
15108
15259
  ];
@@ -15119,9 +15270,11 @@ var init_BookViewer = __esm({
15119
15270
  style.remove();
15120
15271
  };
15121
15272
  }, []);
15122
- const currentChapterId = currentPage >= 2 ? chapters[currentPage - 2]?.id : void 0;
15123
- const currentChapterTitle = currentPage >= 2 ? chapters[currentPage - 2]?.title : void 0;
15273
+ const currentChapterId = currentPage >= 2 ? chapterId(chapters[currentPage - 2]) : void 0;
15274
+ const currentChapterTitle = currentPage >= 2 ? chapterTitle(chapters[currentPage - 2]) : void 0;
15124
15275
  if (!book) return /* @__PURE__ */ jsx(EmptyState, { message: t("book.noData") });
15276
+ const cover = book.cover;
15277
+ const coverTitle = String(cover.title ?? "");
15125
15278
  return /* @__PURE__ */ jsxs(VStack, { className: cn("relative h-full overflow-hidden bg-background", className), children: [
15126
15279
  /* @__PURE__ */ jsxs(
15127
15280
  Box,
@@ -15133,10 +15286,10 @@ var init_BookViewer = __esm({
15133
15286
  /* @__PURE__ */ jsx(
15134
15287
  BookCoverPage,
15135
15288
  {
15136
- title: book.title,
15137
- subtitle: book.subtitle,
15138
- author: book.author,
15139
- coverImageUrl: book.coverImageUrl,
15289
+ title: coverTitle,
15290
+ subtitle: String(cover.subtitle ?? "") || void 0,
15291
+ author: String(cover.author ?? "") || void 0,
15292
+ coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
15140
15293
  direction
15141
15294
  }
15142
15295
  ),
@@ -15147,23 +15300,27 @@ var init_BookViewer = __esm({
15147
15300
  direction
15148
15301
  }
15149
15302
  ),
15150
- chapters.map((chapter) => /* @__PURE__ */ jsx(
15151
- BookChapterView,
15152
- {
15153
- chapter,
15154
- direction
15155
- },
15156
- chapter.id
15157
- ))
15303
+ chapters.map((chapter) => {
15304
+ const id = chapterId(chapter);
15305
+ return /* @__PURE__ */ jsx(
15306
+ BookChapterView,
15307
+ {
15308
+ chapter,
15309
+ orbitalSchema: id ? book.schemaByChapterId[id] : void 0,
15310
+ direction
15311
+ },
15312
+ id
15313
+ );
15314
+ })
15158
15315
  ] }),
15159
15316
  /* @__PURE__ */ jsxs(Box, { className: "print:hidden", children: [
15160
15317
  currentPage === 0 && /* @__PURE__ */ jsx(
15161
15318
  BookCoverPage,
15162
15319
  {
15163
- title: book.title,
15164
- subtitle: book.subtitle,
15165
- author: book.author,
15166
- coverImageUrl: book.coverImageUrl,
15320
+ title: coverTitle,
15321
+ subtitle: String(cover.subtitle ?? "") || void 0,
15322
+ author: String(cover.author ?? "") || void 0,
15323
+ coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
15167
15324
  direction
15168
15325
  }
15169
15326
  ),
@@ -15179,6 +15336,7 @@ var init_BookViewer = __esm({
15179
15336
  BookChapterView,
15180
15337
  {
15181
15338
  chapter: chapters[currentPage - 2],
15339
+ orbitalSchema: currentChapterId ? book.schemaByChapterId[currentChapterId] : void 0,
15182
15340
  direction
15183
15341
  }
15184
15342
  )
@@ -15191,7 +15349,7 @@ var init_BookViewer = __esm({
15191
15349
  {
15192
15350
  currentPage,
15193
15351
  totalPages,
15194
- chapterTitle: currentPage === 0 ? book.title : currentPage === 1 ? t("book.tableOfContents") : currentChapterTitle,
15352
+ chapterTitle: currentPage === 0 ? coverTitle : currentPage === 1 ? t("book.tableOfContents") : currentChapterTitle,
15195
15353
  direction
15196
15354
  }
15197
15355
  )
@@ -15289,7 +15447,7 @@ var init_Grid = __esm({
15289
15447
  };
15290
15448
  Grid = ({
15291
15449
  cols = 1,
15292
- rows,
15450
+ rows: rows2,
15293
15451
  gap = "md",
15294
15452
  rowGap,
15295
15453
  colGap,
@@ -15301,8 +15459,8 @@ var init_Grid = __esm({
15301
15459
  children,
15302
15460
  as: Component = "div"
15303
15461
  }) => {
15304
- const mergedStyle = rows ? { gridTemplateRows: `repeat(${rows}, minmax(0, 1fr))`, ...style } : style;
15305
- return React79__default.createElement(
15462
+ const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
15463
+ return React80__default.createElement(
15306
15464
  Component,
15307
15465
  {
15308
15466
  className: cn(
@@ -16017,14 +16175,14 @@ function BuilderBoard({
16017
16175
  }) {
16018
16176
  const { emit } = useEventBus();
16019
16177
  const { t } = useTranslate();
16020
- const resolved = Array.isArray(entity) ? entity[0] : entity;
16178
+ const resolved = boardEntity(entity);
16021
16179
  const [placements, setPlacements] = useState({});
16022
16180
  const [headerError, setHeaderError] = useState(false);
16023
16181
  const [submitted, setSubmitted] = useState(false);
16024
16182
  const [attempts, setAttempts] = useState(0);
16025
16183
  const [showHint, setShowHint] = useState(false);
16026
- const components = resolved?.components ?? [];
16027
- const slots = resolved?.slots ?? [];
16184
+ const components = Array.isArray(resolved?.components) ? resolved.components : [];
16185
+ const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
16028
16186
  const usedComponentIds = new Set(Object.values(placements));
16029
16187
  const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
16030
16188
  const [selectedComponent, setSelectedComponent] = useState(null);
@@ -16058,7 +16216,7 @@ function BuilderBoard({
16058
16216
  }, [slots, placements, attempts, completeEvent, emit]);
16059
16217
  const handleReset = () => {
16060
16218
  setSubmitted(false);
16061
- if (attempts >= 2 && resolved?.hint) {
16219
+ if (attempts >= 2 && str(resolved?.hint)) {
16062
16220
  setShowHint(true);
16063
16221
  }
16064
16222
  };
@@ -16071,20 +16229,24 @@ function BuilderBoard({
16071
16229
  };
16072
16230
  const getComponentById = (id) => components.find((c) => c.id === id);
16073
16231
  if (!resolved) return null;
16232
+ const theme = resolved.theme ?? void 0;
16233
+ const themeBackground = theme?.background;
16234
+ const headerImage = str(resolved.headerImage);
16235
+ const hint = str(resolved.hint);
16074
16236
  return /* @__PURE__ */ jsx(
16075
16237
  Box,
16076
16238
  {
16077
16239
  className,
16078
16240
  style: {
16079
- backgroundImage: resolved.theme?.background ? `url(${resolved.theme.background})` : void 0,
16241
+ backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
16080
16242
  backgroundSize: "cover",
16081
16243
  backgroundPosition: "center"
16082
16244
  },
16083
16245
  children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
16084
- resolved.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: resolved.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : resolved.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
16246
+ headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
16085
16247
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
16086
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
16087
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.description })
16248
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
16249
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: str(resolved.description) })
16088
16250
  ] }) }),
16089
16251
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
16090
16252
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.components") }),
@@ -16144,9 +16306,9 @@ function BuilderBoard({
16144
16306
  ] }) }),
16145
16307
  submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
16146
16308
  /* @__PURE__ */ jsx(Icon, { icon: allCorrect ? CheckCircle : XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
16147
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage ?? t("builder.success") : resolved.failMessage ?? t("builder.incorrect") })
16309
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("builder.success") : str(resolved.failMessage) || t("builder.incorrect") })
16148
16310
  ] }) }),
16149
- showHint && resolved.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.hint }) }),
16311
+ showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
16150
16312
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
16151
16313
  !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
16152
16314
  /* @__PURE__ */ jsx(Icon, { icon: Wrench, size: "sm" }),
@@ -16165,6 +16327,7 @@ var init_BuilderBoard = __esm({
16165
16327
  "components/game/organisms/puzzles/builder/BuilderBoard.tsx"() {
16166
16328
  init_atoms2();
16167
16329
  init_useEventBus();
16330
+ init_boardEntity();
16168
16331
  BuilderBoard.displayName = "BuilderBoard";
16169
16332
  }
16170
16333
  });
@@ -16502,21 +16665,24 @@ function CalendarGrid({
16502
16665
  eventBus.emit(`UI:${longPressEvent}`, { date: day.toISOString(), time, ...longPressPayload });
16503
16666
  }, 500);
16504
16667
  }, [longPressEvent, longPressPayload, eventBus]);
16505
- const renderEvent = (event) => /* @__PURE__ */ jsx(
16506
- Box,
16507
- {
16508
- rounded: "md",
16509
- padding: "xs",
16510
- border: true,
16511
- className: cn(
16512
- "cursor-pointer hover:shadow-sm transition-shadow text-xs truncate",
16513
- event.color ? event.color : "bg-blue-500/15 border-blue-500/30 text-blue-600"
16514
- ),
16515
- onClick: (e) => handleEventClick(event, e),
16516
- children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "truncate font-medium", children: event.title })
16517
- },
16518
- event.id
16519
- );
16668
+ const renderEvent = (event) => {
16669
+ const color = event.color;
16670
+ return /* @__PURE__ */ jsx(
16671
+ Box,
16672
+ {
16673
+ rounded: "md",
16674
+ padding: "xs",
16675
+ border: true,
16676
+ className: cn(
16677
+ "cursor-pointer hover:shadow-sm transition-shadow text-xs truncate",
16678
+ color ? color : "bg-blue-500/15 border-blue-500/30 text-blue-600"
16679
+ ),
16680
+ onClick: (e) => handleEventClick(event, e),
16681
+ children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "truncate font-medium", children: event.title })
16682
+ },
16683
+ event.id
16684
+ );
16685
+ };
16520
16686
  return /* @__PURE__ */ jsxs(
16521
16687
  Box,
16522
16688
  {
@@ -18180,7 +18346,6 @@ var init_CardGrid = __esm({
18180
18346
  alignItems = "stretch",
18181
18347
  className,
18182
18348
  children,
18183
- // EntityDisplayProps
18184
18349
  entity,
18185
18350
  isLoading = false,
18186
18351
  error = null,
@@ -18652,14 +18817,14 @@ var init_CaseStudyOrganism = __esm({
18652
18817
  /* @__PURE__ */ jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((study) => /* @__PURE__ */ jsx(
18653
18818
  CaseStudyCard,
18654
18819
  {
18655
- title: study.title,
18656
- description: study.description,
18657
- category: study.category,
18658
- categoryColor: study.categoryColor,
18659
- href: study.href,
18660
- linkLabel: study.linkLabel
18820
+ title: String(study.title ?? ""),
18821
+ description: String(study.description ?? ""),
18822
+ category: String(study.category ?? ""),
18823
+ categoryColor: study.categoryColor != null ? String(study.categoryColor) : void 0,
18824
+ href: String(study.href ?? ""),
18825
+ linkLabel: study.linkLabel != null ? String(study.linkLabel) : void 0
18661
18826
  },
18662
- study.id
18827
+ String(study.id ?? "")
18663
18828
  )) })
18664
18829
  ] });
18665
18830
  };
@@ -18682,10 +18847,10 @@ function CastleBoard({
18682
18847
  className
18683
18848
  }) {
18684
18849
  const eventBus = useEventBus();
18685
- const resolved = Array.isArray(entity) ? entity[0] : entity;
18686
- const tiles = resolved?.tiles ?? [];
18687
- const features = resolved?.features ?? [];
18688
- const units = resolved?.units ?? [];
18850
+ const resolved = boardEntity(entity);
18851
+ const tiles = Array.isArray(resolved?.tiles) ? resolved.tiles : [];
18852
+ const features = Array.isArray(resolved?.features) ? resolved.features : [];
18853
+ const units = Array.isArray(resolved?.units) ? resolved.units : [];
18689
18854
  const assetManifest = resolved?.assetManifest;
18690
18855
  const backgroundImage = resolved?.backgroundImage;
18691
18856
  const [hoveredTile, setHoveredTile] = useState(null);
@@ -18713,7 +18878,7 @@ function CastleBoard({
18713
18878
  onFeatureClick?.(feature);
18714
18879
  if (featureClickEvent) {
18715
18880
  eventBus.emit(`UI:${featureClickEvent}`, {
18716
- featureId: feature.id,
18881
+ featureId: feature.id ?? "",
18717
18882
  featureType: feature.type,
18718
18883
  x: feature.x,
18719
18884
  y: feature.y
@@ -18781,6 +18946,7 @@ var init_CastleBoard = __esm({
18781
18946
  init_cn();
18782
18947
  init_useEventBus();
18783
18948
  init_IsometricCanvas2();
18949
+ init_boardEntity();
18784
18950
  init_isometric();
18785
18951
  CastleBoard.displayName = "CastleBoard";
18786
18952
  }
@@ -19637,14 +19803,14 @@ function ClassifierBoard({
19637
19803
  }) {
19638
19804
  const { emit } = useEventBus();
19639
19805
  const { t } = useTranslate();
19640
- const resolved = Array.isArray(entity) ? entity[0] : entity;
19806
+ const resolved = boardEntity(entity);
19641
19807
  const [assignments, setAssignments] = useState({});
19642
19808
  const [headerError, setHeaderError] = useState(false);
19643
19809
  const [submitted, setSubmitted] = useState(false);
19644
19810
  const [attempts, setAttempts] = useState(0);
19645
19811
  const [showHint, setShowHint] = useState(false);
19646
- const items = resolved?.items ?? [];
19647
- const categories = resolved?.categories ?? [];
19812
+ const items = Array.isArray(resolved?.items) ? resolved.items : [];
19813
+ const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
19648
19814
  const unassignedItems = items.filter((item) => !assignments[item.id]);
19649
19815
  const allAssigned = Object.keys(assignments).length === items.length;
19650
19816
  const results = submitted ? items.map((item) => ({
@@ -19676,7 +19842,7 @@ function ClassifierBoard({
19676
19842
  }, [items, assignments, attempts, completeEvent, emit]);
19677
19843
  const handleReset = () => {
19678
19844
  setSubmitted(false);
19679
- if (attempts >= 2 && resolved?.hint) {
19845
+ if (attempts >= 2 && str(resolved?.hint)) {
19680
19846
  setShowHint(true);
19681
19847
  }
19682
19848
  };
@@ -19687,20 +19853,25 @@ function ClassifierBoard({
19687
19853
  setShowHint(false);
19688
19854
  };
19689
19855
  if (!resolved) return null;
19856
+ const theme = resolved.theme ?? void 0;
19857
+ const themeBackground = theme?.background;
19858
+ const headerImage = str(resolved.headerImage);
19859
+ const hint = str(resolved.hint);
19860
+ const failMessage = str(resolved.failMessage);
19690
19861
  return /* @__PURE__ */ jsx(
19691
19862
  Box,
19692
19863
  {
19693
19864
  className,
19694
19865
  style: {
19695
- backgroundImage: resolved.theme?.background ? `url(${resolved.theme.background})` : void 0,
19866
+ backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
19696
19867
  backgroundSize: "cover",
19697
19868
  backgroundPosition: "center"
19698
19869
  },
19699
19870
  children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
19700
- resolved.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: resolved.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : resolved.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
19871
+ headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
19701
19872
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
19702
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
19703
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.description })
19873
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
19874
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: str(resolved.description) })
19704
19875
  ] }) }),
19705
19876
  unassignedItems.length > 0 && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
19706
19877
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("classifier.itemsToSort") }),
@@ -19752,10 +19923,10 @@ function ClassifierBoard({
19752
19923
  }) }),
19753
19924
  submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
19754
19925
  /* @__PURE__ */ jsx(Icon, { icon: allCorrect ? CheckCircle : XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
19755
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage ?? t("classifier.allCorrect") : `${correctCount}/${items.length} ${t("classifier.correct")}` }),
19756
- !allCorrect && resolved.failMessage && /* @__PURE__ */ jsx(Typography, { variant: "body", className: "text-muted-foreground", children: resolved.failMessage })
19926
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("classifier.allCorrect") : `${correctCount}/${items.length} ${t("classifier.correct")}` }),
19927
+ !allCorrect && failMessage && /* @__PURE__ */ jsx(Typography, { variant: "body", className: "text-muted-foreground", children: failMessage })
19757
19928
  ] }) }),
19758
- showHint && resolved.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.hint }) }),
19929
+ showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
19759
19930
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
19760
19931
  !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allAssigned, children: [
19761
19932
  /* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
@@ -19774,6 +19945,7 @@ var init_ClassifierBoard = __esm({
19774
19945
  "components/game/organisms/puzzles/classifier/ClassifierBoard.tsx"() {
19775
19946
  init_atoms2();
19776
19947
  init_useEventBus();
19948
+ init_boardEntity();
19777
19949
  ClassifierBoard.displayName = "ClassifierBoard";
19778
19950
  }
19779
19951
  });
@@ -20826,7 +20998,7 @@ function CraftingRecipe({
20826
20998
  className
20827
20999
  }) {
20828
21000
  const eventBus = useEventBus();
20829
- const handleCraft = React79.useCallback(() => {
21001
+ const handleCraft = React80.useCallback(() => {
20830
21002
  onCraft?.();
20831
21003
  if (craftEvent) {
20832
21004
  eventBus.emit(craftEvent, { output: output.label });
@@ -20843,7 +21015,7 @@ function CraftingRecipe({
20843
21015
  children: [
20844
21016
  /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap items-center", children: inputs.map((ingredient, index) => {
20845
21017
  const hasSufficient = ingredient.available >= ingredient.required;
20846
- return /* @__PURE__ */ jsxs(React79.Fragment, { children: [
21018
+ return /* @__PURE__ */ jsxs(React80.Fragment, { children: [
20847
21019
  /* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
20848
21020
  ItemSlot,
20849
21021
  {
@@ -20906,8 +21078,8 @@ function DPad({
20906
21078
  }) {
20907
21079
  const eventBus = useEventBus();
20908
21080
  const sizes = sizeMap6[size];
20909
- const [activeDirections, setActiveDirections] = React79.useState(/* @__PURE__ */ new Set());
20910
- const handlePress = React79.useCallback(
21081
+ const [activeDirections, setActiveDirections] = React80.useState(/* @__PURE__ */ new Set());
21082
+ const handlePress = React80.useCallback(
20911
21083
  (direction) => {
20912
21084
  setActiveDirections((prev) => new Set(prev).add(direction));
20913
21085
  if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
@@ -20915,7 +21087,7 @@ function DPad({
20915
21087
  },
20916
21088
  [directionEvent, eventBus, onDirection]
20917
21089
  );
20918
- const handleRelease = React79.useCallback(
21090
+ const handleRelease = React80.useCallback(
20919
21091
  (direction) => {
20920
21092
  setActiveDirections((prev) => {
20921
21093
  const next = new Set(prev);
@@ -21650,14 +21822,14 @@ function useDataDnd(args) {
21650
21822
  const isZone = Boolean(dragGroup || accepts || sortable);
21651
21823
  const enabled = isZone || Boolean(dndRoot);
21652
21824
  const eventBus = useEventBus();
21653
- const parentRoot = React79__default.useContext(RootCtx);
21825
+ const parentRoot = React80__default.useContext(RootCtx);
21654
21826
  const isRoot = enabled && parentRoot === null;
21655
- const zoneId = React79__default.useId();
21827
+ const zoneId = React80__default.useId();
21656
21828
  const ownGroup = dragGroup ?? accepts ?? zoneId;
21657
- const [optimisticOrders, setOptimisticOrders] = React79__default.useState(() => /* @__PURE__ */ new Map());
21658
- const optimisticOrdersRef = React79__default.useRef(optimisticOrders);
21829
+ const [optimisticOrders, setOptimisticOrders] = React80__default.useState(() => /* @__PURE__ */ new Map());
21830
+ const optimisticOrdersRef = React80__default.useRef(optimisticOrders);
21659
21831
  optimisticOrdersRef.current = optimisticOrders;
21660
- const clearOptimisticOrder = React79__default.useCallback((group) => {
21832
+ const clearOptimisticOrder = React80__default.useCallback((group) => {
21661
21833
  setOptimisticOrders((prev) => {
21662
21834
  if (!prev.has(group)) return prev;
21663
21835
  const next = new Map(prev);
@@ -21682,7 +21854,7 @@ function useDataDnd(args) {
21682
21854
  const raw = it[dndItemIdField];
21683
21855
  return String(raw ?? `__idx_${idx}`);
21684
21856
  }).join("|");
21685
- const itemIds = React79__default.useMemo(
21857
+ const itemIds = React80__default.useMemo(
21686
21858
  () => orderedItems.map((it, idx) => {
21687
21859
  const raw = it[dndItemIdField];
21688
21860
  return raw ?? `__idx_${idx}`;
@@ -21690,7 +21862,7 @@ function useDataDnd(args) {
21690
21862
  [itemIdsSignature]
21691
21863
  );
21692
21864
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
21693
- React79__default.useEffect(() => {
21865
+ React80__default.useEffect(() => {
21694
21866
  const root = isRoot ? null : parentRoot;
21695
21867
  if (root) {
21696
21868
  root.clearOptimisticOrder(ownGroup);
@@ -21698,20 +21870,20 @@ function useDataDnd(args) {
21698
21870
  clearOptimisticOrder(ownGroup);
21699
21871
  }
21700
21872
  }, [itemsContentSig, ownGroup]);
21701
- const zonesRef = React79__default.useRef(/* @__PURE__ */ new Map());
21702
- const registerZone = React79__default.useCallback((zoneId2, meta2) => {
21873
+ const zonesRef = React80__default.useRef(/* @__PURE__ */ new Map());
21874
+ const registerZone = React80__default.useCallback((zoneId2, meta2) => {
21703
21875
  zonesRef.current.set(zoneId2, meta2);
21704
21876
  }, []);
21705
- const unregisterZone = React79__default.useCallback((zoneId2) => {
21877
+ const unregisterZone = React80__default.useCallback((zoneId2) => {
21706
21878
  zonesRef.current.delete(zoneId2);
21707
21879
  }, []);
21708
- const [activeDrag, setActiveDrag] = React79__default.useState(null);
21709
- const [overZoneGroup, setOverZoneGroup] = React79__default.useState(null);
21710
- const meta = React79__default.useMemo(
21880
+ const [activeDrag, setActiveDrag] = React80__default.useState(null);
21881
+ const [overZoneGroup, setOverZoneGroup] = React80__default.useState(null);
21882
+ const meta = React80__default.useMemo(
21711
21883
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
21712
21884
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
21713
21885
  );
21714
- React79__default.useEffect(() => {
21886
+ React80__default.useEffect(() => {
21715
21887
  const target = isRoot ? null : parentRoot;
21716
21888
  if (!target) {
21717
21889
  zonesRef.current.set(zoneId, meta);
@@ -21730,7 +21902,7 @@ function useDataDnd(args) {
21730
21902
  }, [parentRoot, isRoot, zoneId, meta]);
21731
21903
  const sensors = useAlmadarDndSensors(true);
21732
21904
  const collisionDetection = almadarDndCollisionDetection;
21733
- const findZoneByItem = React79__default.useCallback(
21905
+ const findZoneByItem = React80__default.useCallback(
21734
21906
  (id) => {
21735
21907
  for (const z of zonesRef.current.values()) {
21736
21908
  if (z.itemIds.includes(id)) return z;
@@ -21739,7 +21911,7 @@ function useDataDnd(args) {
21739
21911
  },
21740
21912
  []
21741
21913
  );
21742
- React79__default.useCallback(
21914
+ React80__default.useCallback(
21743
21915
  (group) => {
21744
21916
  for (const z of zonesRef.current.values()) {
21745
21917
  if (z.group === group) return z;
@@ -21748,7 +21920,7 @@ function useDataDnd(args) {
21748
21920
  },
21749
21921
  []
21750
21922
  );
21751
- const handleDragEnd = React79__default.useCallback(
21923
+ const handleDragEnd = React80__default.useCallback(
21752
21924
  (event) => {
21753
21925
  const { active, over } = event;
21754
21926
  const activeIdStr = String(active.id);
@@ -21839,8 +22011,8 @@ function useDataDnd(args) {
21839
22011
  },
21840
22012
  [eventBus]
21841
22013
  );
21842
- const sortableData = React79__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
21843
- const SortableItem = React79__default.useCallback(
22014
+ const sortableData = React80__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
22015
+ const SortableItem = React80__default.useCallback(
21844
22016
  ({ id, children }) => {
21845
22017
  const {
21846
22018
  attributes,
@@ -21880,7 +22052,7 @@ function useDataDnd(args) {
21880
22052
  id: droppableId,
21881
22053
  data: sortableData
21882
22054
  });
21883
- const ctx = React79__default.useContext(RootCtx);
22055
+ const ctx = React80__default.useContext(RootCtx);
21884
22056
  const activeDrag2 = ctx?.activeDrag ?? null;
21885
22057
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
21886
22058
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -21895,7 +22067,7 @@ function useDataDnd(args) {
21895
22067
  showForeignPlaceholder,
21896
22068
  ctxAvailable: ctx != null
21897
22069
  });
21898
- React79__default.useEffect(() => {
22070
+ React80__default.useEffect(() => {
21899
22071
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
21900
22072
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
21901
22073
  return /* @__PURE__ */ jsx(
@@ -21909,11 +22081,11 @@ function useDataDnd(args) {
21909
22081
  }
21910
22082
  );
21911
22083
  };
21912
- const rootContextValue = React79__default.useMemo(
22084
+ const rootContextValue = React80__default.useMemo(
21913
22085
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
21914
22086
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
21915
22087
  );
21916
- const handleDragStart = React79__default.useCallback((event) => {
22088
+ const handleDragStart = React80__default.useCallback((event) => {
21917
22089
  const sourceZone = findZoneByItem(event.active.id);
21918
22090
  const rect = event.active.rect.current.initial;
21919
22091
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -21932,7 +22104,7 @@ function useDataDnd(args) {
21932
22104
  isRoot
21933
22105
  });
21934
22106
  }, [findZoneByItem, isRoot, zoneId]);
21935
- const handleDragOver = React79__default.useCallback((event) => {
22107
+ const handleDragOver = React80__default.useCallback((event) => {
21936
22108
  const { active, over } = event;
21937
22109
  const overData = over?.data?.current;
21938
22110
  const overGroup = overData?.dndGroup ?? null;
@@ -22002,7 +22174,7 @@ function useDataDnd(args) {
22002
22174
  return next;
22003
22175
  });
22004
22176
  }, []);
22005
- const handleDragCancel = React79__default.useCallback((event) => {
22177
+ const handleDragCancel = React80__default.useCallback((event) => {
22006
22178
  setActiveDrag(null);
22007
22179
  setOverZoneGroup(null);
22008
22180
  dndLog.warn("dragCancel", {
@@ -22010,12 +22182,12 @@ function useDataDnd(args) {
22010
22182
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
22011
22183
  });
22012
22184
  }, []);
22013
- const handleDragEndWithCleanup = React79__default.useCallback((event) => {
22185
+ const handleDragEndWithCleanup = React80__default.useCallback((event) => {
22014
22186
  handleDragEnd(event);
22015
22187
  setActiveDrag(null);
22016
22188
  setOverZoneGroup(null);
22017
22189
  }, [handleDragEnd]);
22018
- const wrapContainer = React79__default.useCallback(
22190
+ const wrapContainer = React80__default.useCallback(
22019
22191
  (children) => {
22020
22192
  if (!enabled) return children;
22021
22193
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -22069,7 +22241,7 @@ var init_useDataDnd = __esm({
22069
22241
  init_useAlmadarDndCollision();
22070
22242
  init_Box();
22071
22243
  dndLog = createLogger("almadar:ui:dnd");
22072
- RootCtx = React79__default.createContext(null);
22244
+ RootCtx = React80__default.createContext(null);
22073
22245
  }
22074
22246
  });
22075
22247
  function fieldLabel2(key) {
@@ -22589,7 +22761,7 @@ function DataList({
22589
22761
  }) {
22590
22762
  const eventBus = useEventBus();
22591
22763
  const { t } = useTranslate();
22592
- const [visibleCount, setVisibleCount] = React79__default.useState(pageSize || Infinity);
22764
+ const [visibleCount, setVisibleCount] = React80__default.useState(pageSize || Infinity);
22593
22765
  const fieldDefs = fields ?? columns ?? [];
22594
22766
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
22595
22767
  const dnd = useDataDnd({
@@ -22608,7 +22780,7 @@ function DataList({
22608
22780
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
22609
22781
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
22610
22782
  const hasRenderProp = typeof children === "function";
22611
- React79__default.useEffect(() => {
22783
+ React80__default.useEffect(() => {
22612
22784
  const renderItemTypeOf = typeof schemaRenderItem;
22613
22785
  const childrenTypeOf = typeof children;
22614
22786
  if (data.length > 0 && !hasRenderProp) {
@@ -22713,7 +22885,7 @@ function DataList({
22713
22885
  const items2 = data.map((item) => item);
22714
22886
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
22715
22887
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
22716
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
22888
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React80__default.Fragment, { children: [
22717
22889
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
22718
22890
  group.items.map((itemData, index) => {
22719
22891
  const id = itemData.id || `${gi}-${index}`;
@@ -22861,7 +23033,7 @@ function DataList({
22861
23033
  className
22862
23034
  ),
22863
23035
  children: [
22864
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
23036
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React80__default.Fragment, { children: [
22865
23037
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
22866
23038
  group.items.map(
22867
23039
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -24485,7 +24657,7 @@ var init_WizardProgress = __esm({
24485
24657
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
24486
24658
  const isActive = index === currentStep;
24487
24659
  const isCompleted = index < currentStep;
24488
- return /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
24660
+ return /* @__PURE__ */ jsxs(React80__default.Fragment, { children: [
24489
24661
  /* @__PURE__ */ jsx(
24490
24662
  "button",
24491
24663
  {
@@ -25532,9 +25704,9 @@ function ScoreDisplay({
25532
25704
  ...rest
25533
25705
  }) {
25534
25706
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof rest.score === "number" && !Number.isNaN(rest.score) ? rest.score : 0;
25535
- const [displayValue, setDisplayValue] = React79.useState(resolvedValue);
25536
- const [isAnimating, setIsAnimating] = React79.useState(false);
25537
- React79.useEffect(() => {
25707
+ const [displayValue, setDisplayValue] = React80.useState(resolvedValue);
25708
+ const [isAnimating, setIsAnimating] = React80.useState(false);
25709
+ React80.useEffect(() => {
25538
25710
  if (!animated || displayValue === resolvedValue) {
25539
25711
  setDisplayValue(resolvedValue);
25540
25712
  return;
@@ -25681,7 +25853,7 @@ function InventoryGrid({
25681
25853
  const eventBus = useEventBus();
25682
25854
  const slotCount = totalSlots ?? items.length;
25683
25855
  const emptySlotCount = Math.max(0, slotCount - items.length);
25684
- const handleSelect = React79.useCallback(
25856
+ const handleSelect = React80.useCallback(
25685
25857
  (id) => {
25686
25858
  onSelect?.(id);
25687
25859
  if (selectEvent) {
@@ -25967,31 +26139,31 @@ function GameCanvas2D({
25967
26139
  assetBaseUrl = "",
25968
26140
  className
25969
26141
  }) {
25970
- const canvasRef = React79.useRef(null);
25971
- const rafRef = React79.useRef(0);
25972
- const frameRef = React79.useRef(0);
25973
- const lastTimeRef = React79.useRef(0);
25974
- const imageCache = React79.useRef(/* @__PURE__ */ new Map());
26142
+ const canvasRef = React80.useRef(null);
26143
+ const rafRef = React80.useRef(0);
26144
+ const frameRef = React80.useRef(0);
26145
+ const lastTimeRef = React80.useRef(0);
26146
+ const imageCache = React80.useRef(/* @__PURE__ */ new Map());
25975
26147
  const emit = useEmitEvent();
25976
- const onDrawRef = React79.useRef(onDraw);
26148
+ const onDrawRef = React80.useRef(onDraw);
25977
26149
  onDrawRef.current = onDraw;
25978
- const onTickRef = React79.useRef(onTick);
26150
+ const onTickRef = React80.useRef(onTick);
25979
26151
  onTickRef.current = onTick;
25980
- const tickEventRef = React79.useRef(tickEvent);
26152
+ const tickEventRef = React80.useRef(tickEvent);
25981
26153
  tickEventRef.current = tickEvent;
25982
- const drawEventRef = React79.useRef(drawEvent);
26154
+ const drawEventRef = React80.useRef(drawEvent);
25983
26155
  drawEventRef.current = drawEvent;
25984
- const emitRef = React79.useRef(emit);
26156
+ const emitRef = React80.useRef(emit);
25985
26157
  emitRef.current = emit;
25986
- const assetBaseUrlRef = React79.useRef(assetBaseUrl);
26158
+ const assetBaseUrlRef = React80.useRef(assetBaseUrl);
25987
26159
  assetBaseUrlRef.current = assetBaseUrl;
25988
- const backgroundImageRef = React79.useRef(backgroundImage);
26160
+ const backgroundImageRef = React80.useRef(backgroundImage);
25989
26161
  backgroundImageRef.current = backgroundImage;
25990
- const widthRef = React79.useRef(width);
26162
+ const widthRef = React80.useRef(width);
25991
26163
  widthRef.current = width;
25992
- const heightRef = React79.useRef(height);
26164
+ const heightRef = React80.useRef(height);
25993
26165
  heightRef.current = height;
25994
- const loadImage = React79.useCallback((url) => {
26166
+ const loadImage = React80.useCallback((url) => {
25995
26167
  const fullUrl = url.startsWith("http") ? url : `${assetBaseUrlRef.current}${url}`;
25996
26168
  const cached = imageCache.current.get(fullUrl);
25997
26169
  if (cached?.complete && cached.naturalWidth > 0) return cached;
@@ -26003,7 +26175,7 @@ function GameCanvas2D({
26003
26175
  }
26004
26176
  return null;
26005
26177
  }, []);
26006
- React79.useEffect(() => {
26178
+ React80.useEffect(() => {
26007
26179
  const canvas = canvasRef.current;
26008
26180
  if (!canvas) return;
26009
26181
  const ctx = canvas.getContext("2d");
@@ -26358,7 +26530,7 @@ function TurnPanel({
26358
26530
  className
26359
26531
  }) {
26360
26532
  const eventBus = useEventBus();
26361
- const handleAction = React79.useCallback(
26533
+ const handleAction = React80.useCallback(
26362
26534
  (event) => {
26363
26535
  if (event) {
26364
26536
  eventBus.emit(event, { turn: currentTurn, phase, activeTeam });
@@ -26504,7 +26676,7 @@ function UnitCommandBar({
26504
26676
  className
26505
26677
  }) {
26506
26678
  const eventBus = useEventBus();
26507
- const handleCommand = React79.useCallback(
26679
+ const handleCommand = React80.useCallback(
26508
26680
  (event) => {
26509
26681
  if (event) {
26510
26682
  eventBus.emit(event, { unitId: selectedUnitId });
@@ -26837,7 +27009,7 @@ function InventoryPanel({
26837
27009
  const slotArray = Array.from({ length: safeSlots }, (_, index) => {
26838
27010
  return safeItems[index] ?? null;
26839
27011
  });
26840
- const rows = Math.ceil(safeSlots / safeColumns);
27012
+ const rows2 = Math.ceil(safeSlots / safeColumns);
26841
27013
  const handleSlotClick = useCallback((index) => {
26842
27014
  if (selectSlotEvent) eventBus.emit(`UI:${selectSlotEvent}`, { index });
26843
27015
  onSelectSlot?.(index);
@@ -26906,7 +27078,7 @@ function InventoryPanel({
26906
27078
  className: "grid gap-1 bg-[var(--color-card)] p-2 rounded-container border border-border",
26907
27079
  style: {
26908
27080
  gridTemplateColumns: `repeat(${safeColumns}, ${slotSize}px)`,
26909
- gridTemplateRows: `repeat(${rows}, ${slotSize}px)`
27081
+ gridTemplateRows: `repeat(${rows2}, ${slotSize}px)`
26910
27082
  },
26911
27083
  children: slotArray.map((item, index) => /* @__PURE__ */ jsx(
26912
27084
  "button",
@@ -26989,7 +27161,7 @@ function GameMenu({
26989
27161
  } catch {
26990
27162
  }
26991
27163
  const eventBus = eventBusProp || eventBusFromHook;
26992
- const handleOptionClick = React79.useCallback(
27164
+ const handleOptionClick = React80.useCallback(
26993
27165
  (option) => {
26994
27166
  if (option.event && eventBus) {
26995
27167
  eventBus.emit(`UI:${option.event}`, { option });
@@ -27103,7 +27275,7 @@ function GameOverScreen({
27103
27275
  } catch {
27104
27276
  }
27105
27277
  const eventBus = eventBusProp || eventBusFromHook;
27106
- const handleActionClick = React79.useCallback(
27278
+ const handleActionClick = React80.useCallback(
27107
27279
  (action) => {
27108
27280
  if (action.event && eventBus) {
27109
27281
  eventBus.emit(`UI:${action.event}`, { action });
@@ -28602,8 +28774,8 @@ function TableView({
28602
28774
  }) {
28603
28775
  const eventBus = useEventBus();
28604
28776
  const { t } = useTranslate();
28605
- const [visibleCount, setVisibleCount] = React79__default.useState(pageSize > 0 ? pageSize : Infinity);
28606
- const [localSelected, setLocalSelected] = React79__default.useState(/* @__PURE__ */ new Set());
28777
+ const [visibleCount, setVisibleCount] = React80__default.useState(pageSize > 0 ? pageSize : Infinity);
28778
+ const [localSelected, setLocalSelected] = React80__default.useState(/* @__PURE__ */ new Set());
28607
28779
  const colDefs = columns ?? fields ?? [];
28608
28780
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
28609
28781
  const dnd = useDataDnd({
@@ -28798,12 +28970,12 @@ function TableView({
28798
28970
  ]
28799
28971
  }
28800
28972
  );
28801
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React79__default.Fragment, { children: rowInner }, id);
28973
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React80__default.Fragment, { children: rowInner }, id);
28802
28974
  };
28803
28975
  const items = data.map((row) => row);
28804
28976
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
28805
28977
  let runningIndex = 0;
28806
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
28978
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React80__default.Fragment, { children: [
28807
28979
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
28808
28980
  group.items.map((row) => renderRow(row, runningIndex++))
28809
28981
  ] }, gi)) });
@@ -30155,7 +30327,7 @@ var init_StepFlow = __esm({
30155
30327
  className
30156
30328
  }) => {
30157
30329
  if (orientation === "vertical") {
30158
- return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React79__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
30330
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React80__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
30159
30331
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
30160
30332
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
30161
30333
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -30166,7 +30338,7 @@ var init_StepFlow = __esm({
30166
30338
  ] })
30167
30339
  ] }) }, index)) });
30168
30340
  }
30169
- 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(React79__default.Fragment, { children: [
30341
+ 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(React80__default.Fragment, { children: [
30170
30342
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
30171
30343
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
30172
30344
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -30892,11 +31064,11 @@ function LatticeSVG({
30892
31064
  }) {
30893
31065
  const paths = [];
30894
31066
  const cols = 5;
30895
- const rows = Math.ceil(h / (w / cols));
31067
+ const rows2 = Math.ceil(h / (w / cols));
30896
31068
  const cellW = w / cols;
30897
31069
  const cellH = cellW;
30898
31070
  const bulge = cellW * 0.3;
30899
- for (let row = 0; row < rows; row++) {
31071
+ for (let row = 0; row < rows2; row++) {
30900
31072
  for (let col = 0; col < cols; col++) {
30901
31073
  const cx = col * cellW + cellW / 2;
30902
31074
  const cy = row * cellH + cellH / 2;
@@ -31142,7 +31314,7 @@ var init_LikertScale = __esm({
31142
31314
  md: "text-base",
31143
31315
  lg: "text-lg"
31144
31316
  };
31145
- LikertScale = React79__default.forwardRef(
31317
+ LikertScale = React80__default.forwardRef(
31146
31318
  ({
31147
31319
  question,
31148
31320
  options = DEFAULT_LIKERT_OPTIONS,
@@ -31154,7 +31326,7 @@ var init_LikertScale = __esm({
31154
31326
  variant = "radios",
31155
31327
  className
31156
31328
  }, ref) => {
31157
- const groupId = React79__default.useId();
31329
+ const groupId = React80__default.useId();
31158
31330
  const eventBus = useEventBus();
31159
31331
  const handleSelect = useCallback(
31160
31332
  (next) => {
@@ -31308,7 +31480,7 @@ var init_MatrixQuestion = __esm({
31308
31480
  };
31309
31481
  MatrixQuestion = ({
31310
31482
  title,
31311
- rows,
31483
+ rows: rows2,
31312
31484
  columns = DEFAULT_MATRIX_COLUMNS,
31313
31485
  values,
31314
31486
  onChange,
@@ -31318,7 +31490,7 @@ var init_MatrixQuestion = __esm({
31318
31490
  className
31319
31491
  }) => {
31320
31492
  const styles = sizeStyles13[size];
31321
- const safeRows = rows ?? [];
31493
+ const safeRows = rows2 ?? [];
31322
31494
  const safeValues = values ?? {};
31323
31495
  const eventBus = useEventBus();
31324
31496
  const handleChange = useCallback(
@@ -31946,7 +32118,8 @@ var init_PositionedCanvas = __esm({
31946
32118
  dragRef.current = null;
31947
32119
  setDraggingId(null);
31948
32120
  if (!wasDrag) {
31949
- const next = selectedId === item.id ? null : item.id;
32121
+ const itemId = item.id;
32122
+ const next = selectedId === itemId ? null : itemId;
31950
32123
  onSelect?.(next);
31951
32124
  if (selectEvent) {
31952
32125
  eventBus.emit(`UI:${selectEvent}`, { id: next });
@@ -31981,15 +32154,22 @@ var init_PositionedCanvas = __esm({
31981
32154
  style: { width, height },
31982
32155
  onClick: handleContainerClick,
31983
32156
  children: items.map((item) => {
32157
+ const itemId = item.id;
32158
+ const label = item.label;
32159
+ const x = item.x;
32160
+ const y = item.y;
32161
+ const capacity = item.capacity;
32162
+ const partySize = item.partySize;
32163
+ const serverName = item.serverName;
31984
32164
  const status = item.status ?? "empty";
31985
32165
  const shape = item.shape ?? "round";
31986
- const isSelected = selectedId === item.id;
31987
- const isDragging = draggingId === item.id;
32166
+ const isSelected = selectedId === itemId;
32167
+ const isDragging = draggingId === itemId;
31988
32168
  const statusBadge = STATUS_BADGE[status];
31989
32169
  return /* @__PURE__ */ jsxs(
31990
32170
  Box,
31991
32171
  {
31992
- "data-testid": `item-node-${item.id}`,
32172
+ "data-testid": `item-node-${itemId}`,
31993
32173
  "data-status": status,
31994
32174
  className: cn(
31995
32175
  "absolute flex flex-col items-center justify-center gap-1 border-2 select-none",
@@ -32000,7 +32180,7 @@ var init_PositionedCanvas = __esm({
32000
32180
  isSelected && "outline outline-2 outline-offset-2 outline-primary shadow-md",
32001
32181
  isDragging && "shadow-lg z-10"
32002
32182
  ),
32003
- style: { left: item.x, top: item.y, touchAction: "none" },
32183
+ style: { left: x, top: y, touchAction: "none" },
32004
32184
  onPointerDown: (e) => handlePointerDown(e, item),
32005
32185
  onPointerMove: handlePointerMove,
32006
32186
  onPointerUp: (e) => handlePointerUp(e, item),
@@ -32008,10 +32188,10 @@ var init_PositionedCanvas = __esm({
32008
32188
  children: [
32009
32189
  /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-1", children: [
32010
32190
  getStatusIcon(status),
32011
- /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "semibold", children: item.label })
32191
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "semibold", children: label })
32012
32192
  ] }),
32013
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: item.partySize !== void 0 && status === "seated" ? `${item.partySize}/${item.capacity}` : `Cap ${item.capacity}` }),
32014
- status === "seated" && item.serverName && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "truncate max-w-[80%]", children: item.serverName }),
32193
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: partySize !== void 0 && status === "seated" ? `${partySize}/${capacity}` : `Cap ${capacity}` }),
32194
+ status === "seated" && serverName && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "truncate max-w-[80%]", children: serverName }),
32015
32195
  isSelected && /* @__PURE__ */ jsx(
32016
32196
  Badge,
32017
32197
  {
@@ -32023,7 +32203,7 @@ var init_PositionedCanvas = __esm({
32023
32203
  )
32024
32204
  ]
32025
32205
  },
32026
- item.id
32206
+ itemId
32027
32207
  );
32028
32208
  })
32029
32209
  }
@@ -32795,9 +32975,10 @@ var init_RichBlockEditor = __esm({
32795
32975
  });
32796
32976
  function collectInitiallyCollapsed(nodes, acc) {
32797
32977
  for (const n of nodes) {
32978
+ const replies = n.replies;
32798
32979
  if (n.collapsed) acc.add(n.id);
32799
- if (n.replies && n.replies.length > 0) {
32800
- collectInitiallyCollapsed(n.replies, acc);
32980
+ if (replies && replies.length > 0) {
32981
+ collectInitiallyCollapsed(replies, acc);
32801
32982
  }
32802
32983
  }
32803
32984
  }
@@ -32827,44 +33008,52 @@ var init_ReplyTree = __esm({
32827
33008
  }) => {
32828
33009
  const eventBus = useEventBus();
32829
33010
  const { t } = useTranslate();
32830
- const hasReplies = !!node.replies && node.replies.length > 0;
32831
- const isCollapsed = collapsedSet.has(node.id);
33011
+ const nodeId = node.id;
33012
+ const authorName = node.authorName;
33013
+ const authorAvatarUrl = node.authorAvatarUrl;
33014
+ const content = node.content;
33015
+ const postedAt = node.postedAt;
33016
+ const voteCount = node.voteCount;
33017
+ const userVote = node.userVote;
33018
+ const replies = node.replies;
33019
+ const hasReplies = !!replies && replies.length > 0;
33020
+ const isCollapsed = collapsedSet.has(nodeId);
32832
33021
  const atMaxDepth = depth >= maxDepth;
32833
33022
  const [replyOpen, setReplyOpen] = useState(false);
32834
33023
  const [draft, setDraft] = useState("");
32835
33024
  const handleVote = useCallback(
32836
33025
  (next) => {
32837
- onVote?.(node.id, next);
32838
- if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId: node.id, vote: next });
33026
+ onVote?.(nodeId, next);
33027
+ if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId, vote: next });
32839
33028
  },
32840
- [node.id, onVote, voteEvent, eventBus]
33029
+ [nodeId, onVote, voteEvent, eventBus]
32841
33030
  );
32842
33031
  const handleReply = useCallback(() => {
32843
- onReply?.(node.id);
33032
+ onReply?.(nodeId);
32844
33033
  setReplyOpen((open) => !open);
32845
- }, [node.id, onReply]);
33034
+ }, [nodeId, onReply]);
32846
33035
  const handleSubmitReply = useCallback(() => {
32847
- const content = draft.trim();
32848
- if (!content) return;
32849
- if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: node.id, content });
33036
+ const text = draft.trim();
33037
+ if (!text) return;
33038
+ if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: nodeId, content: text });
32850
33039
  setDraft("");
32851
33040
  setReplyOpen(false);
32852
- }, [node.id, draft, replyEvent, eventBus]);
33041
+ }, [nodeId, draft, replyEvent, eventBus]);
32853
33042
  const handleCancelReply = useCallback(() => {
32854
33043
  setDraft("");
32855
33044
  setReplyOpen(false);
32856
33045
  }, []);
32857
33046
  const handleFlag = useCallback(() => {
32858
- onFlag?.(node.id);
32859
- if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId: node.id });
32860
- }, [node.id, onFlag, flagEvent, eventBus]);
33047
+ onFlag?.(nodeId);
33048
+ if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId });
33049
+ }, [nodeId, onFlag, flagEvent, eventBus]);
32861
33050
  const handleContinue = useCallback(() => {
32862
- onContinueThread?.(node.id);
32863
- if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId: node.id });
32864
- }, [node.id, onContinueThread, continueThreadEvent, eventBus]);
33051
+ onContinueThread?.(nodeId);
33052
+ if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId });
33053
+ }, [nodeId, onContinueThread, continueThreadEvent, eventBus]);
32865
33054
  const handleToggle = useCallback(() => {
32866
- toggleCollapse(node.id);
32867
- }, [node.id, toggleCollapse]);
33055
+ toggleCollapse(nodeId);
33056
+ }, [nodeId, toggleCollapse]);
32868
33057
  return /* @__PURE__ */ jsxs(Box, { className: "flex flex-row gap-2 items-stretch min-w-0", children: [
32869
33058
  /* @__PURE__ */ jsxs(Box, { className: "flex flex-col items-center flex-shrink-0 w-6", children: [
32870
33059
  hasReplies ? /* @__PURE__ */ jsx(
@@ -32896,25 +33085,25 @@ var init_ReplyTree = __esm({
32896
33085
  /* @__PURE__ */ jsx(
32897
33086
  Avatar,
32898
33087
  {
32899
- src: node.authorAvatarUrl,
32900
- name: node.authorName,
33088
+ src: authorAvatarUrl,
33089
+ name: authorName,
32901
33090
  size: "sm"
32902
33091
  }
32903
33092
  ),
32904
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "semibold", children: node.authorName }),
32905
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: node.postedAt })
33093
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "semibold", children: authorName }),
33094
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: postedAt })
32906
33095
  ] }),
32907
- /* @__PURE__ */ jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children: node.content }),
33096
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children: content }),
32908
33097
  showActions && /* @__PURE__ */ jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
32909
33098
  /* @__PURE__ */ jsx(
32910
33099
  VoteStack,
32911
33100
  {
32912
- count: node.voteCount ?? 0,
32913
- userVote: node.userVote ?? null,
33101
+ count: voteCount ?? 0,
33102
+ userVote: userVote ?? null,
32914
33103
  onVote: handleVote,
32915
33104
  size: "sm",
32916
33105
  variant: "horizontal",
32917
- label: t("replyTree.voteOnReplyBy", { author: node.authorName })
33106
+ label: t("replyTree.voteOnReplyBy", { author: authorName })
32918
33107
  }
32919
33108
  ),
32920
33109
  /* @__PURE__ */ jsx(
@@ -32924,7 +33113,7 @@ var init_ReplyTree = __esm({
32924
33113
  size: "sm",
32925
33114
  leftIcon: "message-square",
32926
33115
  onClick: handleReply,
32927
- "aria-label": t("replyTree.replyTo", { author: node.authorName }),
33116
+ "aria-label": t("replyTree.replyTo", { author: authorName }),
32928
33117
  children: t("replyTree.reply")
32929
33118
  }
32930
33119
  ),
@@ -32935,7 +33124,7 @@ var init_ReplyTree = __esm({
32935
33124
  size: "sm",
32936
33125
  leftIcon: "flag",
32937
33126
  onClick: handleFlag,
32938
- "aria-label": t("replyTree.flagReplyBy", { author: node.authorName }),
33127
+ "aria-label": t("replyTree.flagReplyBy", { author: authorName }),
32939
33128
  children: t("replyTree.flag")
32940
33129
  }
32941
33130
  )
@@ -32947,9 +33136,9 @@ var init_ReplyTree = __esm({
32947
33136
  inputType: "textarea",
32948
33137
  rows: 2,
32949
33138
  value: draft,
32950
- placeholder: t("replyTree.replyToPlaceholder", { author: node.authorName }),
33139
+ placeholder: t("replyTree.replyToPlaceholder", { author: authorName }),
32951
33140
  onChange: (e) => setDraft(e.target.value),
32952
- "aria-label": t("replyTree.replyTo", { author: node.authorName })
33141
+ "aria-label": t("replyTree.replyTo", { author: authorName })
32953
33142
  }
32954
33143
  ),
32955
33144
  /* @__PURE__ */ jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
@@ -32980,7 +33169,7 @@ var init_ReplyTree = __esm({
32980
33169
  ),
32981
33170
  children: t("replyTree.continueThread")
32982
33171
  }
32983
- ) : /* @__PURE__ */ jsx(Box, { className: "flex flex-col gap-2 mt-1", children: node.replies.map((child) => /* @__PURE__ */ jsx(
33172
+ ) : /* @__PURE__ */ jsx(Box, { className: "flex flex-col gap-2 mt-1", children: replies.map((child) => /* @__PURE__ */ jsx(
32984
33173
  ReplyTreeNode,
32985
33174
  {
32986
33175
  node: child,
@@ -33442,7 +33631,7 @@ var init_DocBreadcrumb = __esm({
33442
33631
  "aria-label": t("aria.breadcrumb"),
33443
33632
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
33444
33633
  const isLast = idx === items.length - 1;
33445
- return /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
33634
+ return /* @__PURE__ */ jsxs(React80__default.Fragment, { children: [
33446
33635
  idx > 0 && /* @__PURE__ */ jsx(
33447
33636
  Icon,
33448
33637
  {
@@ -34406,7 +34595,7 @@ var init_MiniStateMachine = __esm({
34406
34595
  const x = 2 + i * (NODE_W + GAP2 + ARROW_W + GAP2);
34407
34596
  const tc = transitionCounts[s.name] ?? 0;
34408
34597
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
34409
- return /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
34598
+ return /* @__PURE__ */ jsxs(React80__default.Fragment, { children: [
34410
34599
  /* @__PURE__ */ jsx(
34411
34600
  AvlState,
34412
34601
  {
@@ -34610,7 +34799,7 @@ var init_PageHeader = __esm({
34610
34799
  info: "bg-info/10 text-info"
34611
34800
  };
34612
34801
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
34613
- 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(React79__default.Fragment, { children: [
34802
+ 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(React80__default.Fragment, { children: [
34614
34803
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
34615
34804
  crumb.href ? /* @__PURE__ */ jsx(
34616
34805
  "a",
@@ -34719,7 +34908,7 @@ var init_FormSection = __esm({
34719
34908
  columns = 1,
34720
34909
  className
34721
34910
  }) => {
34722
- const [collapsed, setCollapsed] = React79__default.useState(defaultCollapsed);
34911
+ const [collapsed, setCollapsed] = React80__default.useState(defaultCollapsed);
34723
34912
  const { t } = useTranslate();
34724
34913
  const eventBus = useEventBus();
34725
34914
  const gridClass = {
@@ -34727,7 +34916,7 @@ var init_FormSection = __esm({
34727
34916
  2: "grid-cols-1 md:grid-cols-2",
34728
34917
  3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
34729
34918
  }[columns];
34730
- React79__default.useCallback(() => {
34919
+ React80__default.useCallback(() => {
34731
34920
  if (collapsible) {
34732
34921
  setCollapsed((prev) => !prev);
34733
34922
  eventBus.emit("UI:TOGGLE_COLLAPSE", { collapsed: !collapsed });
@@ -35427,8 +35616,8 @@ var init_WizardContainer = __esm({
35427
35616
  return void 0;
35428
35617
  if (typeof controlledStep === "number") return controlledStep;
35429
35618
  if (typeof controlledStep === "string") return parseInt(controlledStep, 10);
35430
- const num = Number(controlledStep);
35431
- return isNaN(num) ? void 0 : num;
35619
+ const num2 = Number(controlledStep);
35620
+ return isNaN(num2) ? void 0 : num2;
35432
35621
  })();
35433
35622
  const currentStep = normalizedControlledStep !== void 0 ? normalizedControlledStep : internalStep;
35434
35623
  const totalSteps = steps.length;
@@ -35474,7 +35663,7 @@ var init_WizardContainer = __esm({
35474
35663
  const isCompleted = index < currentStep;
35475
35664
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
35476
35665
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
35477
- return /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
35666
+ return /* @__PURE__ */ jsxs(React80__default.Fragment, { children: [
35478
35667
  /* @__PURE__ */ jsx(
35479
35668
  Button,
35480
35669
  {
@@ -37253,7 +37442,7 @@ function DebuggerBoard({
37253
37442
  }) {
37254
37443
  const { emit } = useEventBus();
37255
37444
  const { t } = useTranslate();
37256
- const resolved = Array.isArray(entity) ? entity[0] : entity;
37445
+ const resolved = boardEntity(entity);
37257
37446
  const [flaggedLines, setFlaggedLines] = useState(/* @__PURE__ */ new Set());
37258
37447
  const [headerError, setHeaderError] = useState(false);
37259
37448
  const [submitted, setSubmitted] = useState(false);
@@ -37271,7 +37460,7 @@ function DebuggerBoard({
37271
37460
  return next;
37272
37461
  });
37273
37462
  };
37274
- const lines = resolved?.lines ?? [];
37463
+ const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
37275
37464
  const bugLines = lines.filter((l) => l.isBug);
37276
37465
  const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
37277
37466
  const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
@@ -37286,7 +37475,7 @@ function DebuggerBoard({
37286
37475
  }, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
37287
37476
  const handleReset = () => {
37288
37477
  setSubmitted(false);
37289
- if (attempts >= 2 && resolved?.hint) {
37478
+ if (attempts >= 2 && str(resolved?.hint)) {
37290
37479
  setShowHint(true);
37291
37480
  }
37292
37481
  };
@@ -37297,24 +37486,28 @@ function DebuggerBoard({
37297
37486
  setShowHint(false);
37298
37487
  };
37299
37488
  if (!resolved) return null;
37489
+ const theme = resolved.theme ?? void 0;
37490
+ const themeBackground = theme?.background;
37491
+ const headerImage = str(resolved.headerImage);
37492
+ const hint = str(resolved.hint);
37300
37493
  return /* @__PURE__ */ jsx(
37301
37494
  Box,
37302
37495
  {
37303
37496
  className,
37304
37497
  style: {
37305
- backgroundImage: resolved.theme?.background ? `url(${resolved.theme.background})` : void 0,
37498
+ backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
37306
37499
  backgroundSize: "cover",
37307
37500
  backgroundPosition: "center"
37308
37501
  },
37309
37502
  children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
37310
- resolved.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: resolved.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : resolved.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
37503
+ headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
37311
37504
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
37312
37505
  /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
37313
37506
  /* @__PURE__ */ jsx(Icon, { icon: Bug, size: "sm" }),
37314
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title })
37507
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) })
37315
37508
  ] }),
37316
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.description }),
37317
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(resolved.bugCount) }) })
37509
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: str(resolved.description) }),
37510
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
37318
37511
  ] }) }),
37319
37512
  /* @__PURE__ */ jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsx(VStack, { gap: "none", children: lines.map((line, i) => {
37320
37513
  const isFlagged = flaggedLines.has(line.id);
@@ -37346,7 +37539,7 @@ function DebuggerBoard({
37346
37539
  );
37347
37540
  }) }) }),
37348
37541
  submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
37349
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage ?? t("debugger.allFound") : `${correctFlags.length}/${bugLines.length} ${t("debugger.bugsFound")}` }),
37542
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("debugger.allFound") : `${correctFlags.length}/${bugLines.length} ${t("debugger.bugsFound")}` }),
37350
37543
  bugLines.map((line) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "start", children: [
37351
37544
  /* @__PURE__ */ jsx(
37352
37545
  Icon,
@@ -37362,7 +37555,7 @@ function DebuggerBoard({
37362
37555
  ] })
37363
37556
  ] }, line.id))
37364
37557
  ] }) }),
37365
- showHint && resolved.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.hint }) }),
37558
+ showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
37366
37559
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
37367
37560
  !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.size === 0, children: [
37368
37561
  /* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
@@ -37381,6 +37574,7 @@ var init_DebuggerBoard = __esm({
37381
37574
  "components/game/organisms/puzzles/debugger/DebuggerBoard.tsx"() {
37382
37575
  init_atoms2();
37383
37576
  init_useEventBus();
37577
+ init_boardEntity();
37384
37578
  DebuggerBoard.displayName = "DebuggerBoard";
37385
37579
  }
37386
37580
  });
@@ -37418,7 +37612,7 @@ function getBadgeVariant(fieldName, value) {
37418
37612
  return "default";
37419
37613
  }
37420
37614
  function formatFieldLabel(fieldName) {
37421
- return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase());
37615
+ return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase());
37422
37616
  }
37423
37617
  function formatFieldValue(value, fieldName) {
37424
37618
  if (typeof value === "number") {
@@ -37437,26 +37631,26 @@ function formatFieldValue(value, fieldName) {
37437
37631
  }
37438
37632
  function renderRichFieldValue(value, fieldName, fieldType) {
37439
37633
  if (value === void 0 || value === null) return "\u2014";
37440
- const str = String(value);
37634
+ const str2 = String(value);
37441
37635
  switch (fieldType) {
37442
37636
  case "image":
37443
37637
  case "url": {
37444
- if (str.match(/\.(png|jpe?g|gif|svg|webp|avif)(\?|$)/i) || str.startsWith("data:image/")) {
37638
+ if (str2.match(/\.(png|jpe?g|gif|svg|webp|avif)(\?|$)/i) || str2.startsWith("data:image/")) {
37445
37639
  return /* @__PURE__ */ jsx(Box, { className: "mt-1 max-w-full", children: /* @__PURE__ */ jsx(
37446
37640
  "img",
37447
37641
  {
37448
- src: str,
37642
+ src: str2,
37449
37643
  alt: formatFieldLabel(fieldName),
37450
37644
  className: "max-w-full max-h-64 rounded-md object-contain",
37451
37645
  loading: "lazy"
37452
37646
  }
37453
37647
  ) });
37454
37648
  }
37455
- return str;
37649
+ return str2;
37456
37650
  }
37457
37651
  case "markdown":
37458
37652
  case "richtext":
37459
- return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "break-words", children: str }), children: /* @__PURE__ */ jsx(
37653
+ return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "break-words", children: str2 }), children: /* @__PURE__ */ jsx(
37460
37654
  Box,
37461
37655
  {
37462
37656
  className: "prose prose-sm max-w-none",
@@ -37474,11 +37668,11 @@ function renderRichFieldValue(value, fieldName, fieldType) {
37474
37668
  "--tw-prose-th-borders": "var(--color-border)",
37475
37669
  "--tw-prose-td-borders": "var(--color-border)"
37476
37670
  },
37477
- children: /* @__PURE__ */ jsx(ReactMarkdown2, { children: str })
37671
+ children: /* @__PURE__ */ jsx(ReactMarkdown2, { children: str2 })
37478
37672
  }
37479
37673
  ) });
37480
37674
  case "code":
37481
- return /* @__PURE__ */ jsx(Box, { className: "mt-1 rounded-md bg-muted p-3 overflow-x-auto", children: /* @__PURE__ */ jsx("pre", { className: "text-sm font-mono whitespace-pre-wrap break-words m-0", children: /* @__PURE__ */ jsx("code", { children: str }) }) });
37675
+ return /* @__PURE__ */ jsx(Box, { className: "mt-1 rounded-md bg-muted p-3 overflow-x-auto", children: /* @__PURE__ */ jsx("pre", { className: "text-sm font-mono whitespace-pre-wrap break-words m-0", children: /* @__PURE__ */ jsx("code", { children: str2 }) }) });
37482
37676
  case "html":
37483
37677
  return /* @__PURE__ */ jsx(
37484
37678
  Box,
@@ -37498,12 +37692,12 @@ function renderRichFieldValue(value, fieldName, fieldType) {
37498
37692
  "--tw-prose-th-borders": "var(--color-border)",
37499
37693
  "--tw-prose-td-borders": "var(--color-border)"
37500
37694
  },
37501
- children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: str })
37695
+ children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: str2 })
37502
37696
  }
37503
37697
  );
37504
37698
  case "date":
37505
37699
  case "datetime": {
37506
- const d = new Date(str);
37700
+ const d = new Date(str2);
37507
37701
  if (!isNaN(d.getTime())) {
37508
37702
  return d.toLocaleDateString(void 0, {
37509
37703
  year: "numeric",
@@ -37512,7 +37706,7 @@ function renderRichFieldValue(value, fieldName, fieldType) {
37512
37706
  ...fieldType === "datetime" ? { hour: "2-digit", minute: "2-digit" } : {}
37513
37707
  });
37514
37708
  }
37515
- return str;
37709
+ return str2;
37516
37710
  }
37517
37711
  default:
37518
37712
  return formatFieldValue(value, fieldName);
@@ -37912,7 +38106,7 @@ var init_DialogueBubble = __esm({
37912
38106
  }
37913
38107
  });
37914
38108
  function extractTitle(children) {
37915
- if (!React79__default.isValidElement(children)) return void 0;
38109
+ if (!React80__default.isValidElement(children)) return void 0;
37916
38110
  const props = children.props;
37917
38111
  if (typeof props.title === "string") {
37918
38112
  return props.title;
@@ -38024,7 +38218,7 @@ function LinearView({
38024
38218
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
38025
38219
  const isDone = i < currentIdx;
38026
38220
  const isCurrent = i === currentIdx;
38027
- return /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
38221
+ return /* @__PURE__ */ jsxs(React80__default.Fragment, { children: [
38028
38222
  i > 0 && /* @__PURE__ */ jsx(
38029
38223
  Typography,
38030
38224
  {
@@ -38285,6 +38479,40 @@ var init_RuleEditor = __esm({
38285
38479
  RuleEditor.displayName = "RuleEditor";
38286
38480
  }
38287
38481
  });
38482
+
38483
+ // components/game/organisms/puzzles/event-handler/puzzleObject.ts
38484
+ function objId(o) {
38485
+ return o.id == null ? "" : String(o.id);
38486
+ }
38487
+ function objName(o) {
38488
+ return o.name == null ? "" : String(o.name);
38489
+ }
38490
+ function objIcon(o) {
38491
+ return o.icon == null ? "" : String(o.icon);
38492
+ }
38493
+ function objStates(o) {
38494
+ return Array.isArray(o.states) ? o.states : [];
38495
+ }
38496
+ function objCurrentState(o) {
38497
+ return o.currentState == null ? "" : String(o.currentState);
38498
+ }
38499
+ function objAvailableEvents(o) {
38500
+ return Array.isArray(o.availableEvents) ? o.availableEvents : [];
38501
+ }
38502
+ function objAvailableActions(o) {
38503
+ return Array.isArray(o.availableActions) ? o.availableActions : [];
38504
+ }
38505
+ function objRules(o) {
38506
+ return Array.isArray(o.rules) ? o.rules : [];
38507
+ }
38508
+ function objMaxRules(o) {
38509
+ const n = Number(o.maxRules);
38510
+ return Number.isFinite(n) && n > 0 ? n : 3;
38511
+ }
38512
+ var init_puzzleObject = __esm({
38513
+ "components/game/organisms/puzzles/event-handler/puzzleObject.ts"() {
38514
+ }
38515
+ });
38288
38516
  function ObjectRulePanel({
38289
38517
  object,
38290
38518
  onRulesChange,
@@ -38292,55 +38520,63 @@ function ObjectRulePanel({
38292
38520
  className
38293
38521
  }) {
38294
38522
  const { t } = useTranslate();
38295
- const maxRules = object.maxRules || 3;
38296
- const canAdd = object.rules.length < maxRules;
38523
+ const id = objId(object);
38524
+ const name = objName(object);
38525
+ const icon = objIcon(object);
38526
+ const states = objStates(object);
38527
+ const currentState = objCurrentState(object);
38528
+ const availableEvents = objAvailableEvents(object);
38529
+ const availableActions = objAvailableActions(object);
38530
+ const rules = objRules(object);
38531
+ const maxRules = objMaxRules(object);
38532
+ const canAdd = rules.length < maxRules;
38297
38533
  const handleRuleChange = useCallback((index, updatedRule) => {
38298
- const newRules = [...object.rules];
38534
+ const newRules = [...rules];
38299
38535
  newRules[index] = updatedRule;
38300
- onRulesChange(object.id, newRules);
38301
- }, [object.id, object.rules, onRulesChange]);
38536
+ onRulesChange(id, newRules);
38537
+ }, [id, rules, onRulesChange]);
38302
38538
  const handleRuleRemove = useCallback((index) => {
38303
- const newRules = object.rules.filter((_, i) => i !== index);
38304
- onRulesChange(object.id, newRules);
38305
- }, [object.id, object.rules, onRulesChange]);
38539
+ const newRules = rules.filter((_, i) => i !== index);
38540
+ onRulesChange(id, newRules);
38541
+ }, [id, rules, onRulesChange]);
38306
38542
  const handleAddRule = useCallback(() => {
38307
38543
  if (!canAdd || disabled) return;
38308
- const firstEvent = object.availableEvents[0]?.value || "";
38309
- const firstAction = object.availableActions[0]?.value || "";
38544
+ const firstEvent = availableEvents[0]?.value || "";
38545
+ const firstAction = availableActions[0]?.value || "";
38310
38546
  const newRule = {
38311
38547
  id: `rule-${nextRuleId++}`,
38312
38548
  whenEvent: firstEvent,
38313
38549
  thenAction: firstAction
38314
38550
  };
38315
- onRulesChange(object.id, [...object.rules, newRule]);
38316
- }, [canAdd, disabled, object, onRulesChange]);
38551
+ onRulesChange(id, [...rules, newRule]);
38552
+ }, [canAdd, disabled, id, rules, availableEvents, availableActions, onRulesChange]);
38317
38553
  const machine = {
38318
- name: object.name,
38319
- states: object.states,
38320
- currentState: object.currentState,
38321
- transitions: object.rules.map((r) => ({
38322
- from: object.currentState,
38323
- to: object.states.find((s) => s !== object.currentState) || object.currentState,
38554
+ name,
38555
+ states,
38556
+ currentState,
38557
+ transitions: rules.map((r) => ({
38558
+ from: currentState,
38559
+ to: states.find((s) => s !== currentState) || currentState,
38324
38560
  event: r.whenEvent
38325
38561
  }))
38326
38562
  };
38327
38563
  return /* @__PURE__ */ jsxs(VStack, { className: cn("p-4 rounded-lg bg-card border border-border", className), gap: "sm", children: [
38328
38564
  /* @__PURE__ */ jsxs(HStack, { className: "items-center", gap: "sm", children: [
38329
- /* @__PURE__ */ jsx(Typography, { variant: "h5", children: object.icon }),
38565
+ /* @__PURE__ */ jsx(Typography, { variant: "h5", children: icon }),
38330
38566
  /* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
38331
- /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children: object.name }),
38332
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " + object.currentState })
38567
+ /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children: name }),
38568
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " + currentState })
38333
38569
  ] })
38334
38570
  ] }),
38335
38571
  /* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" }),
38336
38572
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
38337
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count: object.rules.length, max: maxRules }) + ":" }),
38338
- object.rules.map((rule, i) => /* @__PURE__ */ jsx(
38573
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count: rules.length, max: maxRules }) + ":" }),
38574
+ rules.map((rule, i) => /* @__PURE__ */ jsx(
38339
38575
  RuleEditor,
38340
38576
  {
38341
38577
  rule,
38342
- availableEvents: object.availableEvents,
38343
- availableActions: object.availableActions,
38578
+ availableEvents,
38579
+ availableActions,
38344
38580
  onChange: (r) => handleRuleChange(i, r),
38345
38581
  onRemove: () => handleRuleRemove(i),
38346
38582
  disabled
@@ -38358,6 +38594,7 @@ var init_ObjectRulePanel = __esm({
38358
38594
  init_cn();
38359
38595
  init_TraitStateViewer();
38360
38596
  init_RuleEditor();
38597
+ init_puzzleObject();
38361
38598
  nextRuleId = 1;
38362
38599
  ObjectRulePanel.displayName = "ObjectRulePanel";
38363
38600
  }
@@ -38424,11 +38661,11 @@ function EventHandlerBoard({
38424
38661
  }) {
38425
38662
  const { emit } = useEventBus();
38426
38663
  const { t } = useTranslate();
38427
- const resolved = Array.isArray(entity) ? entity[0] : entity;
38428
- const entityObjects = resolved?.objects ?? [];
38429
- const [objects, setObjects] = useState(entityObjects);
38664
+ const resolved = boardEntity(entity);
38665
+ const entityObjects = rows(resolved?.objects);
38666
+ const [objects, setObjects] = useState(() => [...entityObjects]);
38430
38667
  const [selectedObjectId, setSelectedObjectId] = useState(
38431
- entityObjects[0]?.id || null
38668
+ entityObjects[0] ? objId(entityObjects[0]) : null
38432
38669
  );
38433
38670
  const [headerError, setHeaderError] = useState(false);
38434
38671
  const [playState, setPlayState] = useState("editing");
@@ -38439,10 +38676,10 @@ function EventHandlerBoard({
38439
38676
  useEffect(() => () => {
38440
38677
  if (timerRef.current) clearTimeout(timerRef.current);
38441
38678
  }, []);
38442
- const selectedObject = objects.find((o) => o.id === selectedObjectId) || null;
38679
+ const selectedObject = objects.find((o) => objId(o) === selectedObjectId) || null;
38443
38680
  const handleRulesChange = useCallback((objectId, rules) => {
38444
38681
  setObjects((prev) => prev.map(
38445
- (o) => o.id === objectId ? { ...o, rules } : o
38682
+ (o) => objId(o) === objectId ? { ...o, rules } : o
38446
38683
  ));
38447
38684
  }, []);
38448
38685
  const addLogEntry = useCallback((icon, message, status = "done") => {
@@ -38456,11 +38693,12 @@ function EventHandlerBoard({
38456
38693
  setEventLog([]);
38457
38694
  const allRules = [];
38458
38695
  objects.forEach((obj) => {
38459
- obj.rules.forEach((rule) => {
38696
+ objRules(obj).forEach((rule) => {
38460
38697
  allRules.push({ object: obj, rule });
38461
38698
  });
38462
38699
  });
38463
- const triggers = resolved?.triggerEvents || [];
38700
+ const triggers = Array.isArray(resolved?.triggerEvents) ? resolved.triggerEvents : [];
38701
+ const goalEvent = str(resolved?.goalEvent);
38464
38702
  const eventQueue = [...triggers];
38465
38703
  const firedEvents = /* @__PURE__ */ new Set();
38466
38704
  let stepIdx = 0;
@@ -38489,14 +38727,14 @@ function EventHandlerBoard({
38489
38727
  addLogEntry("\u26A1", t("eventHandler.noListeners", { event: currentEvent }), "done");
38490
38728
  } else {
38491
38729
  matching.forEach(({ object, rule }) => {
38492
- addLogEntry(object.icon, t("eventHandler.heardEvent", { object: object.name, event: currentEvent, action: rule.thenAction }), "done");
38730
+ addLogEntry(objIcon(object), t("eventHandler.heardEvent", { object: objName(object), event: currentEvent, action: rule.thenAction }), "done");
38493
38731
  eventQueue.push(rule.thenAction);
38494
- if (rule.thenAction === resolved?.goalEvent) {
38732
+ if (rule.thenAction === goalEvent) {
38495
38733
  goalReached = true;
38496
38734
  }
38497
38735
  });
38498
38736
  }
38499
- if (currentEvent === resolved?.goalEvent) {
38737
+ if (currentEvent === goalEvent) {
38500
38738
  goalReached = true;
38501
38739
  }
38502
38740
  stepIdx++;
@@ -38514,65 +38752,75 @@ function EventHandlerBoard({
38514
38752
  }, []);
38515
38753
  const handleReset = useCallback(() => {
38516
38754
  if (timerRef.current) clearTimeout(timerRef.current);
38517
- setObjects(resolved?.objects ?? []);
38755
+ const resetObjects = rows(resolved?.objects);
38756
+ setObjects([...resetObjects]);
38518
38757
  setPlayState("editing");
38519
38758
  setEventLog([]);
38520
- setSelectedObjectId((resolved?.objects ?? [])[0]?.id || null);
38759
+ setSelectedObjectId(resetObjects[0] ? objId(resetObjects[0]) : null);
38521
38760
  setAttempts(0);
38522
38761
  }, [resolved?.objects]);
38523
38762
  if (!resolved) return null;
38524
38763
  const objectViewers = objects.map((obj) => {
38764
+ const states = objStates(obj);
38765
+ const currentState = objCurrentState(obj);
38525
38766
  const machine = {
38526
- name: obj.name,
38527
- states: obj.states,
38528
- currentState: obj.currentState,
38529
- transitions: obj.rules.map((r) => ({
38530
- from: obj.currentState,
38531
- to: obj.states.find((s) => s !== obj.currentState) || obj.currentState,
38767
+ name: objName(obj),
38768
+ states,
38769
+ currentState,
38770
+ transitions: objRules(obj).map((r) => ({
38771
+ from: currentState,
38772
+ to: states.find((s) => s !== currentState) || currentState,
38532
38773
  event: r.whenEvent
38533
38774
  }))
38534
38775
  };
38535
38776
  return { obj, machine };
38536
38777
  });
38537
- const showHint = attempts >= 3 && resolved.hint;
38778
+ const hint = str(resolved.hint);
38779
+ const showHint = attempts >= 3 && hint;
38780
+ const theme = resolved.theme ?? void 0;
38781
+ const themeBackground = theme?.background;
38782
+ const headerImage = str(resolved.headerImage);
38538
38783
  const encourageKey = ENCOURAGEMENT_KEYS[Math.min(attempts - 1, ENCOURAGEMENT_KEYS.length - 1)] ?? ENCOURAGEMENT_KEYS[0];
38539
38784
  return /* @__PURE__ */ jsxs(
38540
38785
  VStack,
38541
38786
  {
38542
38787
  className: cn("p-4 gap-6", className),
38543
38788
  style: {
38544
- backgroundImage: resolved.theme?.background ? `url(${resolved.theme.background})` : void 0,
38789
+ backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
38545
38790
  backgroundSize: "cover",
38546
38791
  backgroundPosition: "center"
38547
38792
  },
38548
38793
  children: [
38549
- resolved.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: resolved.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : resolved.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
38794
+ headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
38550
38795
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
38551
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
38552
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
38796
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
38797
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
38553
38798
  /* @__PURE__ */ jsxs(HStack, { className: "items-center p-2 rounded bg-primary/10 border border-primary/30", gap: "xs", children: [
38554
38799
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-primary font-bold", children: t("game.goal") + ":" }),
38555
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: resolved.goalCondition })
38800
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: str(resolved.goalCondition) })
38556
38801
  ] })
38557
38802
  ] }),
38558
38803
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
38559
38804
  /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.clickObject") + ":" }),
38560
- /* @__PURE__ */ jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) => /* @__PURE__ */ jsx(
38561
- Box,
38562
- {
38563
- className: cn(
38564
- "p-3 rounded-container border-2 cursor-pointer transition-all hover:scale-105",
38565
- selectedObjectId === obj.id ? "border-primary bg-primary/10" : "border-border bg-card hover:border-muted-foreground"
38566
- ),
38567
- onClick: () => setSelectedObjectId(obj.id),
38568
- children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "items-center min-w-[120px]", children: [
38569
- /* @__PURE__ */ jsx(Typography, { variant: "h5", children: obj.icon }),
38570
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground font-medium", children: obj.name }),
38571
- /* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" })
38572
- ] })
38573
- },
38574
- obj.id
38575
- )) })
38805
+ /* @__PURE__ */ jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) => {
38806
+ const oid = objId(obj);
38807
+ return /* @__PURE__ */ jsx(
38808
+ Box,
38809
+ {
38810
+ className: cn(
38811
+ "p-3 rounded-container border-2 cursor-pointer transition-all hover:scale-105",
38812
+ selectedObjectId === oid ? "border-primary bg-primary/10" : "border-border bg-card hover:border-muted-foreground"
38813
+ ),
38814
+ onClick: () => setSelectedObjectId(oid),
38815
+ children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "items-center min-w-[120px]", children: [
38816
+ /* @__PURE__ */ jsx(Typography, { variant: "h5", children: objIcon(obj) }),
38817
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground font-medium", children: objName(obj) }),
38818
+ /* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" })
38819
+ ] })
38820
+ },
38821
+ oid
38822
+ );
38823
+ }) })
38576
38824
  ] }),
38577
38825
  selectedObject && /* @__PURE__ */ jsx(
38578
38826
  ObjectRulePanel,
@@ -38583,12 +38831,12 @@ function EventHandlerBoard({
38583
38831
  }
38584
38832
  ),
38585
38833
  eventLog.length > 0 && /* @__PURE__ */ jsx(EventLog, { entries: eventLog }),
38586
- playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("eventHandler.chainComplete") }) }),
38834
+ playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("eventHandler.chainComplete") }) }),
38587
38835
  playState === "fail" && /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
38588
38836
  /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(encourageKey) }) }),
38589
38837
  showHint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
38590
38838
  /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
38591
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: resolved.hint })
38839
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
38592
38840
  ] }) })
38593
38841
  ] }),
38594
38842
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
@@ -38616,6 +38864,8 @@ var init_EventHandlerBoard = __esm({
38616
38864
  init_TraitStateViewer();
38617
38865
  init_ObjectRulePanel();
38618
38866
  init_EventLog();
38867
+ init_puzzleObject();
38868
+ init_boardEntity();
38619
38869
  ENCOURAGEMENT_KEYS = [
38620
38870
  "puzzle.tryAgain1",
38621
38871
  "puzzle.tryAgain2",
@@ -38704,7 +38954,10 @@ var init_FeatureGridOrganism = __esm({
38704
38954
  );
38705
38955
  useCallback(
38706
38956
  (feature) => {
38707
- eventBus.emit("UI:FEATURE_CLICK", { id: feature.id, href: feature.href ?? "" });
38957
+ eventBus.emit("UI:FEATURE_CLICK", {
38958
+ id: String(feature.id ?? ""),
38959
+ href: String(feature.href ?? "")
38960
+ });
38708
38961
  },
38709
38962
  [eventBus]
38710
38963
  );
@@ -38714,14 +38967,17 @@ var init_FeatureGridOrganism = __esm({
38714
38967
  if (error) {
38715
38968
  return /* @__PURE__ */ jsx(ErrorState, { message: error.message, className });
38716
38969
  }
38717
- const featureCards = items.map((feature) => ({
38718
- icon: feature.icon,
38719
- title: feature.title,
38720
- description: feature.description,
38721
- href: feature.href,
38722
- linkLabel: feature.linkLabel,
38723
- variant: feature.href ? "interactive" : "bordered"
38724
- }));
38970
+ const featureCards = items.map((feature) => {
38971
+ const href = feature.href != null ? String(feature.href) : void 0;
38972
+ return {
38973
+ icon: feature.icon != null ? String(feature.icon) : void 0,
38974
+ title: String(feature.title ?? ""),
38975
+ description: String(feature.description ?? ""),
38976
+ href,
38977
+ linkLabel: feature.linkLabel != null ? String(feature.linkLabel) : void 0,
38978
+ variant: href ? "interactive" : "bordered"
38979
+ };
38980
+ });
38725
38981
  return /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
38726
38982
  (heading || subtitle) && /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
38727
38983
  heading && /* @__PURE__ */ jsx(Typography, { variant: "h2", align: "center", children: heading }),
@@ -38920,12 +39176,12 @@ var init_Form = __esm({
38920
39176
  const isSchemaEntity = isOrbitalEntitySchema(entity);
38921
39177
  const resolvedEntity = isSchemaEntity ? entity : void 0;
38922
39178
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
38923
- const normalizedInitialData = React79__default.useMemo(() => {
39179
+ const normalizedInitialData = React80__default.useMemo(() => {
38924
39180
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
38925
39181
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
38926
39182
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
38927
39183
  }, [entity, initialData]);
38928
- const entityDerivedFields = React79__default.useMemo(() => {
39184
+ const entityDerivedFields = React80__default.useMemo(() => {
38929
39185
  if (fields && fields.length > 0) return void 0;
38930
39186
  if (!resolvedEntity) return void 0;
38931
39187
  return resolvedEntity.fields.map(
@@ -38945,16 +39201,16 @@ var init_Form = __esm({
38945
39201
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
38946
39202
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
38947
39203
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
38948
- const [formData, setFormData] = React79__default.useState(
39204
+ const [formData, setFormData] = React80__default.useState(
38949
39205
  normalizedInitialData
38950
39206
  );
38951
- const [collapsedSections, setCollapsedSections] = React79__default.useState(
39207
+ const [collapsedSections, setCollapsedSections] = React80__default.useState(
38952
39208
  /* @__PURE__ */ new Set()
38953
39209
  );
38954
- const [submitError, setSubmitError] = React79__default.useState(null);
38955
- const formRef = React79__default.useRef(null);
39210
+ const [submitError, setSubmitError] = React80__default.useState(null);
39211
+ const formRef = React80__default.useRef(null);
38956
39212
  const formMode = props.mode;
38957
- const mountedRef = React79__default.useRef(false);
39213
+ const mountedRef = React80__default.useRef(false);
38958
39214
  if (!mountedRef.current) {
38959
39215
  mountedRef.current = true;
38960
39216
  debug("forms", "mount", {
@@ -38967,7 +39223,7 @@ var init_Form = __esm({
38967
39223
  });
38968
39224
  }
38969
39225
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
38970
- const evalContext = React79__default.useMemo(
39226
+ const evalContext = React80__default.useMemo(
38971
39227
  () => ({
38972
39228
  formValues: formData,
38973
39229
  globalVariables: externalContext?.globalVariables ?? {},
@@ -38976,7 +39232,7 @@ var init_Form = __esm({
38976
39232
  }),
38977
39233
  [formData, externalContext]
38978
39234
  );
38979
- React79__default.useEffect(() => {
39235
+ React80__default.useEffect(() => {
38980
39236
  debug("forms", "initialData-sync", {
38981
39237
  mode: formMode,
38982
39238
  normalizedInitialData,
@@ -38987,7 +39243,7 @@ var init_Form = __esm({
38987
39243
  setFormData(normalizedInitialData);
38988
39244
  }
38989
39245
  }, [normalizedInitialData]);
38990
- const processCalculations = React79__default.useCallback(
39246
+ const processCalculations = React80__default.useCallback(
38991
39247
  (changedFieldId, newFormData) => {
38992
39248
  if (!hiddenCalculations.length) return;
38993
39249
  const context = {
@@ -39012,7 +39268,7 @@ var init_Form = __esm({
39012
39268
  },
39013
39269
  [hiddenCalculations, externalContext, eventBus]
39014
39270
  );
39015
- const checkViolations = React79__default.useCallback(
39271
+ const checkViolations = React80__default.useCallback(
39016
39272
  (changedFieldId, newFormData) => {
39017
39273
  if (!violationTriggers.length) return;
39018
39274
  const context = {
@@ -39050,7 +39306,7 @@ var init_Form = __esm({
39050
39306
  processCalculations(name, newFormData);
39051
39307
  checkViolations(name, newFormData);
39052
39308
  };
39053
- const isFieldVisible = React79__default.useCallback(
39309
+ const isFieldVisible = React80__default.useCallback(
39054
39310
  (fieldName) => {
39055
39311
  const condition = conditionalFields[fieldName];
39056
39312
  if (!condition) return true;
@@ -39058,7 +39314,7 @@ var init_Form = __esm({
39058
39314
  },
39059
39315
  [conditionalFields, evalContext]
39060
39316
  );
39061
- const isSectionVisible = React79__default.useCallback(
39317
+ const isSectionVisible = React80__default.useCallback(
39062
39318
  (section) => {
39063
39319
  if (!section.condition) return true;
39064
39320
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -39134,7 +39390,7 @@ var init_Form = __esm({
39134
39390
  eventBus.emit(`UI:${onCancel}`);
39135
39391
  }
39136
39392
  };
39137
- const renderField = React79__default.useCallback(
39393
+ const renderField = React80__default.useCallback(
39138
39394
  (field) => {
39139
39395
  const fieldName = field.name || field.field;
39140
39396
  if (!fieldName) return null;
@@ -39155,7 +39411,7 @@ var init_Form = __esm({
39155
39411
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
39156
39412
  );
39157
39413
  const effectiveFields = entityDerivedFields ?? fields;
39158
- const normalizedFields = React79__default.useMemo(() => {
39414
+ const normalizedFields = React80__default.useMemo(() => {
39159
39415
  if (!effectiveFields || effectiveFields.length === 0) return [];
39160
39416
  return effectiveFields.map((field) => {
39161
39417
  if (typeof field === "string") {
@@ -39178,7 +39434,7 @@ var init_Form = __esm({
39178
39434
  return field;
39179
39435
  });
39180
39436
  }, [effectiveFields, resolvedEntity]);
39181
- const schemaFields = React79__default.useMemo(() => {
39437
+ const schemaFields = React80__default.useMemo(() => {
39182
39438
  if (normalizedFields.length === 0) return null;
39183
39439
  if (isDebugEnabled()) {
39184
39440
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -39188,7 +39444,7 @@ var init_Form = __esm({
39188
39444
  }
39189
39445
  return normalizedFields.map(renderField).filter(Boolean);
39190
39446
  }, [normalizedFields, renderField, entityName, conditionalFields]);
39191
- const sectionElements = React79__default.useMemo(() => {
39447
+ const sectionElements = React80__default.useMemo(() => {
39192
39448
  if (!sections || sections.length === 0) return null;
39193
39449
  return sections.map((section) => {
39194
39450
  if (!isSectionVisible(section)) {
@@ -40046,22 +40302,24 @@ var init_HeroOrganism = __esm({
40046
40302
  () => Array.isArray(entity) ? entity[0] : entity && typeof entity === "object" ? entity : void 0,
40047
40303
  [entity]
40048
40304
  );
40305
+ const primaryAction = resolved?.primaryAction;
40306
+ const secondaryAction = resolved?.secondaryAction;
40049
40307
  const handlePrimaryClick = useCallback(() => {
40050
- if (resolved?.primaryAction) {
40308
+ if (primaryAction) {
40051
40309
  eventBus.emit("UI:CTA_PRIMARY", {
40052
- label: resolved.primaryAction.label,
40053
- href: resolved.primaryAction.href
40310
+ label: String(primaryAction.label ?? ""),
40311
+ href: String(primaryAction.href ?? "")
40054
40312
  });
40055
40313
  }
40056
- }, [eventBus, resolved]);
40314
+ }, [eventBus, primaryAction]);
40057
40315
  const handleSecondaryClick = useCallback(() => {
40058
- if (resolved?.secondaryAction) {
40316
+ if (secondaryAction) {
40059
40317
  eventBus.emit("UI:CTA_SECONDARY", {
40060
- label: resolved.secondaryAction.label,
40061
- href: resolved.secondaryAction.href
40318
+ label: String(secondaryAction.label ?? ""),
40319
+ href: String(secondaryAction.href ?? "")
40062
40320
  });
40063
40321
  }
40064
- }, [eventBus, resolved]);
40322
+ }, [eventBus, secondaryAction]);
40065
40323
  if (isLoading) {
40066
40324
  return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
40067
40325
  }
@@ -40071,17 +40329,19 @@ var init_HeroOrganism = __esm({
40071
40329
  if (!resolved) {
40072
40330
  return null;
40073
40331
  }
40332
+ const imageRaw = resolved.image;
40333
+ const image = imageRaw ? { src: String(imageRaw.src ?? ""), alt: String(imageRaw.alt ?? "") } : void 0;
40074
40334
  return /* @__PURE__ */ jsxs(
40075
40335
  HeroSection,
40076
40336
  {
40077
- tag: resolved.tag,
40078
- title: resolved.title,
40079
- titleAccent: resolved.titleAccent,
40080
- subtitle: resolved.subtitle,
40081
- primaryAction: resolved.primaryAction ? { label: resolved.primaryAction.label, href: resolved.primaryAction.href } : void 0,
40082
- secondaryAction: resolved.secondaryAction ? { label: resolved.secondaryAction.label, href: resolved.secondaryAction.href } : void 0,
40083
- installCommand: resolved.installCommand,
40084
- image: resolved.image,
40337
+ tag: resolved.tag != null ? String(resolved.tag) : void 0,
40338
+ title: String(resolved.title ?? ""),
40339
+ titleAccent: resolved.titleAccent != null ? String(resolved.titleAccent) : void 0,
40340
+ subtitle: String(resolved.subtitle ?? ""),
40341
+ primaryAction: primaryAction ? { label: String(primaryAction.label ?? ""), href: String(primaryAction.href ?? "") } : void 0,
40342
+ secondaryAction: secondaryAction ? { label: String(secondaryAction.label ?? ""), href: String(secondaryAction.href ?? "") } : void 0,
40343
+ installCommand: resolved.installCommand != null ? String(resolved.installCommand) : void 0,
40344
+ image,
40085
40345
  imagePosition: resolved.imagePosition,
40086
40346
  background: resolved.background,
40087
40347
  className: cn(className),
@@ -40090,8 +40350,8 @@ var init_HeroOrganism = __esm({
40090
40350
  /* @__PURE__ */ jsx(
40091
40351
  _HeroClickInterceptor,
40092
40352
  {
40093
- hasPrimary: !!resolved.primaryAction,
40094
- hasSecondary: !!resolved.secondaryAction,
40353
+ hasPrimary: !!primaryAction,
40354
+ hasSecondary: !!secondaryAction,
40095
40355
  onPrimaryClick: handlePrimaryClick,
40096
40356
  onSecondaryClick: handleSecondaryClick
40097
40357
  }
@@ -40320,7 +40580,7 @@ function formatValue3(value, fieldName) {
40320
40580
  return String(value);
40321
40581
  }
40322
40582
  function formatFieldLabel2(fieldName) {
40323
- return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).replace(/Id$/, "").trim();
40583
+ return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase()).replace(/Id$/, "").trim();
40324
40584
  }
40325
40585
  var STATUS_STYLES2, StatusBadge, ProgressIndicator, List3;
40326
40586
  var init_List = __esm({
@@ -40466,7 +40726,7 @@ var init_List = __esm({
40466
40726
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
40467
40727
  return [];
40468
40728
  }, [entity]);
40469
- const getItemActions = React79__default.useCallback(
40729
+ const getItemActions = React80__default.useCallback(
40470
40730
  (item) => {
40471
40731
  if (!itemActions) return [];
40472
40732
  if (typeof itemActions === "function") {
@@ -40942,7 +41202,7 @@ var init_MediaGallery = __esm({
40942
41202
  [selectable, selectedItems, selectionEvent, eventBus]
40943
41203
  );
40944
41204
  const entityData = Array.isArray(entity) ? entity : [];
40945
- const items = React79__default.useMemo(() => {
41205
+ const items = React80__default.useMemo(() => {
40946
41206
  if (propItems) return propItems;
40947
41207
  if (entityData.length === 0) return [];
40948
41208
  return entityData.map((record, idx) => ({
@@ -41112,9 +41372,9 @@ function MiniMap({
41112
41372
  viewportRect,
41113
41373
  className
41114
41374
  }) {
41115
- const canvasRef = React79.useRef(null);
41116
- const frameRef = React79.useRef(0);
41117
- React79.useEffect(() => {
41375
+ const canvasRef = React80.useRef(null);
41376
+ const frameRef = React80.useRef(0);
41377
+ React80.useEffect(() => {
41118
41378
  const canvas = canvasRef.current;
41119
41379
  if (!canvas) return;
41120
41380
  const ctx = canvas.getContext("2d");
@@ -41196,7 +41456,7 @@ var init_MiniMap = __esm({
41196
41456
  }
41197
41457
  });
41198
41458
  function extractTitle2(children) {
41199
- if (!React79__default.isValidElement(children)) return void 0;
41459
+ if (!React80__default.isValidElement(children)) return void 0;
41200
41460
  const props = children.props;
41201
41461
  if (typeof props.title === "string") {
41202
41462
  return props.title;
@@ -41260,20 +41520,22 @@ function NegotiatorBoard({
41260
41520
  }) {
41261
41521
  const { emit } = useEventBus();
41262
41522
  const { t } = useTranslate();
41263
- const resolved = Array.isArray(entity) ? entity[0] : entity;
41523
+ const resolved = boardEntity(entity);
41264
41524
  const [history, setHistory] = useState([]);
41265
41525
  const [headerError, setHeaderError] = useState(false);
41266
41526
  const [showHint, setShowHint] = useState(false);
41527
+ const totalRounds = num(resolved?.totalRounds);
41528
+ const targetScore = num(resolved?.targetScore);
41267
41529
  const currentRound = history.length;
41268
- const isComplete = currentRound >= (resolved?.totalRounds ?? 0);
41530
+ const isComplete = currentRound >= totalRounds;
41269
41531
  const playerTotal = history.reduce((s, r) => s + r.playerPayoff, 0);
41270
41532
  const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
41271
- const won = isComplete && playerTotal >= (resolved?.targetScore ?? 0);
41272
- const actions = resolved?.actions ?? [];
41273
- const payoffMatrix = resolved?.payoffMatrix ?? [];
41533
+ const won = isComplete && playerTotal >= targetScore;
41534
+ const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
41535
+ const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
41274
41536
  const handleAction = useCallback((actionId) => {
41275
41537
  if (isComplete) return;
41276
- const opponentAction = getOpponentAction(resolved?.opponentStrategy ?? "random", actions, history);
41538
+ const opponentAction = getOpponentAction(str(resolved?.opponentStrategy) || "random", actions, history);
41277
41539
  const payoff = payoffMatrix.find(
41278
41540
  (p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
41279
41541
  );
@@ -41286,42 +41548,46 @@ function NegotiatorBoard({
41286
41548
  };
41287
41549
  const newHistory = [...history, result];
41288
41550
  setHistory(newHistory);
41289
- if (newHistory.length >= (resolved?.totalRounds ?? 0)) {
41551
+ if (newHistory.length >= totalRounds) {
41290
41552
  const total = newHistory.reduce((s, r) => s + r.playerPayoff, 0);
41291
- if (total >= (resolved?.targetScore ?? 0)) {
41553
+ if (total >= targetScore) {
41292
41554
  emit(`UI:${completeEvent}`, { success: true, score: total });
41293
41555
  }
41294
- if (newHistory.length >= 3 && resolved?.hint) {
41556
+ if (newHistory.length >= 3 && str(resolved?.hint)) {
41295
41557
  setShowHint(true);
41296
41558
  }
41297
41559
  }
41298
- }, [isComplete, resolved, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
41560
+ }, [isComplete, resolved, totalRounds, targetScore, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
41299
41561
  const handleReset = () => {
41300
41562
  setHistory([]);
41301
41563
  setShowHint(false);
41302
41564
  };
41303
41565
  const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
41304
41566
  if (!resolved) return null;
41567
+ const theme = resolved.theme ?? void 0;
41568
+ const themeBackground = theme?.background;
41569
+ const headerImage = str(resolved.headerImage);
41570
+ const hint = str(resolved.hint);
41305
41571
  return /* @__PURE__ */ jsx(
41306
41572
  Box,
41307
41573
  {
41308
41574
  className,
41309
41575
  style: {
41310
- backgroundImage: resolved.theme?.background ? `url(${resolved.theme.background})` : void 0,
41576
+ backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
41311
41577
  backgroundSize: "cover",
41312
41578
  backgroundPosition: "center"
41313
41579
  },
41314
41580
  children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
41315
- resolved.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: resolved.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : resolved.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
41581
+ headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
41316
41582
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
41317
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
41318
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.description }),
41583
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
41584
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: str(resolved.description) }),
41319
41585
  /* @__PURE__ */ jsxs(HStack, { gap: "md", children: [
41320
- /* @__PURE__ */ jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(resolved.totalRounds) }) }),
41586
+ /* @__PURE__ */ jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(totalRounds) }) }),
41321
41587
  /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
41322
41588
  t("negotiator.target"),
41323
41589
  ": ",
41324
- resolved.targetScore
41590
+ targetScore
41325
41591
  ] })
41326
41592
  ] })
41327
41593
  ] }) }),
@@ -41370,16 +41636,16 @@ function NegotiatorBoard({
41370
41636
  ] }) }),
41371
41637
  isComplete && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
41372
41638
  /* @__PURE__ */ jsx(Icon, { icon: CheckCircle, size: "lg", className: won ? "text-success" : "text-error" }),
41373
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: won ? resolved.successMessage ?? t("negotiator.success") : resolved.failMessage ?? t("negotiator.failed") }),
41639
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: won ? str(resolved.successMessage) || t("negotiator.success") : str(resolved.failMessage) || t("negotiator.failed") }),
41374
41640
  /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
41375
41641
  t("negotiator.finalScore"),
41376
41642
  ": ",
41377
41643
  playerTotal,
41378
41644
  "/",
41379
- resolved.targetScore
41645
+ targetScore
41380
41646
  ] })
41381
41647
  ] }) }),
41382
- showHint && resolved.hint && !won && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.hint }) }),
41648
+ showHint && hint && !won && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
41383
41649
  isComplete && !won && /* @__PURE__ */ jsx(HStack, { justify: "center", children: /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("negotiator.playAgain") }) })
41384
41650
  ] })
41385
41651
  }
@@ -41389,6 +41655,7 @@ var init_NegotiatorBoard = __esm({
41389
41655
  "components/game/organisms/puzzles/negotiator/NegotiatorBoard.tsx"() {
41390
41656
  init_atoms2();
41391
41657
  init_useEventBus();
41658
+ init_boardEntity();
41392
41659
  NegotiatorBoard.displayName = "NegotiatorBoard";
41393
41660
  }
41394
41661
  });
@@ -41424,13 +41691,13 @@ var init_PricingOrganism = __esm({
41424
41691
  return /* @__PURE__ */ jsx(ErrorState, { message: error.message, className });
41425
41692
  }
41426
41693
  const plans = items.map((plan) => ({
41427
- name: plan.name,
41428
- price: plan.price,
41429
- description: plan.description,
41430
- features: plan.features,
41431
- action: { label: plan.actionLabel, href: plan.actionHref },
41432
- highlighted: plan.highlighted,
41433
- badge: plan.badge
41694
+ name: String(plan.name ?? ""),
41695
+ price: String(plan.price ?? ""),
41696
+ description: plan.description != null ? String(plan.description) : void 0,
41697
+ features: (plan.features ?? []).map((f3) => String(f3)),
41698
+ action: { label: String(plan.actionLabel ?? ""), href: String(plan.actionHref ?? "") },
41699
+ highlighted: Boolean(plan.highlighted),
41700
+ badge: plan.badge != null ? String(plan.badge) : void 0
41434
41701
  }));
41435
41702
  return /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
41436
41703
  (heading || subtitle) && /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
@@ -41646,7 +41913,7 @@ var init_debugRegistry = __esm({
41646
41913
  }
41647
41914
  });
41648
41915
  function useDebugData() {
41649
- const [data, setData] = React79.useState(() => ({
41916
+ const [data, setData] = React80.useState(() => ({
41650
41917
  traits: [],
41651
41918
  ticks: [],
41652
41919
  guards: [],
@@ -41660,7 +41927,7 @@ function useDebugData() {
41660
41927
  },
41661
41928
  lastUpdate: Date.now()
41662
41929
  }));
41663
- React79.useEffect(() => {
41930
+ React80.useEffect(() => {
41664
41931
  const updateData = () => {
41665
41932
  setData({
41666
41933
  traits: getAllTraits(),
@@ -41769,12 +42036,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
41769
42036
  return positions;
41770
42037
  }
41771
42038
  function WalkMinimap() {
41772
- const [walkStep, setWalkStep] = React79.useState(null);
41773
- const [traits2, setTraits] = React79.useState([]);
41774
- const [coveredEdges, setCoveredEdges] = React79.useState([]);
41775
- const [completedTraits, setCompletedTraits] = React79.useState(/* @__PURE__ */ new Set());
41776
- const prevTraitRef = React79.useRef(null);
41777
- React79.useEffect(() => {
42039
+ const [walkStep, setWalkStep] = React80.useState(null);
42040
+ const [traits2, setTraits] = React80.useState([]);
42041
+ const [coveredEdges, setCoveredEdges] = React80.useState([]);
42042
+ const [completedTraits, setCompletedTraits] = React80.useState(/* @__PURE__ */ new Set());
42043
+ const prevTraitRef = React80.useRef(null);
42044
+ React80.useEffect(() => {
41778
42045
  const interval = setInterval(() => {
41779
42046
  const w = window;
41780
42047
  const step = w.__orbitalWalkStep;
@@ -42210,15 +42477,15 @@ var init_EntitiesTab = __esm({
42210
42477
  });
42211
42478
  function EventFlowTab({ events: events2 }) {
42212
42479
  const { t } = useTranslate();
42213
- const [filter, setFilter] = React79.useState("all");
42214
- const containerRef = React79.useRef(null);
42215
- const [autoScroll, setAutoScroll] = React79.useState(true);
42216
- React79.useEffect(() => {
42480
+ const [filter, setFilter] = React80.useState("all");
42481
+ const containerRef = React80.useRef(null);
42482
+ const [autoScroll, setAutoScroll] = React80.useState(true);
42483
+ React80.useEffect(() => {
42217
42484
  if (autoScroll && containerRef.current) {
42218
42485
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
42219
42486
  }
42220
42487
  }, [events2.length, autoScroll]);
42221
- const filteredEvents = React79.useMemo(() => {
42488
+ const filteredEvents = React80.useMemo(() => {
42222
42489
  if (filter === "all") return events2;
42223
42490
  return events2.filter((e) => e.type === filter);
42224
42491
  }, [events2, filter]);
@@ -42334,7 +42601,7 @@ var init_EventFlowTab = __esm({
42334
42601
  });
42335
42602
  function GuardsPanel({ guards }) {
42336
42603
  const { t } = useTranslate();
42337
- const [filter, setFilter] = React79.useState("all");
42604
+ const [filter, setFilter] = React80.useState("all");
42338
42605
  if (guards.length === 0) {
42339
42606
  return /* @__PURE__ */ jsx(
42340
42607
  EmptyState,
@@ -42347,7 +42614,7 @@ function GuardsPanel({ guards }) {
42347
42614
  }
42348
42615
  const passedCount = guards.filter((g) => g.result).length;
42349
42616
  const failedCount = guards.length - passedCount;
42350
- const filteredGuards = React79.useMemo(() => {
42617
+ const filteredGuards = React80.useMemo(() => {
42351
42618
  if (filter === "all") return guards;
42352
42619
  if (filter === "passed") return guards.filter((g) => g.result);
42353
42620
  return guards.filter((g) => !g.result);
@@ -42510,10 +42777,10 @@ function EffectBadge({ effect }) {
42510
42777
  }
42511
42778
  function TransitionTimeline({ transitions }) {
42512
42779
  const { t } = useTranslate();
42513
- const containerRef = React79.useRef(null);
42514
- const [autoScroll, setAutoScroll] = React79.useState(true);
42515
- const [expandedId, setExpandedId] = React79.useState(null);
42516
- React79.useEffect(() => {
42780
+ const containerRef = React80.useRef(null);
42781
+ const [autoScroll, setAutoScroll] = React80.useState(true);
42782
+ const [expandedId, setExpandedId] = React80.useState(null);
42783
+ React80.useEffect(() => {
42517
42784
  if (autoScroll && containerRef.current) {
42518
42785
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
42519
42786
  }
@@ -42793,9 +43060,9 @@ function getAllEvents(traits2) {
42793
43060
  function EventDispatcherTab({ traits: traits2, schema }) {
42794
43061
  const eventBus = useEventBus();
42795
43062
  const { t } = useTranslate();
42796
- const [log8, setLog] = React79.useState([]);
42797
- const prevStatesRef = React79.useRef(/* @__PURE__ */ new Map());
42798
- React79.useEffect(() => {
43063
+ const [log8, setLog] = React80.useState([]);
43064
+ const prevStatesRef = React80.useRef(/* @__PURE__ */ new Map());
43065
+ React80.useEffect(() => {
42799
43066
  for (const trait of traits2) {
42800
43067
  const prev = prevStatesRef.current.get(trait.id);
42801
43068
  if (prev && prev !== trait.currentState) {
@@ -42964,10 +43231,10 @@ function VerifyModePanel({
42964
43231
  localCount
42965
43232
  }) {
42966
43233
  const { t } = useTranslate();
42967
- const [expanded, setExpanded] = React79.useState(true);
42968
- const scrollRef = React79.useRef(null);
42969
- const prevCountRef = React79.useRef(0);
42970
- React79.useEffect(() => {
43234
+ const [expanded, setExpanded] = React80.useState(true);
43235
+ const scrollRef = React80.useRef(null);
43236
+ const prevCountRef = React80.useRef(0);
43237
+ React80.useEffect(() => {
42971
43238
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
42972
43239
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
42973
43240
  }
@@ -43024,10 +43291,10 @@ function RuntimeDebugger({
43024
43291
  schema
43025
43292
  }) {
43026
43293
  const { t } = useTranslate();
43027
- const [isCollapsed, setIsCollapsed] = React79.useState(mode === "verify" ? true : defaultCollapsed);
43028
- const [isVisible, setIsVisible] = React79.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
43294
+ const [isCollapsed, setIsCollapsed] = React80.useState(mode === "verify" ? true : defaultCollapsed);
43295
+ const [isVisible, setIsVisible] = React80.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
43029
43296
  const debugData = useDebugData();
43030
- React79.useEffect(() => {
43297
+ React80.useEffect(() => {
43031
43298
  if (mode === "inline") return;
43032
43299
  return onDebugToggle((enabled) => {
43033
43300
  setIsVisible(enabled);
@@ -43036,7 +43303,7 @@ function RuntimeDebugger({
43036
43303
  }
43037
43304
  });
43038
43305
  }, [mode]);
43039
- React79.useEffect(() => {
43306
+ React80.useEffect(() => {
43040
43307
  if (mode === "inline") return;
43041
43308
  const handleKeyDown = (e) => {
43042
43309
  if (e.key === "`" && isVisible) {
@@ -43485,7 +43752,7 @@ function SequenceBar({
43485
43752
  onSlotRemove(index);
43486
43753
  }, [onSlotRemove, playing]);
43487
43754
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
43488
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React79__default.Fragment, { children: [
43755
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React80__default.Fragment, { children: [
43489
43756
  i > 0 && /* @__PURE__ */ jsx(
43490
43757
  Typography,
43491
43758
  {
@@ -43546,16 +43813,20 @@ function SequencerBoard({
43546
43813
  }) {
43547
43814
  const { emit } = useEventBus();
43548
43815
  const { t } = useTranslate();
43549
- const resolved = Array.isArray(entity) ? entity[0] : entity;
43816
+ const resolved = boardEntity(entity);
43817
+ const maxSlots = num(resolved?.maxSlots);
43818
+ const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
43819
+ const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
43820
+ const allowDuplicates = resolved?.allowDuplicates !== false;
43550
43821
  const [headerError, setHeaderError] = useState(false);
43551
43822
  const [slots, setSlots] = useState(
43552
- () => Array.from({ length: resolved?.maxSlots ?? 0 }, () => void 0)
43823
+ () => Array.from({ length: maxSlots }, () => void 0)
43553
43824
  );
43554
43825
  const [playState, setPlayState] = useState("idle");
43555
43826
  const [currentStep, setCurrentStep] = useState(-1);
43556
43827
  const [attempts, setAttempts] = useState(0);
43557
43828
  const [slotFeedback, setSlotFeedback] = useState(
43558
- () => Array.from({ length: resolved?.maxSlots ?? 0 }, () => null)
43829
+ () => Array.from({ length: maxSlots }, () => null)
43559
43830
  );
43560
43831
  const timerRef = useRef(null);
43561
43832
  useEffect(() => () => {
@@ -43589,17 +43860,17 @@ function SequencerBoard({
43589
43860
  }, [emit]);
43590
43861
  const handleReset = useCallback(() => {
43591
43862
  if (timerRef.current) clearTimeout(timerRef.current);
43592
- setSlots(Array.from({ length: resolved?.maxSlots ?? 0 }, () => void 0));
43863
+ setSlots(Array.from({ length: maxSlots }, () => void 0));
43593
43864
  setPlayState("idle");
43594
43865
  setCurrentStep(-1);
43595
43866
  setAttempts(0);
43596
- setSlotFeedback(Array.from({ length: resolved?.maxSlots ?? 0 }, () => null));
43597
- }, [resolved?.maxSlots]);
43867
+ setSlotFeedback(Array.from({ length: maxSlots }, () => null));
43868
+ }, [maxSlots]);
43598
43869
  const filledSlots = slots.filter((s) => !!s);
43599
43870
  const canPlay = filledSlots.length > 0 && playState === "idle";
43600
43871
  const handlePlay = useCallback(() => {
43601
43872
  if (!canPlay) return;
43602
- setSlotFeedback(Array.from({ length: resolved?.maxSlots ?? 0 }, () => null));
43873
+ setSlotFeedback(Array.from({ length: maxSlots }, () => null));
43603
43874
  emit("UI:PLAY_SOUND", { key: "confirm" });
43604
43875
  const sequence = slots.map((s) => s?.id || "");
43605
43876
  if (playEvent) {
@@ -43610,10 +43881,10 @@ function SequencerBoard({
43610
43881
  let step = 0;
43611
43882
  const advance = () => {
43612
43883
  step++;
43613
- if (step >= (resolved?.maxSlots ?? 0)) {
43884
+ if (step >= maxSlots) {
43614
43885
  const playerSeq = slots.map((s) => s?.id);
43615
43886
  const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
43616
- const success = (resolved?.solutions ?? []).some(
43887
+ const success = solutions.some(
43617
43888
  (sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
43618
43889
  );
43619
43890
  if (success) {
@@ -43625,7 +43896,7 @@ function SequencerBoard({
43625
43896
  }
43626
43897
  } else {
43627
43898
  setAttempts((prev) => prev + 1);
43628
- const feedback = computeSlotFeedback(playerSeq, resolved?.solutions ?? []);
43899
+ const feedback = computeSlotFeedback(playerSeq, solutions);
43629
43900
  setSlotFeedback(feedback);
43630
43901
  setPlayState("idle");
43631
43902
  setCurrentStep(-1);
@@ -43643,10 +43914,10 @@ function SequencerBoard({
43643
43914
  }
43644
43915
  };
43645
43916
  timerRef.current = setTimeout(advance, stepDurationMs);
43646
- }, [canPlay, slots, resolved?.maxSlots, resolved?.solutions, stepDurationMs, playEvent, completeEvent, emit]);
43917
+ }, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, emit]);
43647
43918
  const machine = {
43648
- name: resolved?.title ?? "",
43649
- description: resolved?.description ?? "",
43919
+ name: str(resolved?.title),
43920
+ description: str(resolved?.description),
43650
43921
  states: slots.map((s, i) => stepLabel(s, i)),
43651
43922
  currentState: currentStep >= 0 ? stepLabel(slots[currentStep], currentStep) : "__idle__",
43652
43923
  transitions: slots.slice(0, -1).map((s, i) => ({
@@ -43655,37 +43926,41 @@ function SequencerBoard({
43655
43926
  event: "NEXT"
43656
43927
  }))
43657
43928
  };
43658
- const usedIds = resolved?.allowDuplicates === false ? slots.filter(Boolean).map((s) => s?.id || "") : [];
43659
- const showHint = attempts >= 3 && !!resolved?.hint;
43929
+ const usedIds = !allowDuplicates ? slots.filter(Boolean).map((s) => s?.id || "") : [];
43930
+ const hint = str(resolved?.hint);
43931
+ const showHint = attempts >= 3 && !!hint;
43660
43932
  const hasFeedback = slotFeedback.some((f3) => f3 !== null);
43661
43933
  const correctCount = slotFeedback.filter((f3) => f3 === "correct").length;
43662
43934
  const encourageKey = ENCOURAGEMENT_KEYS2[Math.min(attempts - 1, ENCOURAGEMENT_KEYS2.length - 1)] ?? ENCOURAGEMENT_KEYS2[0];
43663
43935
  if (!resolved) return null;
43936
+ const theme = resolved.theme ?? void 0;
43937
+ const themeBackground = theme?.background;
43938
+ const headerImage = str(resolved.headerImage);
43664
43939
  return /* @__PURE__ */ jsxs(
43665
43940
  VStack,
43666
43941
  {
43667
43942
  className: cn("p-4 gap-6", className),
43668
43943
  style: {
43669
- backgroundImage: resolved.theme?.background ? `url(${resolved.theme.background})` : void 0,
43944
+ backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
43670
43945
  backgroundSize: "cover",
43671
43946
  backgroundPosition: "center"
43672
43947
  },
43673
43948
  children: [
43674
- resolved.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: resolved.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : resolved.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
43949
+ headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
43675
43950
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
43676
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
43677
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description })
43951
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
43952
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) })
43678
43953
  ] }),
43679
43954
  showHint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
43680
43955
  /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
43681
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: resolved.hint })
43956
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
43682
43957
  ] }) }),
43683
43958
  filledSlots.length > 0 && /* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "linear", size: "md" }),
43684
43959
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
43685
43960
  /* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between", children: [
43686
43961
  /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("sequencer.yourSequence") + ":" }),
43687
43962
  hasFeedback && playState === "idle" && /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
43688
- `${correctCount}/${resolved.maxSlots} `,
43963
+ `${correctCount}/${maxSlots} `,
43689
43964
  "\u2705"
43690
43965
  ] })
43691
43966
  ] }),
@@ -43693,7 +43968,7 @@ function SequencerBoard({
43693
43968
  SequenceBar,
43694
43969
  {
43695
43970
  slots,
43696
- maxSlots: resolved.maxSlots,
43971
+ maxSlots,
43697
43972
  onSlotDrop: handleSlotDrop,
43698
43973
  onSlotRemove: handleSlotRemove,
43699
43974
  playing: playState === "playing",
@@ -43707,15 +43982,15 @@ function SequencerBoard({
43707
43982
  playState !== "playing" && /* @__PURE__ */ jsx(
43708
43983
  ActionPalette,
43709
43984
  {
43710
- actions: resolved.availableActions,
43985
+ actions: availableActions,
43711
43986
  usedActionIds: usedIds,
43712
- allowDuplicates: resolved.allowDuplicates !== false,
43987
+ allowDuplicates,
43713
43988
  categoryColors,
43714
43989
  label: t("sequencer.dragActions")
43715
43990
  }
43716
43991
  ),
43717
43992
  hasFeedback && playState === "idle" && attempts > 0 && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: t(encourageKey) }) }),
43718
- playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("sequencer.levelComplete") }) }),
43993
+ playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("sequencer.levelComplete") }) }),
43719
43994
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
43720
43995
  /* @__PURE__ */ jsx(
43721
43996
  Button,
@@ -43739,6 +44014,7 @@ var init_SequencerBoard = __esm({
43739
44014
  init_cn();
43740
44015
  init_useEventBus();
43741
44016
  init_TraitStateViewer();
44017
+ init_boardEntity();
43742
44018
  init_SequenceBar();
43743
44019
  init_ActionPalette();
43744
44020
  ENCOURAGEMENT_KEYS2 = [
@@ -43788,18 +44064,21 @@ var init_ShowcaseOrganism = __esm({
43788
44064
  heading && /* @__PURE__ */ jsx(Typography, { variant: "h2", align: "center", children: heading }),
43789
44065
  subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body1", color: "muted", align: "center", className: "max-w-2xl", children: subtitle })
43790
44066
  ] }),
43791
- /* @__PURE__ */ jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) => /* @__PURE__ */ jsx(
43792
- ShowcaseCard,
43793
- {
43794
- title: item.title,
43795
- description: item.description,
43796
- image: item.image,
43797
- href: item.href,
43798
- badge: item.badge,
43799
- accentColor: item.accentColor
43800
- },
43801
- item.id
43802
- )) })
44067
+ /* @__PURE__ */ jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) => {
44068
+ const imageRaw = item.image;
44069
+ return /* @__PURE__ */ jsx(
44070
+ ShowcaseCard,
44071
+ {
44072
+ title: String(item.title ?? ""),
44073
+ description: item.description != null ? String(item.description) : void 0,
44074
+ image: { src: String(imageRaw?.src ?? ""), alt: String(imageRaw?.alt ?? "") },
44075
+ href: item.href != null ? String(item.href) : void 0,
44076
+ badge: item.badge != null ? String(item.badge) : void 0,
44077
+ accentColor: item.accentColor != null ? String(item.accentColor) : void 0
44078
+ },
44079
+ String(item.id ?? "")
44080
+ );
44081
+ }) })
43803
44082
  ] });
43804
44083
  };
43805
44084
  ShowcaseOrganism.displayName = "ShowcaseOrganism";
@@ -44167,8 +44446,8 @@ function SimulatorBoard({
44167
44446
  }) {
44168
44447
  const { emit } = useEventBus();
44169
44448
  const { t } = useTranslate();
44170
- const resolved = Array.isArray(entity) ? entity[0] : entity;
44171
- const parameters = resolved?.parameters ?? [];
44449
+ const resolved = boardEntity(entity);
44450
+ const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
44172
44451
  const [values, setValues] = useState(() => {
44173
44452
  const init = {};
44174
44453
  for (const p2 of parameters) {
@@ -44182,15 +44461,15 @@ function SimulatorBoard({
44182
44461
  const [showHint, setShowHint] = useState(false);
44183
44462
  const computeOutput = useCallback((params) => {
44184
44463
  try {
44185
- const fn = new Function("params", `return (${resolved?.computeExpression})`);
44464
+ const fn = new Function("params", `return (${str(resolved?.computeExpression)})`);
44186
44465
  return fn(params);
44187
44466
  } catch {
44188
44467
  return 0;
44189
44468
  }
44190
44469
  }, [resolved?.computeExpression]);
44191
44470
  const output = useMemo(() => computeOutput(values) ?? 0, [computeOutput, values]);
44192
- const targetValue = resolved?.targetValue ?? 0;
44193
- const targetTolerance = resolved?.targetTolerance ?? 0;
44471
+ const targetValue = num(resolved?.targetValue);
44472
+ const targetTolerance = num(resolved?.targetTolerance);
44194
44473
  const isCorrect = Math.abs(output - targetValue) <= targetTolerance;
44195
44474
  const handleParameterChange = (id, value) => {
44196
44475
  if (submitted) return;
@@ -44205,7 +44484,7 @@ function SimulatorBoard({
44205
44484
  };
44206
44485
  const handleReset = () => {
44207
44486
  setSubmitted(false);
44208
- if (attempts >= 2 && resolved?.hint) {
44487
+ if (attempts >= 2 && str(resolved?.hint)) {
44209
44488
  setShowHint(true);
44210
44489
  }
44211
44490
  };
@@ -44220,20 +44499,26 @@ function SimulatorBoard({
44220
44499
  setShowHint(false);
44221
44500
  };
44222
44501
  if (!resolved) return null;
44502
+ const theme = resolved.theme ?? void 0;
44503
+ const themeBackground = theme?.background;
44504
+ const headerImage = str(resolved.headerImage);
44505
+ const hint = str(resolved.hint);
44506
+ const outputLabel = str(resolved.outputLabel);
44507
+ const outputUnit = str(resolved.outputUnit);
44223
44508
  return /* @__PURE__ */ jsx(
44224
44509
  Box,
44225
44510
  {
44226
44511
  className,
44227
44512
  style: {
44228
- backgroundImage: resolved.theme?.background ? `url(${resolved.theme.background})` : void 0,
44513
+ backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
44229
44514
  backgroundSize: "cover",
44230
44515
  backgroundPosition: "center"
44231
44516
  },
44232
44517
  children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
44233
- resolved.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: resolved.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : resolved.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
44518
+ headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
44234
44519
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
44235
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
44236
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.description })
44520
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
44521
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: str(resolved.description) })
44237
44522
  ] }) }),
44238
44523
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
44239
44524
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
@@ -44274,28 +44559,28 @@ function SimulatorBoard({
44274
44559
  ] }, param.id))
44275
44560
  ] }) }),
44276
44561
  /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
44277
- /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: resolved.outputLabel }),
44562
+ /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
44278
44563
  /* @__PURE__ */ jsxs(Typography, { variant: "h3", weight: "bold", children: [
44279
44564
  output.toFixed(2),
44280
44565
  " ",
44281
- resolved.outputUnit
44566
+ outputUnit
44282
44567
  ] }),
44283
44568
  submitted && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
44284
44569
  /* @__PURE__ */ jsx(Icon, { icon: isCorrect ? CheckCircle : XCircle, size: "sm", className: isCorrect ? "text-success" : "text-error" }),
44285
- /* @__PURE__ */ jsx(Typography, { variant: "body", className: isCorrect ? "text-success" : "text-error", children: isCorrect ? resolved.successMessage ?? t("simulator.correct") : resolved.failMessage ?? t("simulator.incorrect") })
44570
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: isCorrect ? "text-success" : "text-error", children: isCorrect ? str(resolved.successMessage) || t("simulator.correct") : str(resolved.failMessage) || t("simulator.incorrect") })
44286
44571
  ] }),
44287
44572
  /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
44288
44573
  t("simulator.target"),
44289
44574
  ": ",
44290
44575
  targetValue,
44291
44576
  " ",
44292
- resolved.outputUnit,
44577
+ outputUnit,
44293
44578
  " (\xB1",
44294
44579
  targetTolerance,
44295
44580
  ")"
44296
44581
  ] })
44297
44582
  ] }) }),
44298
- showHint && resolved.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.hint }) }),
44583
+ showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
44299
44584
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
44300
44585
  !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, children: [
44301
44586
  /* @__PURE__ */ jsx(Icon, { icon: Play, size: "sm" }),
@@ -44314,6 +44599,7 @@ var init_SimulatorBoard = __esm({
44314
44599
  "components/game/organisms/puzzles/simulator/SimulatorBoard.tsx"() {
44315
44600
  init_atoms2();
44316
44601
  init_useEventBus();
44602
+ init_boardEntity();
44317
44603
  SimulatorBoard.displayName = "SimulatorBoard";
44318
44604
  }
44319
44605
  });
@@ -44556,7 +44842,7 @@ var init_StatCard = __esm({
44556
44842
  const labelToUse = propLabel ?? propTitle;
44557
44843
  const eventBus = useEventBus();
44558
44844
  const { t } = useTranslate();
44559
- const handleActionClick = React79__default.useCallback(() => {
44845
+ const handleActionClick = React80__default.useCallback(() => {
44560
44846
  if (action?.event) {
44561
44847
  eventBus.emit(`UI:${action.event}`, {});
44562
44848
  }
@@ -44567,7 +44853,7 @@ var init_StatCard = __esm({
44567
44853
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
44568
44854
  const isLoading = externalLoading ?? false;
44569
44855
  const error = externalError;
44570
- const computeMetricValue = React79__default.useCallback(
44856
+ const computeMetricValue = React80__default.useCallback(
44571
44857
  (metric, items) => {
44572
44858
  if (metric.value !== void 0) {
44573
44859
  return metric.value;
@@ -44606,7 +44892,7 @@ var init_StatCard = __esm({
44606
44892
  },
44607
44893
  []
44608
44894
  );
44609
- const schemaStats = React79__default.useMemo(() => {
44895
+ const schemaStats = React80__default.useMemo(() => {
44610
44896
  if (!metrics || metrics.length === 0) return null;
44611
44897
  return metrics.map((metric) => ({
44612
44898
  label: metric.label,
@@ -44614,7 +44900,7 @@ var init_StatCard = __esm({
44614
44900
  format: metric.format
44615
44901
  }));
44616
44902
  }, [metrics, data, computeMetricValue]);
44617
- const calculatedTrend = React79__default.useMemo(() => {
44903
+ const calculatedTrend = React80__default.useMemo(() => {
44618
44904
  if (manualTrend !== void 0) return manualTrend;
44619
44905
  if (previousValue === void 0 || currentValue === void 0)
44620
44906
  return void 0;
@@ -44850,22 +45136,25 @@ function VariablePanel({
44850
45136
  return /* @__PURE__ */ jsxs(VStack, { className: cn("p-3 rounded-lg bg-card border border-border", className), gap: "sm", children: [
44851
45137
  /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
44852
45138
  variables.map((v) => {
44853
- const max = v.max ?? 100;
44854
- const min = v.min ?? 0;
44855
- const pct = Math.round((v.value - min) / (max - min) * 100);
45139
+ const name = v.name == null ? "" : String(v.name);
45140
+ const value = numField(v.value);
45141
+ const max = numField(v.max, 100);
45142
+ const min = numField(v.min, 0);
45143
+ const unit = v.unit == null ? "" : String(v.unit);
45144
+ const pct = Math.round((value - min) / (max - min) * 100);
44856
45145
  const isHigh = pct > 80;
44857
45146
  const isLow = pct < 20;
44858
45147
  return /* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
44859
45148
  /* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between", children: [
44860
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children: v.name }),
45149
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children: name }),
44861
45150
  /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: cn(
44862
45151
  isHigh ? "text-error" : isLow ? "text-warning" : "text-foreground"
44863
45152
  ), children: [
44864
- v.value,
44865
- v.unit || "",
45153
+ value,
45154
+ unit,
44866
45155
  " / ",
44867
45156
  max,
44868
- v.unit || ""
45157
+ unit
44869
45158
  ] })
44870
45159
  ] }),
44871
45160
  /* @__PURE__ */ jsx(
@@ -44876,14 +45165,19 @@ function VariablePanel({
44876
45165
  size: "sm"
44877
45166
  }
44878
45167
  )
44879
- ] }, v.name);
45168
+ ] }, name);
44880
45169
  })
44881
45170
  ] });
44882
45171
  }
45172
+ var numField;
44883
45173
  var init_VariablePanel = __esm({
44884
45174
  "components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
44885
45175
  init_atoms2();
44886
45176
  init_cn();
45177
+ numField = (v, fallback = 0) => {
45178
+ const n = Number(v);
45179
+ return Number.isFinite(n) ? n : fallback;
45180
+ };
44887
45181
  VariablePanel.displayName = "VariablePanel";
44888
45182
  }
44889
45183
  });
@@ -44910,14 +45204,21 @@ function StateArchitectBoard({
44910
45204
  }) {
44911
45205
  const { emit } = useEventBus();
44912
45206
  const { t } = useTranslate();
44913
- const resolved = Array.isArray(entity) ? entity[0] : entity;
44914
- const [transitions, setTransitions] = useState(resolved?.transitions ?? []);
45207
+ const resolved = boardEntity(entity);
45208
+ const entityStates = Array.isArray(resolved?.states) ? resolved.states : [];
45209
+ const initialState = str(resolved?.initialState);
45210
+ const entityName = str(resolved?.entityName);
45211
+ const availableEvents = Array.isArray(resolved?.availableEvents) ? resolved.availableEvents : [];
45212
+ const testCases = Array.isArray(resolved?.testCases) ? resolved.testCases : [];
45213
+ const entityTransitions = Array.isArray(resolved?.transitions) ? resolved.transitions : [];
45214
+ const entityVariables = rows(resolved?.variables);
45215
+ const [transitions, setTransitions] = useState(entityTransitions);
44915
45216
  const [headerError, setHeaderError] = useState(false);
44916
45217
  const [playState, setPlayState] = useState("editing");
44917
- const [currentState, setCurrentState] = useState(resolved?.initialState ?? "");
45218
+ const [currentState, setCurrentState] = useState(initialState);
44918
45219
  const [selectedState, setSelectedState] = useState(null);
44919
45220
  const [testResults, setTestResults] = useState([]);
44920
- const [variables, setVariables] = useState(resolved?.variables ?? []);
45221
+ const [variables, setVariables] = useState(() => [...entityVariables]);
44921
45222
  const [attempts, setAttempts] = useState(0);
44922
45223
  const timerRef = useRef(null);
44923
45224
  const [addingFrom, setAddingFrom] = useState(null);
@@ -44926,12 +45227,12 @@ function StateArchitectBoard({
44926
45227
  }, []);
44927
45228
  const GRAPH_W = 500;
44928
45229
  const GRAPH_H = 400;
44929
- const positions = useMemo(() => layoutStates(resolved?.states ?? [], GRAPH_W, GRAPH_H), [resolved?.states]);
45230
+ const positions = useMemo(() => layoutStates(entityStates, GRAPH_W, GRAPH_H), [entityStates]);
44930
45231
  const handleStateClick = useCallback((state) => {
44931
45232
  if (playState !== "editing") return;
44932
45233
  if (addingFrom) {
44933
45234
  if (addingFrom !== state) {
44934
- const event = resolved?.availableEvents[0] || "EVENT";
45235
+ const event = availableEvents[0] || "EVENT";
44935
45236
  const newTrans = {
44936
45237
  id: `t-${nextTransId++}`,
44937
45238
  from: addingFrom,
@@ -44944,7 +45245,7 @@ function StateArchitectBoard({
44944
45245
  } else {
44945
45246
  setSelectedState(state);
44946
45247
  }
44947
- }, [playState, addingFrom, resolved?.availableEvents]);
45248
+ }, [playState, addingFrom, availableEvents]);
44948
45249
  const handleStartAddTransition = useCallback(() => {
44949
45250
  if (!selectedState) return;
44950
45251
  setAddingFrom(selectedState);
@@ -44953,9 +45254,9 @@ function StateArchitectBoard({
44953
45254
  setTransitions((prev) => prev.filter((t2) => t2.id !== transId));
44954
45255
  }, []);
44955
45256
  const machine = useMemo(() => ({
44956
- name: resolved?.entityName ?? "",
44957
- description: resolved?.description ?? "",
44958
- states: resolved?.states ?? [],
45257
+ name: entityName,
45258
+ description: str(resolved?.description),
45259
+ states: entityStates,
44959
45260
  currentState,
44960
45261
  transitions: transitions.map((t2) => ({
44961
45262
  from: t2.from,
@@ -44963,7 +45264,7 @@ function StateArchitectBoard({
44963
45264
  event: t2.event,
44964
45265
  guardHint: t2.guardHint
44965
45266
  }))
44966
- }), [resolved, currentState, transitions]);
45267
+ }), [entityName, resolved, entityStates, currentState, transitions]);
44967
45268
  const handleTest = useCallback(() => {
44968
45269
  if (playState !== "editing") return;
44969
45270
  if (testEvent) emit(`UI:${testEvent}`, {});
@@ -44972,7 +45273,7 @@ function StateArchitectBoard({
44972
45273
  const results = [];
44973
45274
  let testIdx = 0;
44974
45275
  const runNextTest = () => {
44975
- if (testIdx >= (resolved?.testCases.length ?? 0)) {
45276
+ if (testIdx >= testCases.length) {
44976
45277
  const allPassed = results.every((r) => r.passed);
44977
45278
  setPlayState(allPassed ? "success" : "fail");
44978
45279
  setTestResults(results);
@@ -44987,9 +45288,9 @@ function StateArchitectBoard({
44987
45288
  }
44988
45289
  return;
44989
45290
  }
44990
- const testCase = resolved?.testCases[testIdx];
45291
+ const testCase = testCases[testIdx];
44991
45292
  if (!testCase) return;
44992
- let state = resolved.initialState;
45293
+ let state = initialState;
44993
45294
  for (const event of testCase.events) {
44994
45295
  const trans = transitions.find((t2) => t2.from === state && t2.event === event);
44995
45296
  if (trans) {
@@ -45007,53 +45308,57 @@ function StateArchitectBoard({
45007
45308
  timerRef.current = setTimeout(runNextTest, stepDurationMs);
45008
45309
  };
45009
45310
  timerRef.current = setTimeout(runNextTest, stepDurationMs);
45010
- }, [playState, transitions, resolved, stepDurationMs, testEvent, completeEvent, emit]);
45311
+ }, [playState, transitions, testCases, initialState, stepDurationMs, testEvent, completeEvent, emit]);
45011
45312
  const handleTryAgain = useCallback(() => {
45012
45313
  if (timerRef.current) clearTimeout(timerRef.current);
45013
45314
  setPlayState("editing");
45014
- setCurrentState(resolved?.initialState ?? "");
45315
+ setCurrentState(initialState);
45015
45316
  setTestResults([]);
45016
- }, [resolved?.initialState]);
45317
+ }, [initialState]);
45017
45318
  const handleReset = useCallback(() => {
45018
45319
  if (timerRef.current) clearTimeout(timerRef.current);
45019
- setTransitions(resolved?.transitions ?? []);
45320
+ setTransitions(entityTransitions);
45020
45321
  setPlayState("editing");
45021
- setCurrentState(resolved?.initialState ?? "");
45322
+ setCurrentState(initialState);
45022
45323
  setTestResults([]);
45023
- setVariables(resolved?.variables ?? []);
45324
+ setVariables([...entityVariables]);
45024
45325
  setSelectedState(null);
45025
45326
  setAddingFrom(null);
45026
45327
  setAttempts(0);
45027
- }, [resolved]);
45328
+ }, [entityTransitions, initialState, entityVariables]);
45028
45329
  const codeData = useMemo(() => ({
45029
- name: resolved?.entityName ?? "",
45030
- states: resolved?.states ?? [],
45031
- initialState: resolved?.initialState ?? "",
45330
+ name: entityName,
45331
+ states: entityStates,
45332
+ initialState,
45032
45333
  transitions: transitions.map((t2) => ({
45033
45334
  from: t2.from,
45034
45335
  to: t2.to,
45035
45336
  event: t2.event,
45036
45337
  ...t2.guardHint ? { guard: t2.guardHint } : {}
45037
45338
  }))
45038
- }), [resolved, transitions]);
45339
+ }), [entityName, entityStates, initialState, transitions]);
45039
45340
  if (!resolved) return null;
45341
+ const theme = resolved.theme ?? void 0;
45342
+ const themeBackground = theme?.background;
45343
+ const headerImage = str(resolved.headerImage);
45344
+ const hint = str(resolved.hint);
45040
45345
  return /* @__PURE__ */ jsxs(
45041
45346
  VStack,
45042
45347
  {
45043
45348
  className: cn("p-4 gap-6", className),
45044
45349
  style: {
45045
- backgroundImage: resolved.theme?.background ? `url(${resolved.theme.background})` : void 0,
45350
+ backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
45046
45351
  backgroundSize: "cover",
45047
45352
  backgroundPosition: "center"
45048
45353
  },
45049
45354
  children: [
45050
- resolved.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: resolved.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : resolved.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
45355
+ headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
45051
45356
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
45052
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
45053
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
45357
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
45358
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
45054
45359
  /* @__PURE__ */ jsxs(HStack, { className: "items-center p-2 rounded bg-warning/10 border border-warning/30", gap: "xs", children: [
45055
45360
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-warning font-bold", children: t("game.hint") + ":" }),
45056
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: resolved.hint })
45361
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: hint })
45057
45362
  ] })
45058
45363
  ] }),
45059
45364
  /* @__PURE__ */ jsxs(HStack, { className: "flex-wrap items-start", gap: "lg", children: [
@@ -45101,14 +45406,14 @@ function StateArchitectBoard({
45101
45406
  ]
45102
45407
  }
45103
45408
  ),
45104
- resolved.states.map((state) => /* @__PURE__ */ jsx(
45409
+ entityStates.map((state) => /* @__PURE__ */ jsx(
45105
45410
  StateNode2,
45106
45411
  {
45107
45412
  name: state,
45108
45413
  position: positions[state],
45109
45414
  isCurrent: state === currentState,
45110
45415
  isSelected: state === selectedState,
45111
- isInitial: state === resolved.initialState,
45416
+ isInitial: state === initialState,
45112
45417
  onClick: () => handleStateClick(state)
45113
45418
  },
45114
45419
  state
@@ -45155,7 +45460,7 @@ function StateArchitectBoard({
45155
45460
  /* @__PURE__ */ jsx(
45156
45461
  VariablePanel,
45157
45462
  {
45158
- entityName: resolved.entityName,
45463
+ entityName,
45159
45464
  variables
45160
45465
  }
45161
45466
  ),
@@ -45170,12 +45475,12 @@ function StateArchitectBoard({
45170
45475
  resolved.showCodeView !== false && /* @__PURE__ */ jsx(CodeView, { data: codeData, label: "View Code" })
45171
45476
  ] })
45172
45477
  ] }),
45173
- playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("stateArchitect.allPassed") }) }),
45478
+ playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("stateArchitect.allPassed") }) }),
45174
45479
  playState === "fail" && /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
45175
45480
  /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(ENCOURAGEMENT_KEYS3[Math.min(attempts - 1, ENCOURAGEMENT_KEYS3.length - 1)] ?? ENCOURAGEMENT_KEYS3[0]) }) }),
45176
- attempts >= 3 && resolved.hint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
45481
+ attempts >= 3 && hint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
45177
45482
  /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
45178
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: resolved.hint })
45483
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
45179
45484
  ] }) })
45180
45485
  ] }),
45181
45486
  /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
@@ -45205,6 +45510,7 @@ var init_StateArchitectBoard = __esm({
45205
45510
  init_TransitionArrow();
45206
45511
  init_VariablePanel();
45207
45512
  init_CodeView();
45513
+ init_boardEntity();
45208
45514
  ENCOURAGEMENT_KEYS3 = [
45209
45515
  "puzzle.tryAgain1",
45210
45516
  "puzzle.tryAgain2",
@@ -45241,8 +45547,8 @@ var init_StatsOrganism = __esm({
45241
45547
  return /* @__PURE__ */ jsx(ErrorState, { message: error.message, className });
45242
45548
  }
45243
45549
  const stats = items.map((item) => ({
45244
- value: item.value,
45245
- label: item.label
45550
+ value: String(item.value ?? ""),
45551
+ label: String(item.label ?? "")
45246
45552
  }));
45247
45553
  return /* @__PURE__ */ jsx(
45248
45554
  StatsGrid,
@@ -45359,10 +45665,10 @@ var init_StepFlowOrganism = __esm({
45359
45665
  return /* @__PURE__ */ jsx(ErrorState, { message: error.message, className });
45360
45666
  }
45361
45667
  const steps = items.map((item) => ({
45362
- number: item.number,
45363
- title: item.title,
45364
- description: item.description,
45365
- icon: item.icon
45668
+ number: item.number != null ? Number(item.number) : void 0,
45669
+ title: String(item.title ?? ""),
45670
+ description: String(item.description ?? ""),
45671
+ icon: item.icon != null ? String(item.icon) : void 0
45366
45672
  }));
45367
45673
  return /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
45368
45674
  (heading || subtitle) && /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
@@ -45535,13 +45841,13 @@ var init_TeamOrganism = __esm({
45535
45841
  /* @__PURE__ */ jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((member) => /* @__PURE__ */ jsx(
45536
45842
  TeamCard,
45537
45843
  {
45538
- name: member.name,
45539
- nameAr: member.nameAr,
45540
- role: member.role,
45541
- bio: member.bio,
45542
- avatar: member.avatar
45844
+ name: String(member.name ?? ""),
45845
+ nameAr: member.nameAr != null ? String(member.nameAr) : void 0,
45846
+ role: String(member.role ?? ""),
45847
+ bio: String(member.bio ?? ""),
45848
+ avatar: member.avatar != null ? String(member.avatar) : void 0
45543
45849
  },
45544
- member.id
45850
+ String(member.id ?? "")
45545
45851
  )) })
45546
45852
  ] });
45547
45853
  };
@@ -45599,7 +45905,7 @@ var init_Timeline = __esm({
45599
45905
  }) => {
45600
45906
  const { t } = useTranslate();
45601
45907
  const entityData = Array.isArray(entity) ? entity : [];
45602
- const items = React79__default.useMemo(() => {
45908
+ const items = React80__default.useMemo(() => {
45603
45909
  if (propItems) return propItems;
45604
45910
  if (entityData.length === 0) return [];
45605
45911
  return entityData.map((record, idx) => {
@@ -45756,7 +46062,7 @@ var init_TimerDisplay = __esm({
45756
46062
  }
45757
46063
  });
45758
46064
  function extractToastProps(children) {
45759
- if (!React79__default.isValidElement(children)) {
46065
+ if (!React80__default.isValidElement(children)) {
45760
46066
  if (typeof children === "string") {
45761
46067
  return { message: children };
45762
46068
  }
@@ -45794,7 +46100,7 @@ var init_ToastSlot = __esm({
45794
46100
  eventBus.emit("UI:CLOSE");
45795
46101
  };
45796
46102
  if (!isVisible) return null;
45797
- const isCustomContent = React79__default.isValidElement(children) && !message;
46103
+ const isCustomContent = React80__default.isValidElement(children) && !message;
45798
46104
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
45799
46105
  Toast,
45800
46106
  {
@@ -45828,8 +46134,8 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
45828
46134
  const [turn, setTurn] = useState(1);
45829
46135
  const [gameResult, setGameResult] = useState(null);
45830
46136
  const checkGameEnd = useCallback((currentUnits) => {
45831
- const pa = currentUnits.filter((u) => u.team === "player" && u.health > 0);
45832
- const ea = currentUnits.filter((u) => u.team === "enemy" && u.health > 0);
46137
+ const pa = currentUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
46138
+ const ea = currentUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
45833
46139
  if (pa.length === 0) {
45834
46140
  setGameResult("defeat");
45835
46141
  setPhase("game_over");
@@ -45847,34 +46153,36 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
45847
46153
  }
45848
46154
  }, [onGameEnd, gameEndEvent, eventBus]);
45849
46155
  const handleUnitClick = useCallback((unitId) => {
45850
- const unit = units.find((u) => u.id === unitId);
46156
+ const unit = units.find((u) => str(u.id) === unitId);
45851
46157
  if (!unit) return;
45852
46158
  if (unitClickEvent) {
45853
46159
  eventBus.emit(`UI:${unitClickEvent}`, { unitId });
45854
46160
  }
45855
46161
  if (phase === "observation" || phase === "selection") {
45856
- if (unit.team === "player") {
46162
+ if (unitTeam(unit) === "player") {
45857
46163
  setSelectedUnitId(unitId);
45858
46164
  setPhase("movement");
45859
46165
  }
45860
46166
  } else if (phase === "action") {
45861
- const selectedUnit = units.find((u) => u.id === selectedUnitId);
46167
+ const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
45862
46168
  if (!selectedUnit) return;
45863
- if (unit.team === "enemy") {
45864
- const dx = Math.abs(unit.position.x - selectedUnit.position.x);
45865
- const dy = Math.abs(unit.position.y - selectedUnit.position.y);
46169
+ if (unitTeam(unit) === "enemy") {
46170
+ const up = unitPosition(unit);
46171
+ const sp = unitPosition(selectedUnit);
46172
+ const dx = Math.abs(up.x - sp.x);
46173
+ const dy = Math.abs(up.y - sp.y);
45866
46174
  if (dx <= 1 && dy <= 1 && dx + dy > 0) {
45867
- const damage = calculateDamage2 ? calculateDamage2(selectedUnit, unit) : Math.max(1, selectedUnit.attack - unit.defense);
45868
- const newHealth = Math.max(0, unit.health - damage);
46175
+ const damage = calculateDamage2 ? calculateDamage2(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
46176
+ const newHealth = Math.max(0, unitHealth(unit) - damage);
45869
46177
  const updatedUnits = units.map(
45870
- (u) => u.id === unit.id ? { ...u, health: newHealth } : u
46178
+ (u) => str(u.id) === str(unit.id) ? { ...u, health: newHealth } : u
45871
46179
  );
45872
46180
  setUnits(updatedUnits);
45873
46181
  onAttack?.(selectedUnit, unit, damage);
45874
46182
  if (attackEvent) {
45875
46183
  eventBus.emit(`UI:${attackEvent}`, {
45876
- attackerId: selectedUnit.id,
45877
- targetId: unit.id,
46184
+ attackerId: str(selectedUnit.id),
46185
+ targetId: str(unit.id),
45878
46186
  damage
45879
46187
  });
45880
46188
  }
@@ -45891,16 +46199,20 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
45891
46199
  eventBus.emit(`UI:${tileClickEvent}`, { x, y });
45892
46200
  }
45893
46201
  if (phase === "movement" && selectedUnitId) {
45894
- const selectedUnit = units.find((u) => u.id === selectedUnitId);
46202
+ const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
45895
46203
  if (!selectedUnit) return;
45896
- const dx = Math.abs(x - selectedUnit.position.x);
45897
- const dy = Math.abs(y - selectedUnit.position.y);
46204
+ const sp = unitPosition(selectedUnit);
46205
+ const dx = Math.abs(x - sp.x);
46206
+ const dy = Math.abs(y - sp.y);
45898
46207
  const dist = dx + dy;
45899
- if (dist > 0 && dist <= selectedUnit.movement) {
45900
- if (!units.some((u) => u.position.x === x && u.position.y === y && u.health > 0)) {
46208
+ if (dist > 0 && dist <= num(selectedUnit.movement)) {
46209
+ if (!units.some((u) => {
46210
+ const p2 = unitPosition(u);
46211
+ return p2.x === x && p2.y === y && unitHealth(u) > 0;
46212
+ })) {
45901
46213
  setUnits(
45902
46214
  (prev) => prev.map(
45903
- (u) => u.id === selectedUnitId ? { ...u, position: { x, y } } : u
46215
+ (u) => str(u.id) === selectedUnitId ? { ...u, position: { x, y } } : u
45904
46216
  )
45905
46217
  );
45906
46218
  setPhase("action");
@@ -45943,12 +46255,13 @@ var init_useBattleState = __esm({
45943
46255
  "components/game/organisms/hooks/useBattleState.ts"() {
45944
46256
  "use client";
45945
46257
  init_useEventBus();
46258
+ init_boardEntity();
45946
46259
  }
45947
46260
  });
45948
46261
  function UncontrolledBattleBoard({ entity, ...rest }) {
45949
- const resolved = Array.isArray(entity) ? entity[0] : entity;
46262
+ const resolved = boardEntity(entity);
45950
46263
  const battleState = useBattleState(
45951
- resolved?.initialUnits ?? [],
46264
+ rows(resolved?.initialUnits),
45952
46265
  {
45953
46266
  tileClickEvent: rest.tileClickEvent,
45954
46267
  unitClickEvent: rest.unitClickEvent,
@@ -45984,10 +46297,23 @@ function UncontrolledBattleBoard({ entity, ...rest }) {
45984
46297
  var init_UncontrolledBattleBoard = __esm({
45985
46298
  "components/game/organisms/UncontrolledBattleBoard.tsx"() {
45986
46299
  init_BattleBoard();
46300
+ init_boardEntity();
45987
46301
  init_useBattleState();
45988
46302
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
45989
46303
  }
45990
46304
  });
46305
+ function heroPosition(h) {
46306
+ return vec2(h.position);
46307
+ }
46308
+ function heroOwner(h) {
46309
+ return str(h.owner);
46310
+ }
46311
+ function heroMovement(h) {
46312
+ return num(h.movement);
46313
+ }
46314
+ function hexPassable(h) {
46315
+ return h.passable !== false;
46316
+ }
45991
46317
  function defaultIsInRange(from, to, range) {
45992
46318
  return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
45993
46319
  }
@@ -46018,36 +46344,36 @@ function WorldMapBoard({
46018
46344
  className
46019
46345
  }) {
46020
46346
  const eventBus = useEventBus();
46021
- const resolved = Array.isArray(entity) ? entity[0] : entity;
46022
- const hexes = resolved?.hexes ?? [];
46023
- const heroes = resolved?.heroes ?? [];
46024
- const features = resolved?.features ?? [];
46025
- const selectedHeroId = resolved?.selectedHeroId;
46347
+ const resolved = boardEntity(entity);
46348
+ const hexes = rows(resolved?.hexes);
46349
+ const heroes = rows(resolved?.heroes);
46350
+ const features = Array.isArray(resolved?.features) ? resolved.features : [];
46351
+ const selectedHeroId = resolved?.selectedHeroId ?? null;
46026
46352
  const assetManifest = resolved?.assetManifest;
46027
46353
  const backgroundImage = resolved?.backgroundImage;
46028
46354
  const [hoveredTile, setHoveredTile] = useState(null);
46029
46355
  const selectedHero = useMemo(
46030
- () => heroes.find((h) => h.id === selectedHeroId) ?? null,
46356
+ () => heroes.find((h) => str(h.id) === selectedHeroId) ?? null,
46031
46357
  [heroes, selectedHeroId]
46032
46358
  );
46033
46359
  const tiles = useMemo(
46034
46360
  () => hexes.map((hex) => ({
46035
- x: hex.x,
46036
- y: hex.y,
46037
- terrain: hex.terrain,
46038
- terrainSprite: hex.terrainSprite
46361
+ x: num(hex.x),
46362
+ y: num(hex.y),
46363
+ terrain: str(hex.terrain),
46364
+ terrainSprite: hex.terrainSprite == null ? void 0 : str(hex.terrainSprite)
46039
46365
  })),
46040
46366
  [hexes]
46041
46367
  );
46042
46368
  const baseUnits = useMemo(
46043
46369
  () => heroes.map((hero) => ({
46044
- id: hero.id,
46045
- position: hero.position,
46046
- name: hero.name,
46047
- team: hero.owner === "enemy" ? "enemy" : "player",
46370
+ id: str(hero.id),
46371
+ position: heroPosition(hero),
46372
+ name: str(hero.name),
46373
+ team: heroOwner(hero) === "enemy" ? "enemy" : "player",
46048
46374
  health: 100,
46049
46375
  maxHealth: 100,
46050
- sprite: hero.sprite
46376
+ sprite: hero.sprite == null ? void 0 : str(hero.sprite)
46051
46377
  })),
46052
46378
  [heroes]
46053
46379
  );
@@ -46088,73 +46414,94 @@ function WorldMapBoard({
46088
46414
  const isoUnits = useMemo(() => {
46089
46415
  if (movingPositions.size === 0) return baseUnits;
46090
46416
  return baseUnits.map((u) => {
46091
- const pos = movingPositions.get(u.id);
46417
+ const pos = u.id == null ? void 0 : movingPositions.get(u.id);
46092
46418
  return pos ? { ...u, position: pos } : u;
46093
46419
  });
46094
46420
  }, [baseUnits, movingPositions]);
46095
46421
  const validMoves = useMemo(() => {
46096
- if (!selectedHero || selectedHero.movement <= 0) return [];
46422
+ if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
46423
+ const sp = heroPosition(selectedHero);
46424
+ const sOwner = heroOwner(selectedHero);
46425
+ const range = heroMovement(selectedHero);
46097
46426
  const moves = [];
46098
46427
  hexes.forEach((hex) => {
46099
- if (hex.passable === false) return;
46100
- if (hex.x === selectedHero.position.x && hex.y === selectedHero.position.y) return;
46101
- if (!isInRange(selectedHero.position, { x: hex.x, y: hex.y }, selectedHero.movement)) return;
46102
- if (heroes.some((h) => h.position.x === hex.x && h.position.y === hex.y && h.owner === selectedHero.owner)) return;
46103
- moves.push({ x: hex.x, y: hex.y });
46428
+ const hx = num(hex.x);
46429
+ const hy = num(hex.y);
46430
+ if (!hexPassable(hex)) return;
46431
+ if (hx === sp.x && hy === sp.y) return;
46432
+ if (!isInRange(sp, { x: hx, y: hy }, range)) return;
46433
+ if (heroes.some((h) => {
46434
+ const hp = heroPosition(h);
46435
+ return hp.x === hx && hp.y === hy && heroOwner(h) === sOwner;
46436
+ })) return;
46437
+ moves.push({ x: hx, y: hy });
46104
46438
  });
46105
46439
  return moves;
46106
46440
  }, [selectedHero, hexes, heroes, isInRange]);
46107
46441
  const attackTargets = useMemo(() => {
46108
- if (!selectedHero || selectedHero.movement <= 0) return [];
46109
- return heroes.filter((h) => h.owner !== selectedHero.owner).filter((h) => isInRange(selectedHero.position, h.position, selectedHero.movement)).map((h) => h.position);
46442
+ if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
46443
+ const sp = heroPosition(selectedHero);
46444
+ const sOwner = heroOwner(selectedHero);
46445
+ const range = heroMovement(selectedHero);
46446
+ return heroes.filter((h) => heroOwner(h) !== sOwner).filter((h) => isInRange(sp, heroPosition(h), range)).map((h) => heroPosition(h));
46110
46447
  }, [selectedHero, heroes, isInRange]);
46111
- const maxY = Math.max(...hexes.map((h) => h.y), 0);
46448
+ const maxY = Math.max(...hexes.map((h) => num(h.y)), 0);
46112
46449
  const baseOffsetX = (maxY + 1) * (TILE_WIDTH * scale / 2);
46113
46450
  const tileToScreen = useCallback(
46114
46451
  (tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
46115
46452
  [scale, baseOffsetX]
46116
46453
  );
46117
46454
  const hoveredHex = useMemo(
46118
- () => hoveredTile ? hexes.find((h) => h.x === hoveredTile.x && h.y === hoveredTile.y) ?? null : null,
46455
+ () => hoveredTile ? hexes.find((h) => num(h.x) === hoveredTile.x && num(h.y) === hoveredTile.y) ?? null : null,
46119
46456
  [hoveredTile, hexes]
46120
46457
  );
46121
46458
  const hoveredHero = useMemo(
46122
- () => hoveredTile ? heroes.find((h) => h.position.x === hoveredTile.x && h.position.y === hoveredTile.y) ?? null : null,
46459
+ () => hoveredTile ? heroes.find((h) => {
46460
+ const hp = heroPosition(h);
46461
+ return hp.x === hoveredTile.x && hp.y === hoveredTile.y;
46462
+ }) ?? null : null,
46123
46463
  [hoveredTile, heroes]
46124
46464
  );
46125
46465
  const handleTileClick = useCallback((x, y) => {
46126
46466
  if (movementAnimRef.current) return;
46127
- const hex = hexes.find((h) => h.x === x && h.y === y);
46467
+ const hex = hexes.find((h) => num(h.x) === x && num(h.y) === y);
46128
46468
  if (!hex) return;
46129
46469
  if (tileClickEvent) {
46130
46470
  eventBus.emit(`UI:${tileClickEvent}`, { x, y });
46131
46471
  }
46132
46472
  if (selectedHero && validMoves.some((m) => m.x === x && m.y === y)) {
46133
- startMoveAnimation(selectedHero.id, { ...selectedHero.position }, { x, y }, () => {
46134
- onHeroMove?.(selectedHero.id, x, y);
46473
+ const heroId = str(selectedHero.id);
46474
+ startMoveAnimation(heroId, { ...heroPosition(selectedHero) }, { x, y }, () => {
46475
+ onHeroMove?.(heroId, x, y);
46135
46476
  if (heroMoveEvent) {
46136
- eventBus.emit(`UI:${heroMoveEvent}`, { heroId: selectedHero.id, toX: x, toY: y });
46477
+ eventBus.emit(`UI:${heroMoveEvent}`, { heroId, toX: x, toY: y });
46137
46478
  }
46138
- if (hex.feature && hex.feature !== "none") {
46139
- onFeatureEnter?.(selectedHero.id, hex);
46479
+ const feature = str(hex.feature);
46480
+ if (feature && feature !== "none") {
46481
+ onFeatureEnter?.(heroId, hex);
46140
46482
  if (featureEnterEvent) {
46141
- eventBus.emit(`UI:${featureEnterEvent}`, { heroId: selectedHero.id, feature: hex.feature, hex });
46483
+ eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex });
46142
46484
  }
46143
46485
  }
46144
46486
  });
46145
46487
  return;
46146
46488
  }
46147
- const enemy = heroes.find((h) => h.position.x === x && h.position.y === y && h.owner === "enemy");
46489
+ const enemy = heroes.find((h) => {
46490
+ const hp = heroPosition(h);
46491
+ return hp.x === x && hp.y === y && heroOwner(h) === "enemy";
46492
+ });
46148
46493
  if (selectedHero && enemy && attackTargets.some((t) => t.x === x && t.y === y)) {
46149
- onBattleEncounter?.(selectedHero.id, enemy.id);
46494
+ const attackerId = str(selectedHero.id);
46495
+ const defenderId = str(enemy.id);
46496
+ onBattleEncounter?.(attackerId, defenderId);
46150
46497
  if (battleEncounterEvent) {
46151
- eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId: selectedHero.id, defenderId: enemy.id });
46498
+ eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId, defenderId });
46152
46499
  }
46153
46500
  }
46154
46501
  }, [hexes, heroes, selectedHero, validMoves, attackTargets, startMoveAnimation, onHeroMove, onFeatureEnter, onBattleEncounter, eventBus, tileClickEvent, heroMoveEvent, featureEnterEvent, battleEncounterEvent]);
46155
46502
  const handleUnitClick = useCallback((unitId) => {
46156
- const hero = heroes.find((h) => h.id === unitId);
46157
- if (hero && (hero.owner === "player" || allowMoveAllHeroes)) {
46503
+ const hero = heroes.find((h) => str(h.id) === unitId);
46504
+ if (hero && (heroOwner(hero) === "player" || allowMoveAllHeroes)) {
46158
46505
  onHeroSelect?.(unitId);
46159
46506
  if (heroSelectEvent) {
46160
46507
  eventBus.emit(`UI:${heroSelectEvent}`, { heroId: unitId });
@@ -46227,6 +46574,7 @@ var init_WorldMapBoard = __esm({
46227
46574
  init_Stack();
46228
46575
  init_LoadingState();
46229
46576
  init_IsometricCanvas2();
46577
+ init_boardEntity();
46230
46578
  init_isometric();
46231
46579
  WorldMapBoard.displayName = "WorldMapBoard";
46232
46580
  }
@@ -46330,12 +46678,12 @@ var init_XPBar = __esm({
46330
46678
  }
46331
46679
  });
46332
46680
  function lazyThree(name, loader) {
46333
- const Lazy = React79__default.lazy(() => loader().then((m) => ({ default: m[name] })));
46681
+ const Lazy = React80__default.lazy(() => loader().then((m) => ({ default: m[name] })));
46334
46682
  function ThreeWrapper(props) {
46335
- return React79__default.createElement(
46336
- React79__default.Suspense,
46683
+ return React80__default.createElement(
46684
+ React80__default.Suspense,
46337
46685
  { fallback: null },
46338
- React79__default.createElement(Lazy, props)
46686
+ React80__default.createElement(Lazy, props)
46339
46687
  );
46340
46688
  }
46341
46689
  ThreeWrapper.displayName = `Lazy(${name})`;
@@ -46350,7 +46698,7 @@ var init_component_registry_generated = __esm({
46350
46698
  init_ActionButtons();
46351
46699
  init_ActionPalette();
46352
46700
  init_ActionTile();
46353
- init_AnimatedCounter();
46701
+ init_AnimatedCounter2();
46354
46702
  init_AnimatedGraphic();
46355
46703
  init_AnimatedReveal();
46356
46704
  init_ArticleSection();
@@ -46621,7 +46969,7 @@ var init_component_registry_generated = __esm({
46621
46969
  "ActionTile": ActionTile,
46622
46970
  "Alert": AlertPattern,
46623
46971
  "AlertPattern": AlertPattern,
46624
- "AnimatedCounter": AnimatedCounter,
46972
+ "AnimatedCounter": AnimatedCounter2,
46625
46973
  "AnimatedGraphic": AnimatedGraphic,
46626
46974
  "AnimatedReveal": AnimatedReveal,
46627
46975
  "ArticleSection": ArticleSection,
@@ -46951,7 +47299,7 @@ function SuspenseConfigProvider({
46951
47299
  config,
46952
47300
  children
46953
47301
  }) {
46954
- return React79__default.createElement(
47302
+ return React80__default.createElement(
46955
47303
  SuspenseConfigContext.Provider,
46956
47304
  { value: config },
46957
47305
  children
@@ -47436,7 +47784,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
47436
47784
  const key = `${parentId}-${index}-trait:${traitName}`;
47437
47785
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
47438
47786
  }
47439
- return /* @__PURE__ */ jsx(React79__default.Fragment, { children: child }, `${parentId}-${index}`);
47787
+ return /* @__PURE__ */ jsx(React80__default.Fragment, { children: child }, `${parentId}-${index}`);
47440
47788
  }
47441
47789
  if (!child || typeof child !== "object") return null;
47442
47790
  const childId = `${parentId}-${index}`;
@@ -47476,14 +47824,14 @@ function isPatternConfig(value) {
47476
47824
  if (value === null || value === void 0) return false;
47477
47825
  if (typeof value !== "object") return false;
47478
47826
  if (Array.isArray(value)) return false;
47479
- if (React79__default.isValidElement(value)) return false;
47827
+ if (React80__default.isValidElement(value)) return false;
47480
47828
  if (value instanceof Date) return false;
47481
47829
  if (typeof value === "function") return false;
47482
47830
  const record = value;
47483
47831
  return "type" in record && typeof record.type === "string";
47484
47832
  }
47485
47833
  function isPlainConfigObject(value) {
47486
- if (React79__default.isValidElement(value)) return false;
47834
+ if (React80__default.isValidElement(value)) return false;
47487
47835
  if (value instanceof Date) return false;
47488
47836
  const proto = Object.getPrototypeOf(value);
47489
47837
  return proto === Object.prototype || proto === null;