@almadar/ui 5.60.0 → 5.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/avl/index.cjs +3233 -1757
  2. package/dist/avl/index.js +2057 -581
  3. package/dist/components/core/molecules/GraphCanvas.d.ts +6 -0
  4. package/dist/components/core/templates/index.d.ts +4 -0
  5. package/dist/components/game/molecules/CardHand.d.ts +35 -0
  6. package/dist/components/game/molecules/DialogueBox.d.ts +8 -2
  7. package/dist/components/game/molecules/index.d.ts +1 -0
  8. package/dist/components/game/molecules/three/index.cjs +229 -120
  9. package/dist/components/game/molecules/three/index.js +229 -120
  10. package/dist/components/game/organisms/CardBattlerBoard.d.ts +46 -0
  11. package/dist/components/game/organisms/CityBuilderBoard.d.ts +63 -0
  12. package/dist/components/game/organisms/TopDownShooterBoard.d.ts +64 -0
  13. package/dist/components/game/organisms/TowerDefenseBoard.d.ts +10 -1
  14. package/dist/components/game/organisms/TraitSlot.d.ts +1 -3
  15. package/dist/components/game/organisms/VisualNovelBoard.d.ts +53 -0
  16. package/dist/components/game/organisms/index.d.ts +4 -0
  17. package/dist/components/game/templates/CardBattlerTemplate.d.ts +35 -0
  18. package/dist/components/game/templates/CityBuilderTemplate.d.ts +40 -0
  19. package/dist/components/game/templates/GameCanvas3DBattleTemplate.d.ts +5 -2
  20. package/dist/components/game/templates/GameCanvas3DCastleTemplate.d.ts +5 -2
  21. package/dist/components/game/templates/GameCanvas3DWorldMapTemplate.d.ts +5 -2
  22. package/dist/components/game/templates/TopDownShooterTemplate.d.ts +42 -0
  23. package/dist/components/game/templates/VisualNovelTemplate.d.ts +28 -0
  24. package/dist/components/game/templates/game3dAssetManifest.d.ts +50 -0
  25. package/dist/components/game/templates/index.d.ts +4 -0
  26. package/dist/components/index.cjs +3048 -1547
  27. package/dist/components/index.js +2019 -527
  28. package/dist/docs/index.cjs +105 -1
  29. package/dist/docs/index.js +105 -1
  30. package/dist/hooks/index.cjs +105 -1
  31. package/dist/hooks/index.js +105 -1
  32. package/dist/locales/index.cjs +315 -3
  33. package/dist/locales/index.js +315 -3
  34. package/dist/providers/index.cjs +3034 -1558
  35. package/dist/providers/index.js +2025 -549
  36. package/dist/runtime/index.cjs +3085 -1609
  37. package/dist/runtime/index.js +2024 -548
  38. package/locales/ar.json +105 -1
  39. package/locales/en.json +105 -1
  40. package/locales/sl.json +105 -1
  41. package/package.json +1 -1
package/dist/avl/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import * as React90 from 'react';
3
- import React90__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
2
+ import * as React93 from 'react';
3
+ import React93__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
4
4
  import { OrbitalProvider, EventBusContext, useTraitScope, VerificationProvider, TraitScopeProvider } from '@almadar/ui/providers';
5
5
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
6
6
  import ELK from 'elkjs/lib/elk.bundled.js';
@@ -3470,7 +3470,7 @@ var init_Box = __esm({
3470
3470
  fixed: "fixed",
3471
3471
  sticky: "sticky"
3472
3472
  };
3473
- Box = React90__default.forwardRef(
3473
+ Box = React93__default.forwardRef(
3474
3474
  ({
3475
3475
  padding,
3476
3476
  paddingX,
@@ -3520,7 +3520,7 @@ var init_Box = __esm({
3520
3520
  onMouseLeave?.(e);
3521
3521
  }, [hoverEvent, eventBus, onMouseLeave]);
3522
3522
  const isClickable = action || onClick;
3523
- return React90__default.createElement(
3523
+ return React93__default.createElement(
3524
3524
  Component2,
3525
3525
  {
3526
3526
  ref,
@@ -4110,7 +4110,7 @@ var init_MiniStateMachine = __esm({
4110
4110
  const x = 2 + i * (NODE_W + GAP + ARROW_W + GAP);
4111
4111
  const tc = transitionCounts[s.name] ?? 0;
4112
4112
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
4113
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
4113
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
4114
4114
  /* @__PURE__ */ jsx(
4115
4115
  AvlState,
4116
4116
  {
@@ -4485,7 +4485,7 @@ function loadLib(key, importer) {
4485
4485
  return p2;
4486
4486
  }
4487
4487
  function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
4488
- const Lazy = React90__default.lazy(async () => {
4488
+ const Lazy = React93__default.lazy(async () => {
4489
4489
  const lib = await loadLib(libKey, importer);
4490
4490
  const Comp = pick(lib);
4491
4491
  if (!Comp) {
@@ -4495,7 +4495,7 @@ function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
4495
4495
  return { default: Comp };
4496
4496
  });
4497
4497
  const Wrapped = (props) => /* @__PURE__ */ jsx(
4498
- React90__default.Suspense,
4498
+ React93__default.Suspense,
4499
4499
  {
4500
4500
  fallback: /* @__PURE__ */ jsx(
4501
4501
  "span",
@@ -5221,7 +5221,7 @@ var init_Icon = __esm({
5221
5221
  const directIcon = typeof icon === "string" ? void 0 : icon;
5222
5222
  const effectiveName = typeof icon === "string" ? icon : name;
5223
5223
  const family = useIconFamily();
5224
- const RenderedComponent = React90__default.useMemo(() => {
5224
+ const RenderedComponent = React93__default.useMemo(() => {
5225
5225
  if (directIcon) return null;
5226
5226
  return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
5227
5227
  }, [directIcon, effectiveName, family]);
@@ -5280,7 +5280,7 @@ function resolveIconProp(value, sizeClass) {
5280
5280
  const IconComp = value;
5281
5281
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
5282
5282
  }
5283
- if (React90__default.isValidElement(value)) {
5283
+ if (React93__default.isValidElement(value)) {
5284
5284
  return value;
5285
5285
  }
5286
5286
  if (typeof value === "object" && value !== null && "render" in value) {
@@ -5356,7 +5356,7 @@ var init_Button = __esm({
5356
5356
  md: "h-icon-default w-icon-default",
5357
5357
  lg: "h-icon-default w-icon-default"
5358
5358
  };
5359
- Button = React90__default.forwardRef(
5359
+ Button = React93__default.forwardRef(
5360
5360
  ({
5361
5361
  className,
5362
5362
  variant = "primary",
@@ -5421,7 +5421,7 @@ var Dialog;
5421
5421
  var init_Dialog = __esm({
5422
5422
  "components/core/atoms/Dialog.tsx"() {
5423
5423
  init_cn();
5424
- Dialog = React90__default.forwardRef(
5424
+ Dialog = React93__default.forwardRef(
5425
5425
  ({
5426
5426
  role = "dialog",
5427
5427
  "aria-modal": ariaModal = true,
@@ -5916,7 +5916,7 @@ var init_Badge = __esm({
5916
5916
  md: "px-2.5 py-1 text-sm",
5917
5917
  lg: "px-3 py-1.5 text-base"
5918
5918
  };
5919
- Badge = React90__default.forwardRef(
5919
+ Badge = React93__default.forwardRef(
5920
5920
  ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
5921
5921
  const iconSizes3 = {
5922
5922
  sm: "h-icon-default w-icon-default",
@@ -6252,7 +6252,7 @@ var init_SvgFlow = __esm({
6252
6252
  width = 100,
6253
6253
  height = 100
6254
6254
  }) => {
6255
- const markerId = React90__default.useMemo(() => {
6255
+ const markerId = React93__default.useMemo(() => {
6256
6256
  flowIdCounter += 1;
6257
6257
  return `almadar-flow-arrow-${flowIdCounter}`;
6258
6258
  }, []);
@@ -6845,7 +6845,7 @@ var init_SvgRing = __esm({
6845
6845
  width = 100,
6846
6846
  height = 100
6847
6847
  }) => {
6848
- const gradientId = React90__default.useMemo(() => {
6848
+ const gradientId = React93__default.useMemo(() => {
6849
6849
  ringIdCounter += 1;
6850
6850
  return `almadar-ring-glow-${ringIdCounter}`;
6851
6851
  }, []);
@@ -7026,7 +7026,7 @@ var init_Input = __esm({
7026
7026
  init_cn();
7027
7027
  init_Icon();
7028
7028
  init_useEventBus();
7029
- Input = React90__default.forwardRef(
7029
+ Input = React93__default.forwardRef(
7030
7030
  ({
7031
7031
  className,
7032
7032
  inputType,
@@ -7186,7 +7186,7 @@ var Label;
7186
7186
  var init_Label = __esm({
7187
7187
  "components/core/atoms/Label.tsx"() {
7188
7188
  init_cn();
7189
- Label = React90__default.forwardRef(
7189
+ Label = React93__default.forwardRef(
7190
7190
  ({ className, required, children, ...props }, ref) => {
7191
7191
  return /* @__PURE__ */ jsxs(
7192
7192
  "label",
@@ -7213,7 +7213,7 @@ var init_Textarea = __esm({
7213
7213
  "components/core/atoms/Textarea.tsx"() {
7214
7214
  init_cn();
7215
7215
  init_useEventBus();
7216
- Textarea = React90__default.forwardRef(
7216
+ Textarea = React93__default.forwardRef(
7217
7217
  ({ className, error, onChange, ...props }, ref) => {
7218
7218
  const eventBus = useEventBus();
7219
7219
  const handleChange = (e) => {
@@ -7452,7 +7452,7 @@ var init_Select = __esm({
7452
7452
  init_cn();
7453
7453
  init_Icon();
7454
7454
  init_useEventBus();
7455
- Select = React90__default.forwardRef(
7455
+ Select = React93__default.forwardRef(
7456
7456
  (props, _ref) => {
7457
7457
  const { multiple, searchable, clearable } = props;
7458
7458
  if (multiple || searchable || clearable) {
@@ -7469,7 +7469,7 @@ var init_Checkbox = __esm({
7469
7469
  "components/core/atoms/Checkbox.tsx"() {
7470
7470
  init_cn();
7471
7471
  init_useEventBus();
7472
- Checkbox = React90__default.forwardRef(
7472
+ Checkbox = React93__default.forwardRef(
7473
7473
  ({ className, label, id, onChange, ...props }, ref) => {
7474
7474
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
7475
7475
  const eventBus = useEventBus();
@@ -7523,7 +7523,7 @@ var init_Spinner = __esm({
7523
7523
  md: "h-6 w-6",
7524
7524
  lg: "h-8 w-8"
7525
7525
  };
7526
- Spinner = React90__default.forwardRef(
7526
+ Spinner = React93__default.forwardRef(
7527
7527
  ({ className, size = "md", overlay, ...props }, ref) => {
7528
7528
  if (overlay) {
7529
7529
  return /* @__PURE__ */ jsx(
@@ -7613,7 +7613,7 @@ var init_Card = __esm({
7613
7613
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
7614
7614
  "tile-image-first": "p-0 overflow-hidden"
7615
7615
  };
7616
- Card = React90__default.forwardRef(
7616
+ Card = React93__default.forwardRef(
7617
7617
  ({
7618
7618
  className,
7619
7619
  variant = "bordered",
@@ -7661,9 +7661,9 @@ var init_Card = __esm({
7661
7661
  }
7662
7662
  );
7663
7663
  Card.displayName = "Card";
7664
- CardHeader = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
7664
+ CardHeader = React93__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
7665
7665
  CardHeader.displayName = "CardHeader";
7666
- CardTitle = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7666
+ CardTitle = React93__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7667
7667
  "h3",
7668
7668
  {
7669
7669
  ref,
@@ -7676,11 +7676,11 @@ var init_Card = __esm({
7676
7676
  }
7677
7677
  ));
7678
7678
  CardTitle.displayName = "CardTitle";
7679
- CardContent = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
7679
+ CardContent = React93__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
7680
7680
  CardContent.displayName = "CardContent";
7681
7681
  CardBody = CardContent;
7682
7682
  CardBody.displayName = "CardBody";
7683
- CardFooter = React90__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7683
+ CardFooter = React93__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
7684
7684
  "div",
7685
7685
  {
7686
7686
  ref,
@@ -7735,7 +7735,7 @@ var init_FilterPill = __esm({
7735
7735
  md: "w-3.5 h-3.5",
7736
7736
  lg: "w-4 h-4"
7737
7737
  };
7738
- FilterPill = React90__default.forwardRef(
7738
+ FilterPill = React93__default.forwardRef(
7739
7739
  ({
7740
7740
  className,
7741
7741
  variant = "default",
@@ -7864,8 +7864,8 @@ var init_Avatar = __esm({
7864
7864
  actionPayload
7865
7865
  }) => {
7866
7866
  const eventBus = useEventBus();
7867
- const [imgFailed, setImgFailed] = React90__default.useState(false);
7868
- React90__default.useEffect(() => {
7867
+ const [imgFailed, setImgFailed] = React93__default.useState(false);
7868
+ React93__default.useEffect(() => {
7869
7869
  setImgFailed(false);
7870
7870
  }, [src]);
7871
7871
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -8250,7 +8250,7 @@ var init_Radio = __esm({
8250
8250
  md: "w-2.5 h-2.5",
8251
8251
  lg: "w-3 h-3"
8252
8252
  };
8253
- Radio = React90__default.forwardRef(
8253
+ Radio = React93__default.forwardRef(
8254
8254
  ({
8255
8255
  label,
8256
8256
  helperText,
@@ -8267,12 +8267,12 @@ var init_Radio = __esm({
8267
8267
  onChange,
8268
8268
  ...props
8269
8269
  }, ref) => {
8270
- const reactId = React90__default.useId();
8270
+ const reactId = React93__default.useId();
8271
8271
  const baseId = id || `radio-${reactId}`;
8272
8272
  const hasError = !!error;
8273
8273
  const eventBus = useEventBus();
8274
- const [selected, setSelected] = React90__default.useState(value);
8275
- React90__default.useEffect(() => {
8274
+ const [selected, setSelected] = React93__default.useState(value);
8275
+ React93__default.useEffect(() => {
8276
8276
  if (value !== void 0) setSelected(value);
8277
8277
  }, [value]);
8278
8278
  const pick = (next, e) => {
@@ -8454,7 +8454,7 @@ var init_Switch = __esm({
8454
8454
  "components/core/atoms/Switch.tsx"() {
8455
8455
  "use client";
8456
8456
  init_cn();
8457
- Switch = React90.forwardRef(
8457
+ Switch = React93.forwardRef(
8458
8458
  ({
8459
8459
  checked,
8460
8460
  defaultChecked = false,
@@ -8465,10 +8465,10 @@ var init_Switch = __esm({
8465
8465
  name,
8466
8466
  className
8467
8467
  }, ref) => {
8468
- const [isChecked, setIsChecked] = React90.useState(
8468
+ const [isChecked, setIsChecked] = React93.useState(
8469
8469
  checked !== void 0 ? checked : defaultChecked
8470
8470
  );
8471
- React90.useEffect(() => {
8471
+ React93.useEffect(() => {
8472
8472
  if (checked !== void 0) {
8473
8473
  setIsChecked(checked);
8474
8474
  }
@@ -8737,7 +8737,7 @@ var Aside;
8737
8737
  var init_Aside = __esm({
8738
8738
  "components/core/atoms/Aside.tsx"() {
8739
8739
  init_cn();
8740
- Aside = React90__default.forwardRef(
8740
+ Aside = React93__default.forwardRef(
8741
8741
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
8742
8742
  );
8743
8743
  Aside.displayName = "Aside";
@@ -8815,8 +8815,8 @@ var init_LawReferenceTooltip = __esm({
8815
8815
  className
8816
8816
  }) => {
8817
8817
  const { t } = useTranslate();
8818
- const [isVisible, setIsVisible] = React90__default.useState(false);
8819
- const timeoutRef = React90__default.useRef(null);
8818
+ const [isVisible, setIsVisible] = React93__default.useState(false);
8819
+ const timeoutRef = React93__default.useRef(null);
8820
8820
  const handleMouseEnter = () => {
8821
8821
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
8822
8822
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -8825,7 +8825,7 @@ var init_LawReferenceTooltip = __esm({
8825
8825
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
8826
8826
  setIsVisible(false);
8827
8827
  };
8828
- React90__default.useEffect(() => {
8828
+ React93__default.useEffect(() => {
8829
8829
  return () => {
8830
8830
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
8831
8831
  };
@@ -9035,7 +9035,7 @@ var init_StatusDot = __esm({
9035
9035
  md: "w-2.5 h-2.5",
9036
9036
  lg: "w-3 h-3"
9037
9037
  };
9038
- StatusDot = React90__default.forwardRef(
9038
+ StatusDot = React93__default.forwardRef(
9039
9039
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
9040
9040
  return /* @__PURE__ */ jsx(
9041
9041
  "span",
@@ -9089,7 +9089,7 @@ var init_TrendIndicator = __esm({
9089
9089
  down: "trending-down",
9090
9090
  flat: "arrow-right"
9091
9091
  };
9092
- TrendIndicator = React90__default.forwardRef(
9092
+ TrendIndicator = React93__default.forwardRef(
9093
9093
  ({
9094
9094
  className,
9095
9095
  value,
@@ -9156,7 +9156,7 @@ var init_RangeSlider = __esm({
9156
9156
  md: "w-4 h-4",
9157
9157
  lg: "w-5 h-5"
9158
9158
  };
9159
- RangeSlider = React90__default.forwardRef(
9159
+ RangeSlider = React93__default.forwardRef(
9160
9160
  ({
9161
9161
  className,
9162
9162
  min = 0,
@@ -9664,7 +9664,7 @@ var init_ContentSection = __esm({
9664
9664
  md: "py-16",
9665
9665
  lg: "py-24"
9666
9666
  };
9667
- ContentSection = React90__default.forwardRef(
9667
+ ContentSection = React93__default.forwardRef(
9668
9668
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
9669
9669
  return /* @__PURE__ */ jsx(
9670
9670
  Box,
@@ -10198,7 +10198,7 @@ var init_AnimatedReveal = __esm({
10198
10198
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
10199
10199
  "none": {}
10200
10200
  };
10201
- AnimatedReveal = React90__default.forwardRef(
10201
+ AnimatedReveal = React93__default.forwardRef(
10202
10202
  ({
10203
10203
  trigger = "scroll",
10204
10204
  animation = "fade-up",
@@ -10358,7 +10358,7 @@ var init_AnimatedGraphic = __esm({
10358
10358
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
10359
10359
  "use client";
10360
10360
  init_cn();
10361
- AnimatedGraphic = React90__default.forwardRef(
10361
+ AnimatedGraphic = React93__default.forwardRef(
10362
10362
  ({
10363
10363
  src,
10364
10364
  svgContent,
@@ -10381,7 +10381,7 @@ var init_AnimatedGraphic = __esm({
10381
10381
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
10382
10382
  const resolvedSvg = svgContent ?? fetchedSvg;
10383
10383
  const prevAnimateRef = useRef(animate);
10384
- const setRef = React90__default.useCallback(
10384
+ const setRef = React93__default.useCallback(
10385
10385
  (node) => {
10386
10386
  containerRef.current = node;
10387
10387
  if (typeof ref === "function") ref(node);
@@ -10607,9 +10607,9 @@ function ScoreDisplay({
10607
10607
  ...rest
10608
10608
  }) {
10609
10609
  const resolvedValue = typeof value === "number" && !Number.isNaN(value) ? value : typeof rest.score === "number" && !Number.isNaN(rest.score) ? rest.score : 0;
10610
- const [displayValue, setDisplayValue] = React90.useState(resolvedValue);
10611
- const [isAnimating, setIsAnimating] = React90.useState(false);
10612
- React90.useEffect(() => {
10610
+ const [displayValue, setDisplayValue] = React93.useState(resolvedValue);
10611
+ const [isAnimating, setIsAnimating] = React93.useState(false);
10612
+ React93.useEffect(() => {
10613
10613
  if (!animated || displayValue === resolvedValue) {
10614
10614
  setDisplayValue(resolvedValue);
10615
10615
  return;
@@ -10692,9 +10692,9 @@ function ControlButton({
10692
10692
  className
10693
10693
  }) {
10694
10694
  const eventBus = useEventBus();
10695
- const [isPressed, setIsPressed] = React90.useState(false);
10695
+ const [isPressed, setIsPressed] = React93.useState(false);
10696
10696
  const actualPressed = pressed ?? isPressed;
10697
- const handlePointerDown = React90.useCallback(
10697
+ const handlePointerDown = React93.useCallback(
10698
10698
  (e) => {
10699
10699
  e.preventDefault();
10700
10700
  if (disabled) return;
@@ -10704,7 +10704,7 @@ function ControlButton({
10704
10704
  },
10705
10705
  [disabled, pressEvent, eventBus, onPress]
10706
10706
  );
10707
- const handlePointerUp = React90.useCallback(
10707
+ const handlePointerUp = React93.useCallback(
10708
10708
  (e) => {
10709
10709
  e.preventDefault();
10710
10710
  if (disabled) return;
@@ -10714,7 +10714,7 @@ function ControlButton({
10714
10714
  },
10715
10715
  [disabled, releaseEvent, eventBus, onRelease]
10716
10716
  );
10717
- const handlePointerLeave = React90.useCallback(
10717
+ const handlePointerLeave = React93.useCallback(
10718
10718
  (e) => {
10719
10719
  if (isPressed) {
10720
10720
  setIsPressed(false);
@@ -11335,8 +11335,8 @@ function XPBar({
11335
11335
  }) {
11336
11336
  const sizes = sizeMap9[size];
11337
11337
  const percentage = max > 0 ? Math.max(0, Math.min(100, current / max * 100)) : 0;
11338
- const [fillWidth, setFillWidth] = React90.useState(animated ? 0 : percentage);
11339
- React90.useEffect(() => {
11338
+ const [fillWidth, setFillWidth] = React93.useState(animated ? 0 : percentage);
11339
+ React93.useEffect(() => {
11340
11340
  if (!animated) {
11341
11341
  setFillWidth(percentage);
11342
11342
  return;
@@ -11824,9 +11824,9 @@ function MiniMap({
11824
11824
  viewportRect = DEFAULT_VIEWPORT,
11825
11825
  className
11826
11826
  }) {
11827
- const canvasRef = React90.useRef(null);
11828
- const frameRef = React90.useRef(0);
11829
- React90.useEffect(() => {
11827
+ const canvasRef = React93.useRef(null);
11828
+ const frameRef = React93.useRef(0);
11829
+ React93.useEffect(() => {
11830
11830
  const canvas = canvasRef.current;
11831
11831
  if (!canvas) return;
11832
11832
  const ctx = canvas.getContext("2d");
@@ -12015,7 +12015,7 @@ var init_ErrorBoundary = __esm({
12015
12015
  }
12016
12016
  );
12017
12017
  };
12018
- ErrorBoundary = class extends React90__default.Component {
12018
+ ErrorBoundary = class extends React93__default.Component {
12019
12019
  constructor(props) {
12020
12020
  super(props);
12021
12021
  __publicField(this, "reset", () => {
@@ -12160,16 +12160,6 @@ var init_Skeleton = __esm({
12160
12160
  Skeleton.displayName = "Skeleton";
12161
12161
  }
12162
12162
  });
12163
- function isKnownPattern(type) {
12164
- return type in componentMapping;
12165
- }
12166
- var componentMapping;
12167
- var init_pattern_resolver = __esm({
12168
- "renderer/pattern-resolver.ts"() {
12169
- createLogger("almadar:ui:pattern-resolver");
12170
- componentMapping = {};
12171
- }
12172
- });
12173
12163
 
12174
12164
  // renderer/slot-definitions.ts
12175
12165
  function isPortalSlot(slot) {
@@ -12278,7 +12268,6 @@ var init_navigation = __esm({
12278
12268
  // renderer/index.ts
12279
12269
  var init_renderer = __esm({
12280
12270
  "renderer/index.ts"() {
12281
- init_pattern_resolver();
12282
12271
  init_slot_definitions();
12283
12272
  }
12284
12273
  });
@@ -13061,8 +13050,8 @@ function ActionButtons({
13061
13050
  disabled
13062
13051
  }) {
13063
13052
  const eventBus = useEventBus();
13064
- const [activeButtons, setActiveButtons] = React90.useState(/* @__PURE__ */ new Set());
13065
- const handlePress = React90.useCallback(
13053
+ const [activeButtons, setActiveButtons] = React93.useState(/* @__PURE__ */ new Set());
13054
+ const handlePress = React93.useCallback(
13066
13055
  (id) => {
13067
13056
  setActiveButtons((prev) => new Set(prev).add(id));
13068
13057
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -13070,7 +13059,7 @@ function ActionButtons({
13070
13059
  },
13071
13060
  [actionEvent, eventBus, onAction]
13072
13061
  );
13073
- const handleRelease = React90.useCallback(
13062
+ const handleRelease = React93.useCallback(
13074
13063
  (id) => {
13075
13064
  setActiveButtons((prev) => {
13076
13065
  const next = new Set(prev);
@@ -13707,8 +13696,8 @@ var init_AnimatedCounter = __esm({
13707
13696
  const [displayValue, setDisplayValue] = useState("0");
13708
13697
  const [hasAnimated, setHasAnimated] = useState(false);
13709
13698
  const animate = useCallback(() => {
13710
- const { num: num2, prefix, suffix, decimals } = parseValue(value);
13711
- if (num2 === 0) {
13699
+ const { num: num3, prefix, suffix, decimals } = parseValue(value);
13700
+ if (num3 === 0) {
13712
13701
  setDisplayValue(String(value));
13713
13702
  return;
13714
13703
  }
@@ -13717,7 +13706,7 @@ var init_AnimatedCounter = __esm({
13717
13706
  const elapsed = now2 - startTime;
13718
13707
  const progress = Math.min(elapsed / duration, 1);
13719
13708
  const eased = 1 - Math.pow(1 - progress, 3);
13720
- const current = eased * num2;
13709
+ const current = eased * num3;
13721
13710
  setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
13722
13711
  if (progress < 1) {
13723
13712
  requestAnimationFrame(tick);
@@ -13982,7 +13971,7 @@ function recordTransition(trace) {
13982
13971
  ...trace,
13983
13972
  id: `t-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
13984
13973
  };
13985
- log5.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
13974
+ log4.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
13986
13975
  getState().transitions.push(entry);
13987
13976
  if (getState().transitions.length > MAX_TRANSITIONS) {
13988
13977
  getState().transitions.shift();
@@ -14081,7 +14070,7 @@ function getTraitSnapshots() {
14081
14070
  try {
14082
14071
  snapshots.push(getter());
14083
14072
  } catch (err) {
14084
- log5.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
14073
+ log4.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
14085
14074
  }
14086
14075
  }
14087
14076
  return snapshots;
@@ -14180,10 +14169,10 @@ function updateAssetStatus(url, status) {
14180
14169
  window.__orbitalVerification.assetStatus[url] = status;
14181
14170
  }
14182
14171
  }
14183
- var log5, MAX_TRANSITIONS;
14172
+ var log4, MAX_TRANSITIONS;
14184
14173
  var init_verificationRegistry = __esm({
14185
14174
  "lib/verificationRegistry.ts"() {
14186
- log5 = createLogger("almadar:bridge");
14175
+ log4 = createLogger("almadar:bridge");
14187
14176
  MAX_TRANSITIONS = 500;
14188
14177
  exposeOnWindow();
14189
14178
  }
@@ -14547,7 +14536,7 @@ function IsometricCanvas({
14547
14536
  // Tuning
14548
14537
  diamondTopY: diamondTopYProp,
14549
14538
  // Remote asset loading
14550
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
14539
+ assetBaseUrl,
14551
14540
  assetManifest
14552
14541
  }) {
14553
14542
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
@@ -14626,7 +14615,7 @@ function IsometricCanvas({
14626
14615
  const attackTargetSet = useMemo(() => {
14627
14616
  return new Set(attackTargets.map((p2) => `${p2.x},${p2.y}`));
14628
14617
  }, [attackTargets]);
14629
- const resolveManifestUrl = useCallback((relativePath) => {
14618
+ const resolveManifestUrl7 = useCallback((relativePath) => {
14630
14619
  if (!relativePath) return void 0;
14631
14620
  if (assetBaseUrl) return `${assetBaseUrl.replace(/\/$/, "")}${relativePath.startsWith("/") ? "" : "/"}${relativePath}`;
14632
14621
  return relativePath;
@@ -14639,7 +14628,7 @@ function IsometricCanvas({
14639
14628
  const url = getTerrainSprite(tile.terrain ?? "");
14640
14629
  if (url) urls.push(url);
14641
14630
  } else {
14642
- const url = resolveManifestUrl(assetManifest?.terrains?.[tile.terrain ?? ""]);
14631
+ const url = resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
14643
14632
  if (url) urls.push(url);
14644
14633
  }
14645
14634
  }
@@ -14649,7 +14638,7 @@ function IsometricCanvas({
14649
14638
  const url = getFeatureSprite(feature.type);
14650
14639
  if (url) urls.push(url);
14651
14640
  } else {
14652
- const url = resolveManifestUrl(assetManifest?.features?.[feature.type]);
14641
+ const url = resolveManifestUrl7(assetManifest?.features?.[feature.type]);
14653
14642
  if (url) urls.push(url);
14654
14643
  }
14655
14644
  }
@@ -14659,13 +14648,13 @@ function IsometricCanvas({
14659
14648
  const url = getUnitSprite(unit);
14660
14649
  if (url) urls.push(url);
14661
14650
  } else if (unit.unitType) {
14662
- const url = resolveManifestUrl(assetManifest?.units?.[unit.unitType]);
14651
+ const url = resolveManifestUrl7(assetManifest?.units?.[unit.unitType]);
14663
14652
  if (url) urls.push(url);
14664
14653
  }
14665
14654
  }
14666
14655
  if (assetManifest?.effects) {
14667
14656
  for (const path of Object.values(assetManifest.effects)) {
14668
- const url = resolveManifestUrl(path);
14657
+ const url = resolveManifestUrl7(path);
14669
14658
  if (url) urls.push(url);
14670
14659
  }
14671
14660
  }
@@ -14673,7 +14662,7 @@ function IsometricCanvas({
14673
14662
  if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
14674
14663
  if (backgroundImage) urls.push(backgroundImage);
14675
14664
  return [...new Set(urls.filter(Boolean))];
14676
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl]);
14665
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl7]);
14677
14666
  const { getImage, pendingCount } = useImageCache(spriteUrls);
14678
14667
  useEffect(() => {
14679
14668
  if (typeof window === "undefined") return;
@@ -14697,14 +14686,14 @@ function IsometricCanvas({
14697
14686
  lerpToTarget
14698
14687
  } = useCamera();
14699
14688
  const resolveTerrainSpriteUrl = useCallback((tile) => {
14700
- return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl(assetManifest?.terrains?.[tile.terrain ?? ""]);
14701
- }, [getTerrainSprite, assetManifest, resolveManifestUrl]);
14689
+ return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
14690
+ }, [getTerrainSprite, assetManifest, resolveManifestUrl7]);
14702
14691
  const resolveFeatureSpriteUrl = useCallback((featureType) => {
14703
- return getFeatureSprite?.(featureType) || resolveManifestUrl(assetManifest?.features?.[featureType]);
14704
- }, [getFeatureSprite, assetManifest, resolveManifestUrl]);
14692
+ return getFeatureSprite?.(featureType) || resolveManifestUrl7(assetManifest?.features?.[featureType]);
14693
+ }, [getFeatureSprite, assetManifest, resolveManifestUrl7]);
14705
14694
  const resolveUnitSpriteUrl = useCallback((unit) => {
14706
- return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl(assetManifest?.units?.[unit.unitType]) : void 0);
14707
- }, [getUnitSprite, assetManifest, resolveManifestUrl]);
14695
+ return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl7(assetManifest?.units?.[unit.unitType]) : void 0);
14696
+ }, [getUnitSprite, assetManifest, resolveManifestUrl7]);
14708
14697
  const drawMinimap = useCallback(() => {
14709
14698
  if (!showMinimap) return;
14710
14699
  const miniCanvas = minimapRef.current;
@@ -14806,7 +14795,15 @@ function IsometricCanvas({
14806
14795
  const spriteUrl = resolveTerrainSpriteUrl(tile);
14807
14796
  const img = spriteUrl ? getImage(spriteUrl) : null;
14808
14797
  if (img) {
14809
- ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
14798
+ if (img.naturalWidth === 0) {
14799
+ ctx.drawImage(img, pos.x, pos.y, scaledTileWidth, scaledTileHeight);
14800
+ } else {
14801
+ const drawW = scaledTileWidth;
14802
+ const drawH = scaledTileWidth * (img.naturalHeight / img.naturalWidth);
14803
+ const drawX = pos.x;
14804
+ const drawY = pos.y + scaledTileHeight - drawH;
14805
+ ctx.drawImage(img, drawX, drawY, drawW, drawH);
14806
+ }
14810
14807
  } else {
14811
14808
  const centerX = pos.x + scaledTileWidth / 2;
14812
14809
  const topY = pos.y + scaledDiamondTopY;
@@ -16114,7 +16111,7 @@ function generateDiff(oldVal, newVal) {
16114
16111
  }
16115
16112
  return diff;
16116
16113
  }
16117
- var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log6, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
16114
+ var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log5, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
16118
16115
  var init_CodeBlock = __esm({
16119
16116
  "components/core/molecules/markdown/CodeBlock.tsx"() {
16120
16117
  init_cn();
@@ -16197,7 +16194,7 @@ var init_CodeBlock = __esm({
16197
16194
  "lolo-op-async": { color: ORB_COLORS.dark.async }
16198
16195
  };
16199
16196
  loloStyle = { ...dark, ...loloStyleOverrides };
16200
- log6 = createLogger("almadar:ui:markdown-code");
16197
+ log5 = createLogger("almadar:ui:markdown-code");
16201
16198
  CODE_LANGUAGES = [
16202
16199
  "text",
16203
16200
  "json",
@@ -16236,7 +16233,7 @@ var init_CodeBlock = __esm({
16236
16233
  };
16237
16234
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
16238
16235
  HIDDEN_LINE_NUMBERS = { display: "none" };
16239
- CodeBlock = React90__default.memo(
16236
+ CodeBlock = React93__default.memo(
16240
16237
  ({
16241
16238
  code: rawCode,
16242
16239
  language = "text",
@@ -16405,24 +16402,24 @@ var init_CodeBlock = __esm({
16405
16402
  return;
16406
16403
  }
16407
16404
  lineEls.forEach((el) => {
16408
- const num2 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
16409
- if (hiddenLines.has(num2)) {
16405
+ const num3 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
16406
+ if (hiddenLines.has(num3)) {
16410
16407
  el.style.display = "none";
16411
16408
  return;
16412
16409
  }
16413
16410
  el.style.display = "";
16414
16411
  el.style.position = "relative";
16415
16412
  el.style.paddingLeft = "1.2em";
16416
- const region = foldStartMap.get(num2);
16413
+ const region = foldStartMap.get(num3);
16417
16414
  if (!region) return;
16418
- const isCollapsed = collapsed.has(num2);
16415
+ const isCollapsed = collapsed.has(num3);
16419
16416
  const toggle = document.createElement("span");
16420
16417
  toggle.className = "fold-toggle";
16421
16418
  toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
16422
16419
  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%";
16423
16420
  toggle.addEventListener("click", (e) => {
16424
16421
  e.stopPropagation();
16425
- toggleFoldRef.current(num2);
16422
+ toggleFoldRef.current(num3);
16426
16423
  });
16427
16424
  el.insertBefore(toggle, el.firstChild);
16428
16425
  if (isCollapsed) {
@@ -16461,7 +16458,7 @@ var init_CodeBlock = __esm({
16461
16458
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: true });
16462
16459
  setTimeout(() => setCopied(false), 2e3);
16463
16460
  } catch (err) {
16464
- log6.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
16461
+ log5.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
16465
16462
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: false });
16466
16463
  }
16467
16464
  };
@@ -16823,7 +16820,7 @@ var init_MarkdownContent = __esm({
16823
16820
  init_Box();
16824
16821
  init_CodeBlock();
16825
16822
  init_cn();
16826
- MarkdownContent = React90__default.memo(
16823
+ MarkdownContent = React93__default.memo(
16827
16824
  ({ content, direction = "ltr", className }) => {
16828
16825
  const { t: _t } = useTranslate();
16829
16826
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -18140,7 +18137,7 @@ var init_StateMachineView = __esm({
18140
18137
  style: { top: title ? 30 : 0 },
18141
18138
  children: [
18142
18139
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
18143
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React90__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
18140
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React93__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
18144
18141
  StateNode,
18145
18142
  {
18146
18143
  state,
@@ -20342,14 +20339,14 @@ function useSafeEventBus2() {
20342
20339
  } };
20343
20340
  }
20344
20341
  }
20345
- var log7, lookStyles4, ButtonGroup;
20342
+ var log6, lookStyles4, ButtonGroup;
20346
20343
  var init_ButtonGroup = __esm({
20347
20344
  "components/core/molecules/ButtonGroup.tsx"() {
20348
20345
  "use client";
20349
20346
  init_cn();
20350
20347
  init_atoms2();
20351
20348
  init_useEventBus();
20352
- log7 = createLogger("almadar:ui:button-group");
20349
+ log6 = createLogger("almadar:ui:button-group");
20353
20350
  lookStyles4 = {
20354
20351
  "right-aligned-buttons": "",
20355
20352
  "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
@@ -20430,7 +20427,7 @@ var init_ButtonGroup = __esm({
20430
20427
  {
20431
20428
  variant: "ghost",
20432
20429
  onClick: () => {
20433
- log7.debug("Filter clicked", { field: filter.field });
20430
+ log6.debug("Filter clicked", { field: filter.field });
20434
20431
  },
20435
20432
  children: filter.label
20436
20433
  },
@@ -22041,8 +22038,8 @@ function EmojiEffect({
22041
22038
  );
22042
22039
  }
22043
22040
  function CanvasEffect({
22044
- effectSpriteUrl = "https://almadar-kflow-assets.web.app/shared/effects/gas/gas00.png",
22045
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/effects/",
22041
+ effectSpriteUrl,
22042
+ assetBaseUrl,
22046
22043
  ...props
22047
22044
  }) {
22048
22045
  const eventBus = useEventBus();
@@ -22085,6 +22082,380 @@ var init_CanvasEffect = __esm({
22085
22082
  CanvasEffect.displayName = "CanvasEffect";
22086
22083
  }
22087
22084
  });
22085
+ function CardHand({
22086
+ cards = DEFAULT_CARDS,
22087
+ selectedId = "",
22088
+ size = "md",
22089
+ onCardClick,
22090
+ cardClickEvent,
22091
+ emptyLabel = "No cards in hand",
22092
+ className
22093
+ }) {
22094
+ const eventBus = useEventBus();
22095
+ const handleClick = React93.useCallback(
22096
+ (card) => {
22097
+ if (card.disabled) return;
22098
+ onCardClick?.(card.id);
22099
+ if (cardClickEvent) {
22100
+ eventBus.emit(`UI:${cardClickEvent}`, { cardId: card.id });
22101
+ }
22102
+ },
22103
+ [onCardClick, cardClickEvent, eventBus]
22104
+ );
22105
+ if (cards.length === 0) {
22106
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex items-center justify-center p-4", className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: emptyLabel }) });
22107
+ }
22108
+ const art = artSizeMap[size];
22109
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex flex-wrap gap-2 justify-center items-end", className), children: cards.map((card) => {
22110
+ const selected = selectedId === card.id;
22111
+ return /* @__PURE__ */ jsxs(
22112
+ "button",
22113
+ {
22114
+ type: "button",
22115
+ onClick: () => handleClick(card),
22116
+ disabled: card.disabled,
22117
+ title: card.title,
22118
+ className: cn(
22119
+ "card-hand-card relative flex flex-col items-center rounded-interactive border-2",
22120
+ "bg-card/90 px-1.5 pt-1.5 pb-1 transition-all duration-150",
22121
+ cardSizeMap[size],
22122
+ card.disabled ? "border-border opacity-50 cursor-not-allowed" : "border-accent hover:brightness-125 hover:-translate-y-1 cursor-pointer",
22123
+ selected && "ring-2 ring-foreground ring-offset-1 ring-offset-background -translate-y-1"
22124
+ ),
22125
+ children: [
22126
+ card.cost != null && /* @__PURE__ */ jsx(
22127
+ "span",
22128
+ {
22129
+ className: cn(
22130
+ "absolute -top-2 -left-2 flex items-center justify-center",
22131
+ "min-w-[22px] h-[22px] rounded-full px-1",
22132
+ "bg-info text-foreground text-xs font-bold border border-background"
22133
+ ),
22134
+ children: card.cost
22135
+ }
22136
+ ),
22137
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: card.iconUrl ? /* @__PURE__ */ jsx(
22138
+ "img",
22139
+ {
22140
+ src: card.iconUrl,
22141
+ alt: card.title ?? card.id,
22142
+ width: art,
22143
+ height: art,
22144
+ style: { imageRendering: "pixelated", objectFit: "contain" },
22145
+ className: "flex-shrink-0"
22146
+ }
22147
+ ) : /* @__PURE__ */ jsx(
22148
+ Box,
22149
+ {
22150
+ className: "rounded bg-muted/40",
22151
+ style: { width: art, height: art }
22152
+ }
22153
+ ) }),
22154
+ card.title != null && /* @__PURE__ */ jsx(
22155
+ Typography,
22156
+ {
22157
+ variant: "small",
22158
+ className: "w-full truncate text-center text-[10px] leading-tight font-semibold",
22159
+ children: card.title
22160
+ }
22161
+ ),
22162
+ (card.attack != null || card.defense != null) && /* @__PURE__ */ jsxs(Box, { className: "flex w-full items-center justify-between px-0.5 text-[10px] font-bold leading-none", children: [
22163
+ /* @__PURE__ */ jsx("span", { className: "text-error", children: card.attack != null ? `\u2694${card.attack}` : "" }),
22164
+ /* @__PURE__ */ jsx("span", { className: "text-info", children: card.defense != null ? `\u{1F6E1}${card.defense}` : "" })
22165
+ ] })
22166
+ ]
22167
+ },
22168
+ card.id
22169
+ );
22170
+ }) });
22171
+ }
22172
+ var cardSizeMap, artSizeMap, DEFAULT_CARDS;
22173
+ var init_CardHand = __esm({
22174
+ "components/game/molecules/CardHand.tsx"() {
22175
+ "use client";
22176
+ init_cn();
22177
+ init_useEventBus();
22178
+ init_Box();
22179
+ init_Typography();
22180
+ cardSizeMap = {
22181
+ sm: "w-16 h-24",
22182
+ md: "w-20 h-28",
22183
+ lg: "w-24 h-36"
22184
+ };
22185
+ artSizeMap = {
22186
+ sm: 40,
22187
+ md: 52,
22188
+ lg: 64
22189
+ };
22190
+ DEFAULT_CARDS = [
22191
+ { id: "card-1", title: "Brawler", cost: 1, attack: 2, defense: 1 },
22192
+ { id: "card-2", title: "Guardian", cost: 2, attack: 1, defense: 4 },
22193
+ { id: "card-3", title: "Striker", cost: 3, attack: 5, defense: 2 }
22194
+ ];
22195
+ CardHand.displayName = "CardHand";
22196
+ }
22197
+ });
22198
+ function resolveManifestUrl(manifest, relative) {
22199
+ if (relative == null) return void 0;
22200
+ if (/^https?:\/\//.test(relative)) return relative;
22201
+ const base = manifest?.baseUrl;
22202
+ if (base == null) return relative;
22203
+ const cleanBase = base.replace(/\/$/, "");
22204
+ const cleanRel = relative.replace(/^\//, "");
22205
+ return `${cleanBase}/${cleanRel}`;
22206
+ }
22207
+ function rowToCard(r2) {
22208
+ return {
22209
+ id: str(r2.id),
22210
+ iconKey: r2.iconKey == null ? void 0 : str(r2.iconKey),
22211
+ title: r2.title == null ? void 0 : str(r2.title),
22212
+ cost: r2.cost == null ? void 0 : num(r2.cost),
22213
+ attack: r2.attack == null ? void 0 : num(r2.attack),
22214
+ defense: r2.defense == null ? void 0 : num(r2.defense)
22215
+ };
22216
+ }
22217
+ function toHandCards(cards, manifest, mana) {
22218
+ return cards.map((c) => {
22219
+ const key = c.iconKey ?? c.id;
22220
+ const iconUrl = resolveManifestUrl(manifest, manifest?.cards?.[key]);
22221
+ return {
22222
+ id: c.id,
22223
+ iconUrl,
22224
+ title: c.title,
22225
+ cost: c.cost,
22226
+ attack: c.attack,
22227
+ defense: c.defense,
22228
+ disabled: c.cost != null && c.cost > mana
22229
+ };
22230
+ });
22231
+ }
22232
+ function CardBattlerBoard({
22233
+ entity,
22234
+ deck: propDeck,
22235
+ hand: propHand,
22236
+ board: propBoard,
22237
+ mana: propMana,
22238
+ maxMana: propMaxMana,
22239
+ turn: propTurn,
22240
+ result: propResult,
22241
+ assetManifest: propAssetManifest,
22242
+ playCardEvent,
22243
+ endTurnEvent,
22244
+ playAgainEvent,
22245
+ gameEndEvent,
22246
+ className
22247
+ }) {
22248
+ const board = boardEntity(entity) ?? {};
22249
+ const eventBus = useEventBus();
22250
+ const { t } = useTranslate();
22251
+ const assetManifest = propAssetManifest ?? board.assetManifest;
22252
+ const entityHand = useMemo(() => rows(board.hand).map(rowToCard), [board.hand]);
22253
+ const rawHand = propHand ?? entityHand;
22254
+ const hand = rawHand.length > 0 ? rawHand : DEFAULT_HAND;
22255
+ const entityBoard = useMemo(() => rows(board.board).map(rowToCard), [board.board]);
22256
+ const playedCards = propBoard ?? entityBoard;
22257
+ const entityDeck = useMemo(() => rows(board.deck).map(rowToCard), [board.deck]);
22258
+ const deck = propDeck ?? entityDeck;
22259
+ const mana = propMana ?? num(board.mana, 3);
22260
+ const maxMana = propMaxMana ?? num(board.maxMana, 3);
22261
+ const turn = propTurn ?? num(board.turn, 1);
22262
+ const result = propResult ?? (str(board.result) || "none");
22263
+ const handCards = useMemo(() => toHandCards(hand, assetManifest, mana), [hand, assetManifest, mana]);
22264
+ const boardCards = useMemo(() => toHandCards(playedCards, assetManifest, mana), [playedCards, assetManifest, mana]);
22265
+ const emittedGameEnd = useRef(false);
22266
+ if (result !== "none" && !emittedGameEnd.current) {
22267
+ emittedGameEnd.current = true;
22268
+ if (gameEndEvent) {
22269
+ eventBus.emit(`UI:${gameEndEvent}`, { result });
22270
+ }
22271
+ }
22272
+ if (result === "none") {
22273
+ emittedGameEnd.current = false;
22274
+ }
22275
+ const handlePlayCard = useCallback((cardId) => {
22276
+ if (result !== "none") return;
22277
+ if (playCardEvent) {
22278
+ eventBus.emit(`UI:${playCardEvent}`, { cardId });
22279
+ }
22280
+ }, [result, playCardEvent, eventBus]);
22281
+ const handleEndTurn = useCallback(() => {
22282
+ if (result !== "none") return;
22283
+ if (endTurnEvent) {
22284
+ eventBus.emit(`UI:${endTurnEvent}`, {});
22285
+ }
22286
+ }, [result, endTurnEvent, eventBus]);
22287
+ const handlePlayAgain = useCallback(() => {
22288
+ if (playAgainEvent) {
22289
+ eventBus.emit(`UI:${playAgainEvent}`, {});
22290
+ }
22291
+ }, [playAgainEvent, eventBus]);
22292
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("card-battler-board relative min-h-[600px] bg-background", className), gap: "none", children: [
22293
+ /* @__PURE__ */ jsxs(
22294
+ HStack,
22295
+ {
22296
+ className: "px-4 py-2 border-b border-border bg-surface",
22297
+ gap: "lg",
22298
+ align: "center",
22299
+ children: [
22300
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
22301
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.mana") ?? "Mana" }),
22302
+ /* @__PURE__ */ jsxs(Typography, { variant: "body2", weight: "bold", className: "text-info", children: [
22303
+ mana,
22304
+ " / ",
22305
+ maxMana
22306
+ ] })
22307
+ ] }),
22308
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
22309
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.turn") ?? "Turn" }),
22310
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: turn })
22311
+ ] }),
22312
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
22313
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.deck") ?? "Deck" }),
22314
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: deck.length })
22315
+ ] }),
22316
+ /* @__PURE__ */ jsx(Box, { className: "ml-auto", children: result === "none" && /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: handleEndTurn, children: t("cb.endTurn") ?? "End Turn" }) })
22317
+ ]
22318
+ }
22319
+ ),
22320
+ /* @__PURE__ */ jsxs(Box, { className: "flex-1 relative p-4 overflow-auto", children: [
22321
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", className: "mb-2 uppercase tracking-wide", children: t("cb.battlefield") ?? "Battlefield" }),
22322
+ boardCards.length > 0 ? /* @__PURE__ */ jsx(
22323
+ CardHand,
22324
+ {
22325
+ cards: boardCards,
22326
+ size: "md",
22327
+ className: "justify-start"
22328
+ }
22329
+ ) : /* @__PURE__ */ jsx(Box, { className: "flex items-center justify-center h-32 rounded-interactive border-2 border-dashed border-border", children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.emptyBoard") ?? "Play a card to begin" }) })
22330
+ ] }),
22331
+ /* @__PURE__ */ jsxs(Box, { className: "border-t border-border bg-surface px-4 py-3", children: [
22332
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", className: "mb-2 uppercase tracking-wide", children: t("cb.hand") ?? "Your Hand" }),
22333
+ /* @__PURE__ */ jsx(
22334
+ CardHand,
22335
+ {
22336
+ cards: handCards,
22337
+ size: "lg",
22338
+ onCardClick: handlePlayCard,
22339
+ emptyLabel: t("cb.emptyHand") ?? "No cards in hand"
22340
+ }
22341
+ )
22342
+ ] }),
22343
+ result !== "none" && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
22344
+ /* @__PURE__ */ jsx(
22345
+ Typography,
22346
+ {
22347
+ variant: "h2",
22348
+ className: cn(
22349
+ "text-4xl font-black tracking-widest uppercase",
22350
+ result === "won" ? "text-warning" : "text-error"
22351
+ ),
22352
+ children: result === "won" ? t("cb.victory") ?? "Victory!" : t("cb.defeat") ?? "Defeat!"
22353
+ }
22354
+ ),
22355
+ /* @__PURE__ */ jsx(
22356
+ Button,
22357
+ {
22358
+ variant: "primary",
22359
+ className: "px-8 py-3 font-semibold",
22360
+ onClick: handlePlayAgain,
22361
+ children: t("cb.playAgain") ?? "Play Again"
22362
+ }
22363
+ )
22364
+ ] }) })
22365
+ ] });
22366
+ }
22367
+ var DEFAULT_HAND;
22368
+ var init_CardBattlerBoard = __esm({
22369
+ "components/game/organisms/CardBattlerBoard.tsx"() {
22370
+ "use client";
22371
+ init_cn();
22372
+ init_useEventBus();
22373
+ init_Box();
22374
+ init_Button();
22375
+ init_Typography();
22376
+ init_Stack();
22377
+ init_CardHand();
22378
+ init_boardEntity();
22379
+ DEFAULT_HAND = [
22380
+ { id: "c1", iconKey: "bear", title: "Bear", cost: 3, attack: 5, defense: 4 },
22381
+ { id: "c2", iconKey: "owl", title: "Owl", cost: 1, attack: 2, defense: 1 },
22382
+ { id: "c3", iconKey: "gorilla", title: "Gorilla", cost: 4, attack: 6, defense: 5 },
22383
+ { id: "c4", iconKey: "frog", title: "Frog", cost: 1, attack: 1, defense: 2 },
22384
+ { id: "c5", iconKey: "snake", title: "Snake", cost: 2, attack: 4, defense: 1 }
22385
+ ];
22386
+ CardBattlerBoard.displayName = "CardBattlerBoard";
22387
+ }
22388
+ });
22389
+ function isEntityRow(value) {
22390
+ return value != null && typeof value === "object" && !Array.isArray(value);
22391
+ }
22392
+ function CardBattlerTemplate({
22393
+ entity,
22394
+ title = "Card Battler",
22395
+ deck,
22396
+ hand,
22397
+ board,
22398
+ mana,
22399
+ maxMana,
22400
+ turn,
22401
+ result,
22402
+ assetManifest,
22403
+ playCardEvent,
22404
+ endTurnEvent,
22405
+ playAgainEvent,
22406
+ gameEndEvent,
22407
+ className
22408
+ }) {
22409
+ const resolved = isEntityRow(entity) ? entity : void 0;
22410
+ return /* @__PURE__ */ jsxs(
22411
+ Box,
22412
+ {
22413
+ display: "flex",
22414
+ fullHeight: true,
22415
+ className: cn("card-battler-template flex-col", className),
22416
+ children: [
22417
+ /* @__PURE__ */ jsx(
22418
+ HStack,
22419
+ {
22420
+ gap: "sm",
22421
+ align: "center",
22422
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
22423
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
22424
+ }
22425
+ ),
22426
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
22427
+ CardBattlerBoard,
22428
+ {
22429
+ entity: resolved,
22430
+ deck,
22431
+ hand,
22432
+ board,
22433
+ mana,
22434
+ maxMana,
22435
+ turn,
22436
+ result,
22437
+ assetManifest,
22438
+ playCardEvent,
22439
+ endTurnEvent,
22440
+ playAgainEvent,
22441
+ gameEndEvent,
22442
+ className: "h-full"
22443
+ }
22444
+ ) })
22445
+ ]
22446
+ }
22447
+ );
22448
+ }
22449
+ var init_CardBattlerTemplate = __esm({
22450
+ "components/game/templates/CardBattlerTemplate.tsx"() {
22451
+ init_cn();
22452
+ init_Box();
22453
+ init_Stack();
22454
+ init_Typography();
22455
+ init_CardBattlerBoard();
22456
+ CardBattlerTemplate.displayName = "CardBattlerTemplate";
22457
+ }
22458
+ });
22088
22459
 
22089
22460
  // lib/getNestedValue.ts
22090
22461
  function getNestedValue(obj, path) {
@@ -23867,6 +24238,315 @@ var init_ChartLegend = __esm({
23867
24238
  ChartLegend.displayName = "ChartLegend";
23868
24239
  }
23869
24240
  });
24241
+ function resolveManifestUrl2(manifest, relative) {
24242
+ if (relative == null) return void 0;
24243
+ if (/^https?:\/\//.test(relative)) return relative;
24244
+ const base = manifest?.baseUrl;
24245
+ if (base == null) return relative;
24246
+ const cleanBase = base.replace(/\/$/, "");
24247
+ const cleanRel = relative.replace(/^\//, "");
24248
+ return `${cleanBase}/${cleanRel}`;
24249
+ }
24250
+ function buildDefaultCBTiles() {
24251
+ const tiles = [];
24252
+ for (let y = 0; y < CB_GRID_H; y++) {
24253
+ for (let x = 0; x < CB_GRID_W; x++) {
24254
+ const variant = (x * 3 + y * 5 + (x ^ y)) % 3;
24255
+ const terrainKey = ["grass", "stone", "dirt"][variant];
24256
+ tiles.push({ x, y, terrain: terrainKey, passable: true });
24257
+ }
24258
+ }
24259
+ return tiles;
24260
+ }
24261
+ function tilesToIso(tiles, manifest) {
24262
+ return tiles.map((t) => {
24263
+ const key = t.terrain ?? "grass";
24264
+ const sprite = t.terrainSprite ?? resolveManifestUrl2(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl2(manifest, manifest?.terrains?.grass);
24265
+ return {
24266
+ x: t.x,
24267
+ y: t.y,
24268
+ terrain: t.terrain,
24269
+ terrainSprite: sprite,
24270
+ passable: t.passable
24271
+ };
24272
+ });
24273
+ }
24274
+ function buildingsToFeatures(buildings, manifest) {
24275
+ return buildings.map((b) => ({
24276
+ id: b.id,
24277
+ x: b.x,
24278
+ y: b.y,
24279
+ type: b.type,
24280
+ sprite: resolveManifestUrl2(manifest, manifest?.features?.[b.type])
24281
+ }));
24282
+ }
24283
+ function CityBuilderBoard({
24284
+ entity,
24285
+ tiles: propTiles,
24286
+ buildings: propBuildings,
24287
+ assetManifest: propAssetManifest,
24288
+ buildTypes: propBuildTypes,
24289
+ pendingBuildType: propPendingBuildType,
24290
+ gold: propGold,
24291
+ wood: propWood,
24292
+ population: propPopulation,
24293
+ result: propResult,
24294
+ scale = 0.3,
24295
+ unitScale = 0.6,
24296
+ spriteHeightRatio = 1.5,
24297
+ spriteMaxWidthRatio = 0.7,
24298
+ selectBuildTypeEvent,
24299
+ placeBuildingEvent,
24300
+ gameEndEvent,
24301
+ className
24302
+ }) {
24303
+ const board = boardEntity(entity) ?? {};
24304
+ const eventBus = useEventBus();
24305
+ const { t } = useTranslate();
24306
+ const assetManifest = propAssetManifest ?? board.assetManifest;
24307
+ const entityTiles = useMemo(
24308
+ () => rows(board.tiles).map((r2) => ({
24309
+ x: num(r2.x),
24310
+ y: num(r2.y),
24311
+ terrain: r2.terrain == null ? void 0 : str(r2.terrain),
24312
+ terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
24313
+ passable: r2.passable !== false
24314
+ })),
24315
+ [board.tiles]
24316
+ );
24317
+ const rawTiles = propTiles ?? entityTiles;
24318
+ const tiles = rawTiles.length >= CB_GRID_W * CB_GRID_H ? rawTiles : DEFAULT_CB_TILES;
24319
+ const entityBuildings = useMemo(
24320
+ () => rows(board.buildings).map((r2) => ({
24321
+ id: str(r2.id),
24322
+ x: num(r2.x),
24323
+ y: num(r2.y),
24324
+ type: str(r2.type)
24325
+ })),
24326
+ [board.buildings]
24327
+ );
24328
+ const buildings = propBuildings ?? entityBuildings;
24329
+ const buildTypes = propBuildTypes ?? DEFAULT_BUILD_TYPES;
24330
+ const gold = propGold ?? num(board.gold, 100);
24331
+ const wood = propWood ?? num(board.wood, 80);
24332
+ const population = propPopulation ?? num(board.population, 0);
24333
+ const pendingBuildType = propPendingBuildType ?? (str(board.pendingBuildType) || buildTypes[0]?.type || "");
24334
+ const result = propResult ?? (str(board.result) || "none");
24335
+ const [hoveredTile, setHoveredTile] = useState(null);
24336
+ const emittedGameEnd = useRef(false);
24337
+ if (result !== "none" && !emittedGameEnd.current) {
24338
+ emittedGameEnd.current = true;
24339
+ if (gameEndEvent) {
24340
+ eventBus.emit(`UI:${gameEndEvent}`, { result });
24341
+ }
24342
+ }
24343
+ if (result === "none") {
24344
+ emittedGameEnd.current = false;
24345
+ }
24346
+ const pendingCost = useMemo(
24347
+ () => buildTypes.find((b) => b.type === pendingBuildType)?.cost ?? 0,
24348
+ [buildTypes, pendingBuildType]
24349
+ );
24350
+ const buildingPositions = useMemo(
24351
+ () => new Set(buildings.map((b) => `${b.x},${b.y}`)),
24352
+ [buildings]
24353
+ );
24354
+ const validMoves = useMemo(() => {
24355
+ if (result !== "none" || gold < pendingCost) return [];
24356
+ return tiles.filter(
24357
+ (t2) => t2.passable !== false && !buildingPositions.has(`${t2.x},${t2.y}`)
24358
+ ).map((t2) => ({ x: t2.x, y: t2.y }));
24359
+ }, [tiles, buildingPositions, result, gold, pendingCost]);
24360
+ const isoTiles = useMemo(() => tilesToIso(tiles, assetManifest), [tiles, assetManifest]);
24361
+ const buildingFeatures = useMemo(() => buildingsToFeatures(buildings, assetManifest), [buildings, assetManifest]);
24362
+ const handleTileClick = useCallback((x, y) => {
24363
+ if (result !== "none") return;
24364
+ if (buildingPositions.has(`${x},${y}`)) return;
24365
+ if (gold < pendingCost) return;
24366
+ if (placeBuildingEvent) {
24367
+ eventBus.emit(`UI:${placeBuildingEvent}`, { x, y });
24368
+ }
24369
+ }, [result, buildingPositions, gold, pendingCost, placeBuildingEvent, eventBus]);
24370
+ const handleSelectBuildType = useCallback((buildType) => {
24371
+ if (selectBuildTypeEvent) {
24372
+ eventBus.emit(`UI:${selectBuildTypeEvent}`, { buildType });
24373
+ }
24374
+ }, [selectBuildTypeEvent, eventBus]);
24375
+ const canBuild = gold >= pendingCost && result === "none";
24376
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("city-builder-board relative min-h-[600px] bg-background", className), gap: "none", children: [
24377
+ /* @__PURE__ */ jsxs(
24378
+ HStack,
24379
+ {
24380
+ className: "px-4 py-2 border-b border-border bg-surface",
24381
+ gap: "lg",
24382
+ align: "center",
24383
+ children: [
24384
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
24385
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.gold") ?? "Gold" }),
24386
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-warning", children: gold })
24387
+ ] }),
24388
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
24389
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.wood") ?? "Wood" }),
24390
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-success", children: wood })
24391
+ ] }),
24392
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
24393
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("cb.population") ?? "Population" }),
24394
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: population })
24395
+ ] }),
24396
+ /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", className: "ml-auto", children: buildTypes.map((b) => /* @__PURE__ */ jsxs(
24397
+ Button,
24398
+ {
24399
+ variant: b.type === pendingBuildType ? "primary" : "secondary",
24400
+ size: "sm",
24401
+ disabled: gold < b.cost || result !== "none",
24402
+ onClick: () => handleSelectBuildType(b.type),
24403
+ children: [
24404
+ b.label,
24405
+ " (",
24406
+ b.cost,
24407
+ ")"
24408
+ ]
24409
+ },
24410
+ b.type
24411
+ )) })
24412
+ ]
24413
+ }
24414
+ ),
24415
+ /* @__PURE__ */ jsxs(Box, { className: "relative flex-1", children: [
24416
+ /* @__PURE__ */ jsx(
24417
+ IsometricCanvas_default,
24418
+ {
24419
+ tiles: isoTiles,
24420
+ features: buildingFeatures,
24421
+ assetBaseUrl: assetManifest?.baseUrl,
24422
+ assetManifest,
24423
+ validMoves,
24424
+ hoveredTile,
24425
+ onTileClick: handleTileClick,
24426
+ onTileHover: (x, y) => setHoveredTile({ x, y }),
24427
+ onTileLeave: () => setHoveredTile(null),
24428
+ scale,
24429
+ unitScale,
24430
+ spriteHeightRatio,
24431
+ spriteMaxWidthRatio
24432
+ }
24433
+ ),
24434
+ hoveredTile && canBuild && validMoves.some((m) => m.x === hoveredTile.x && m.y === hoveredTile.y) && /* @__PURE__ */ jsx(Box, { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10 bg-background/80 rounded px-3 py-1 backdrop-blur-sm pointer-events-none", children: /* @__PURE__ */ jsx(Typography, { variant: "small", children: t("cb.placeBuilding") ?? `Build ${pendingBuildType} (${pendingCost} gold)` }) })
24435
+ ] }),
24436
+ result !== "none" && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
24437
+ /* @__PURE__ */ jsx(
24438
+ Typography,
24439
+ {
24440
+ variant: "h2",
24441
+ className: cn(
24442
+ "text-4xl font-black tracking-widest uppercase",
24443
+ result === "won" ? "text-warning" : "text-error"
24444
+ ),
24445
+ children: result === "won" ? t("cb.victory") ?? "City Thrives!" : t("cb.defeat") ?? "City Collapsed!"
24446
+ }
24447
+ ),
24448
+ /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: result === "won" ? t("cb.reachedGoal") ?? `Your city reached a population of ${population}.` : t("cb.bankrupt") ?? "Your city ran out of resources." })
24449
+ ] }) })
24450
+ ] });
24451
+ }
24452
+ var CB_GRID_W, CB_GRID_H, DEFAULT_BUILD_TYPES, DEFAULT_CB_TILES;
24453
+ var init_CityBuilderBoard = __esm({
24454
+ "components/game/organisms/CityBuilderBoard.tsx"() {
24455
+ "use client";
24456
+ init_cn();
24457
+ init_useEventBus();
24458
+ init_Box();
24459
+ init_Button();
24460
+ init_Typography();
24461
+ init_Stack();
24462
+ init_IsometricCanvas();
24463
+ init_boardEntity();
24464
+ CB_GRID_W = 12;
24465
+ CB_GRID_H = 12;
24466
+ DEFAULT_BUILD_TYPES = [
24467
+ { type: "house", label: "House", cost: 20 },
24468
+ { type: "farm", label: "Farm", cost: 15 },
24469
+ { type: "mine", label: "Mine", cost: 25 },
24470
+ { type: "barracks", label: "Barracks", cost: 40 }
24471
+ ];
24472
+ DEFAULT_CB_TILES = buildDefaultCBTiles();
24473
+ CityBuilderBoard.displayName = "CityBuilderBoard";
24474
+ }
24475
+ });
24476
+ function isEntityRow2(value) {
24477
+ return value != null && typeof value === "object" && !Array.isArray(value);
24478
+ }
24479
+ function CityBuilderTemplate({
24480
+ entity,
24481
+ title = "City Builder",
24482
+ tiles,
24483
+ buildings,
24484
+ buildTypes,
24485
+ pendingBuildType,
24486
+ assetManifest,
24487
+ gold,
24488
+ wood,
24489
+ population,
24490
+ result,
24491
+ scale,
24492
+ unitScale,
24493
+ selectBuildTypeEvent,
24494
+ placeBuildingEvent,
24495
+ gameEndEvent,
24496
+ className
24497
+ }) {
24498
+ const resolved = isEntityRow2(entity) ? entity : void 0;
24499
+ return /* @__PURE__ */ jsxs(
24500
+ Box,
24501
+ {
24502
+ display: "flex",
24503
+ fullHeight: true,
24504
+ className: cn("city-builder-template flex-col", className),
24505
+ children: [
24506
+ /* @__PURE__ */ jsx(
24507
+ HStack,
24508
+ {
24509
+ gap: "sm",
24510
+ align: "center",
24511
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
24512
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
24513
+ }
24514
+ ),
24515
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
24516
+ CityBuilderBoard,
24517
+ {
24518
+ entity: resolved,
24519
+ tiles,
24520
+ buildings,
24521
+ buildTypes,
24522
+ pendingBuildType,
24523
+ assetManifest,
24524
+ gold,
24525
+ wood,
24526
+ population,
24527
+ result,
24528
+ scale,
24529
+ unitScale,
24530
+ selectBuildTypeEvent,
24531
+ placeBuildingEvent,
24532
+ gameEndEvent,
24533
+ className: "h-full"
24534
+ }
24535
+ ) })
24536
+ ]
24537
+ }
24538
+ );
24539
+ }
24540
+ var init_CityBuilderTemplate = __esm({
24541
+ "components/game/templates/CityBuilderTemplate.tsx"() {
24542
+ init_cn();
24543
+ init_Box();
24544
+ init_Stack();
24545
+ init_Typography();
24546
+ init_CityBuilderBoard();
24547
+ CityBuilderTemplate.displayName = "CityBuilderTemplate";
24548
+ }
24549
+ });
23870
24550
  function ClassifierBoard({
23871
24551
  entity,
23872
24552
  completeEvent = "PUZZLE_COMPLETE",
@@ -24681,7 +25361,7 @@ function CraftingRecipe({
24681
25361
  className
24682
25362
  }) {
24683
25363
  const eventBus = useEventBus();
24684
- const handleCraft = React90.useCallback(() => {
25364
+ const handleCraft = React93.useCallback(() => {
24685
25365
  onCraft?.();
24686
25366
  if (craftEvent) {
24687
25367
  eventBus.emit(craftEvent, { output: output.label });
@@ -24698,7 +25378,7 @@ function CraftingRecipe({
24698
25378
  children: [
24699
25379
  /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap items-center", children: inputs.map((ingredient, index) => {
24700
25380
  const hasSufficient = ingredient.available >= ingredient.required;
24701
- return /* @__PURE__ */ jsxs(React90.Fragment, { children: [
25381
+ return /* @__PURE__ */ jsxs(React93.Fragment, { children: [
24702
25382
  /* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
24703
25383
  ItemSlot,
24704
25384
  {
@@ -24770,8 +25450,8 @@ function DPad({
24770
25450
  }) {
24771
25451
  const eventBus = useEventBus();
24772
25452
  const sizes = sizeMap15[size];
24773
- const [activeDirections, setActiveDirections] = React90.useState(/* @__PURE__ */ new Set());
24774
- const handlePress = React90.useCallback(
25453
+ const [activeDirections, setActiveDirections] = React93.useState(/* @__PURE__ */ new Set());
25454
+ const handlePress = React93.useCallback(
24775
25455
  (direction) => {
24776
25456
  setActiveDirections((prev) => new Set(prev).add(direction));
24777
25457
  if (directionEvent) eventBus.emit(`UI:${directionEvent}`, { direction, pressed: true });
@@ -24779,7 +25459,7 @@ function DPad({
24779
25459
  },
24780
25460
  [directionEvent, eventBus, onDirection]
24781
25461
  );
24782
- const handleRelease = React90.useCallback(
25462
+ const handleRelease = React93.useCallback(
24783
25463
  (direction) => {
24784
25464
  setActiveDirections((prev) => {
24785
25465
  const next = new Set(prev);
@@ -25586,8 +26266,8 @@ var init_Menu = __esm({
25586
26266
  "bottom-end": "bottom-start"
25587
26267
  };
25588
26268
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
25589
- const triggerChild = React90__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
25590
- const triggerElement = React90__default.cloneElement(
26269
+ const triggerChild = React93__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
26270
+ const triggerElement = React93__default.cloneElement(
25591
26271
  triggerChild,
25592
26272
  {
25593
26273
  ref: triggerRef,
@@ -25721,14 +26401,14 @@ function useDataDnd(args) {
25721
26401
  const isZone = Boolean(dragGroup || accepts || sortable);
25722
26402
  const enabled = isZone || Boolean(dndRoot);
25723
26403
  const eventBus = useEventBus();
25724
- const parentRoot = React90__default.useContext(RootCtx);
26404
+ const parentRoot = React93__default.useContext(RootCtx);
25725
26405
  const isRoot = enabled && parentRoot === null;
25726
- const zoneId = React90__default.useId();
26406
+ const zoneId = React93__default.useId();
25727
26407
  const ownGroup = dragGroup ?? accepts ?? zoneId;
25728
- const [optimisticOrders, setOptimisticOrders] = React90__default.useState(() => /* @__PURE__ */ new Map());
25729
- const optimisticOrdersRef = React90__default.useRef(optimisticOrders);
26408
+ const [optimisticOrders, setOptimisticOrders] = React93__default.useState(() => /* @__PURE__ */ new Map());
26409
+ const optimisticOrdersRef = React93__default.useRef(optimisticOrders);
25730
26410
  optimisticOrdersRef.current = optimisticOrders;
25731
- const clearOptimisticOrder = React90__default.useCallback((group) => {
26411
+ const clearOptimisticOrder = React93__default.useCallback((group) => {
25732
26412
  setOptimisticOrders((prev) => {
25733
26413
  if (!prev.has(group)) return prev;
25734
26414
  const next = new Map(prev);
@@ -25753,7 +26433,7 @@ function useDataDnd(args) {
25753
26433
  const raw = it[dndItemIdField];
25754
26434
  return String(raw ?? `__idx_${idx}`);
25755
26435
  }).join("|");
25756
- const itemIds = React90__default.useMemo(
26436
+ const itemIds = React93__default.useMemo(
25757
26437
  () => orderedItems.map((it, idx) => {
25758
26438
  const raw = it[dndItemIdField];
25759
26439
  return raw ?? `__idx_${idx}`;
@@ -25761,7 +26441,7 @@ function useDataDnd(args) {
25761
26441
  [itemIdsSignature]
25762
26442
  );
25763
26443
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
25764
- React90__default.useEffect(() => {
26444
+ React93__default.useEffect(() => {
25765
26445
  const root = isRoot ? null : parentRoot;
25766
26446
  if (root) {
25767
26447
  root.clearOptimisticOrder(ownGroup);
@@ -25769,20 +26449,20 @@ function useDataDnd(args) {
25769
26449
  clearOptimisticOrder(ownGroup);
25770
26450
  }
25771
26451
  }, [itemsContentSig, ownGroup]);
25772
- const zonesRef = React90__default.useRef(/* @__PURE__ */ new Map());
25773
- const registerZone = React90__default.useCallback((zoneId2, meta2) => {
26452
+ const zonesRef = React93__default.useRef(/* @__PURE__ */ new Map());
26453
+ const registerZone = React93__default.useCallback((zoneId2, meta2) => {
25774
26454
  zonesRef.current.set(zoneId2, meta2);
25775
26455
  }, []);
25776
- const unregisterZone = React90__default.useCallback((zoneId2) => {
26456
+ const unregisterZone = React93__default.useCallback((zoneId2) => {
25777
26457
  zonesRef.current.delete(zoneId2);
25778
26458
  }, []);
25779
- const [activeDrag, setActiveDrag] = React90__default.useState(null);
25780
- const [overZoneGroup, setOverZoneGroup] = React90__default.useState(null);
25781
- const meta = React90__default.useMemo(
26459
+ const [activeDrag, setActiveDrag] = React93__default.useState(null);
26460
+ const [overZoneGroup, setOverZoneGroup] = React93__default.useState(null);
26461
+ const meta = React93__default.useMemo(
25782
26462
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
25783
26463
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
25784
26464
  );
25785
- React90__default.useEffect(() => {
26465
+ React93__default.useEffect(() => {
25786
26466
  const target = isRoot ? null : parentRoot;
25787
26467
  if (!target) {
25788
26468
  zonesRef.current.set(zoneId, meta);
@@ -25801,7 +26481,7 @@ function useDataDnd(args) {
25801
26481
  }, [parentRoot, isRoot, zoneId, meta]);
25802
26482
  const sensors = useAlmadarDndSensors(true);
25803
26483
  const collisionDetection = almadarDndCollisionDetection;
25804
- const findZoneByItem = React90__default.useCallback(
26484
+ const findZoneByItem = React93__default.useCallback(
25805
26485
  (id) => {
25806
26486
  for (const z of zonesRef.current.values()) {
25807
26487
  if (z.itemIds.includes(id)) return z;
@@ -25810,7 +26490,7 @@ function useDataDnd(args) {
25810
26490
  },
25811
26491
  []
25812
26492
  );
25813
- React90__default.useCallback(
26493
+ React93__default.useCallback(
25814
26494
  (group) => {
25815
26495
  for (const z of zonesRef.current.values()) {
25816
26496
  if (z.group === group) return z;
@@ -25819,7 +26499,7 @@ function useDataDnd(args) {
25819
26499
  },
25820
26500
  []
25821
26501
  );
25822
- const handleDragEnd = React90__default.useCallback(
26502
+ const handleDragEnd = React93__default.useCallback(
25823
26503
  (event) => {
25824
26504
  const { active, over } = event;
25825
26505
  const activeIdStr = String(active.id);
@@ -25910,8 +26590,8 @@ function useDataDnd(args) {
25910
26590
  },
25911
26591
  [eventBus]
25912
26592
  );
25913
- const sortableData = React90__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
25914
- const SortableItem = React90__default.useCallback(
26593
+ const sortableData = React93__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
26594
+ const SortableItem = React93__default.useCallback(
25915
26595
  ({ id, children }) => {
25916
26596
  const {
25917
26597
  attributes,
@@ -25951,7 +26631,7 @@ function useDataDnd(args) {
25951
26631
  id: droppableId,
25952
26632
  data: sortableData
25953
26633
  });
25954
- const ctx = React90__default.useContext(RootCtx);
26634
+ const ctx = React93__default.useContext(RootCtx);
25955
26635
  const activeDrag2 = ctx?.activeDrag ?? null;
25956
26636
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
25957
26637
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -25966,7 +26646,7 @@ function useDataDnd(args) {
25966
26646
  showForeignPlaceholder,
25967
26647
  ctxAvailable: ctx != null
25968
26648
  });
25969
- React90__default.useEffect(() => {
26649
+ React93__default.useEffect(() => {
25970
26650
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
25971
26651
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
25972
26652
  return /* @__PURE__ */ jsx(
@@ -25980,11 +26660,11 @@ function useDataDnd(args) {
25980
26660
  }
25981
26661
  );
25982
26662
  };
25983
- const rootContextValue = React90__default.useMemo(
26663
+ const rootContextValue = React93__default.useMemo(
25984
26664
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
25985
26665
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
25986
26666
  );
25987
- const handleDragStart = React90__default.useCallback((event) => {
26667
+ const handleDragStart = React93__default.useCallback((event) => {
25988
26668
  const sourceZone = findZoneByItem(event.active.id);
25989
26669
  const rect = event.active.rect.current.initial;
25990
26670
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -26003,7 +26683,7 @@ function useDataDnd(args) {
26003
26683
  isRoot
26004
26684
  });
26005
26685
  }, [findZoneByItem, isRoot, zoneId]);
26006
- const handleDragOver = React90__default.useCallback((event) => {
26686
+ const handleDragOver = React93__default.useCallback((event) => {
26007
26687
  const { active, over } = event;
26008
26688
  const overData = over?.data?.current;
26009
26689
  const overGroup = overData?.dndGroup ?? null;
@@ -26073,7 +26753,7 @@ function useDataDnd(args) {
26073
26753
  return next;
26074
26754
  });
26075
26755
  }, []);
26076
- const handleDragCancel = React90__default.useCallback((event) => {
26756
+ const handleDragCancel = React93__default.useCallback((event) => {
26077
26757
  setActiveDrag(null);
26078
26758
  setOverZoneGroup(null);
26079
26759
  dndLog.warn("dragCancel", {
@@ -26081,12 +26761,12 @@ function useDataDnd(args) {
26081
26761
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
26082
26762
  });
26083
26763
  }, []);
26084
- const handleDragEndWithCleanup = React90__default.useCallback((event) => {
26764
+ const handleDragEndWithCleanup = React93__default.useCallback((event) => {
26085
26765
  handleDragEnd(event);
26086
26766
  setActiveDrag(null);
26087
26767
  setOverZoneGroup(null);
26088
26768
  }, [handleDragEnd]);
26089
- const wrapContainer = React90__default.useCallback(
26769
+ const wrapContainer = React93__default.useCallback(
26090
26770
  (children) => {
26091
26771
  if (!enabled) return children;
26092
26772
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -26140,7 +26820,7 @@ var init_useDataDnd = __esm({
26140
26820
  init_useAlmadarDndCollision();
26141
26821
  init_Box();
26142
26822
  dndLog = createLogger("almadar:ui:dnd");
26143
- RootCtx = React90__default.createContext(null);
26823
+ RootCtx = React93__default.createContext(null);
26144
26824
  }
26145
26825
  });
26146
26826
  function renderIconInput(icon, props) {
@@ -26666,7 +27346,7 @@ function DataList({
26666
27346
  }) {
26667
27347
  const eventBus = useEventBus();
26668
27348
  const { t } = useTranslate();
26669
- const [visibleCount, setVisibleCount] = React90__default.useState(pageSize || Infinity);
27349
+ const [visibleCount, setVisibleCount] = React93__default.useState(pageSize || Infinity);
26670
27350
  const fieldDefs = fields ?? columns ?? [];
26671
27351
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
26672
27352
  const dnd = useDataDnd({
@@ -26685,7 +27365,7 @@ function DataList({
26685
27365
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
26686
27366
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
26687
27367
  const hasRenderProp = typeof children === "function";
26688
- React90__default.useEffect(() => {
27368
+ React93__default.useEffect(() => {
26689
27369
  const renderItemTypeOf = typeof schemaRenderItem;
26690
27370
  const childrenTypeOf = typeof children;
26691
27371
  if (data.length > 0 && !hasRenderProp) {
@@ -26790,7 +27470,7 @@ function DataList({
26790
27470
  const items2 = data.map((item) => item);
26791
27471
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
26792
27472
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
26793
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
27473
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
26794
27474
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
26795
27475
  group.items.map((itemData, index) => {
26796
27476
  const id = itemData.id || `${gi}-${index}`;
@@ -26931,7 +27611,7 @@ function DataList({
26931
27611
  className
26932
27612
  ),
26933
27613
  children: [
26934
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
27614
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
26935
27615
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
26936
27616
  group.items.map(
26937
27617
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -27847,7 +28527,7 @@ var init_Grid = __esm({
27847
28527
  as: Component2 = "div"
27848
28528
  }) => {
27849
28529
  const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
27850
- return React90__default.createElement(
28530
+ return React93__default.createElement(
27851
28531
  Component2,
27852
28532
  {
27853
28533
  className: cn(
@@ -28035,8 +28715,8 @@ var init_Popover = __esm({
28035
28715
  onMouseEnter: handleOpen,
28036
28716
  onMouseLeave: handleClose
28037
28717
  };
28038
- const childElement = React90__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
28039
- const triggerElement = React90__default.cloneElement(
28718
+ const childElement = React93__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
28719
+ const triggerElement = React93__default.cloneElement(
28040
28720
  childElement,
28041
28721
  {
28042
28722
  ref: triggerRef,
@@ -28092,9 +28772,9 @@ function debug(...args) {
28092
28772
  const [first, ...rest] = args;
28093
28773
  const message = typeof first === "string" ? first : "<debug>";
28094
28774
  if (rest.length === 0 && typeof first === "string") {
28095
- log8.debug(message);
28775
+ log7.debug(message);
28096
28776
  } else {
28097
- log8.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
28777
+ log7.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
28098
28778
  }
28099
28779
  }
28100
28780
  function debugGroup(label) {
@@ -28122,11 +28802,11 @@ function toLogMetaValue(v) {
28122
28802
  }
28123
28803
  return String(v);
28124
28804
  }
28125
- var NAMESPACE, log8;
28805
+ var NAMESPACE, log7;
28126
28806
  var init_debug = __esm({
28127
28807
  "lib/debug.ts"() {
28128
28808
  NAMESPACE = "almadar:ui:debug";
28129
- log8 = createLogger(NAMESPACE);
28809
+ log7 = createLogger(NAMESPACE);
28130
28810
  createLogger("almadar:ui:debug:input");
28131
28811
  createLogger("almadar:ui:debug:collision");
28132
28812
  createLogger("almadar:ui:debug:physics");
@@ -28626,8 +29306,8 @@ var init_Tooltip = __esm({
28626
29306
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
28627
29307
  };
28628
29308
  }, []);
28629
- const triggerElement = React90__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
28630
- const trigger = React90__default.cloneElement(triggerElement, {
29309
+ const triggerElement = React93__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
29310
+ const trigger = React93__default.cloneElement(triggerElement, {
28631
29311
  ref: triggerRef,
28632
29312
  onMouseEnter: handleMouseEnter,
28633
29313
  onMouseLeave: handleMouseLeave,
@@ -28713,7 +29393,7 @@ var init_WizardProgress = __esm({
28713
29393
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
28714
29394
  const isActive = index === currentStep;
28715
29395
  const isCompleted = index < currentStep;
28716
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
29396
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
28717
29397
  /* @__PURE__ */ jsx(
28718
29398
  "button",
28719
29399
  {
@@ -29674,7 +30354,7 @@ var init_ProgressDots = __esm({
29674
30354
  }
29675
30355
  });
29676
30356
  function StatBadge({
29677
- assetUrl = DEFAULT_ASSET_URL12,
30357
+ assetUrl,
29678
30358
  label,
29679
30359
  value = 0,
29680
30360
  max,
@@ -29741,7 +30421,7 @@ function StatBadge({
29741
30421
  }
29742
30422
  );
29743
30423
  }
29744
- var sizeMap17, variantMap2, DEFAULT_ASSET_URL12;
30424
+ var sizeMap17, variantMap2;
29745
30425
  var init_StatBadge = __esm({
29746
30426
  "components/game/molecules/StatBadge.tsx"() {
29747
30427
  init_cn();
@@ -29760,7 +30440,6 @@ var init_StatBadge = __esm({
29760
30440
  warning: "bg-warning/15 border-warning/40 text-foreground",
29761
30441
  danger: "bg-error/15 border-error/40 text-foreground"
29762
30442
  };
29763
- DEFAULT_ASSET_URL12 = "https://almadar-kflow-assets.web.app/shared/effects/particles/light_01.png";
29764
30443
  StatBadge.displayName = "StatBadge";
29765
30444
  }
29766
30445
  });
@@ -29777,7 +30456,7 @@ function InventoryGrid({
29777
30456
  const eventBus = useEventBus();
29778
30457
  const slotCount = totalSlots ?? items.length;
29779
30458
  const emptySlotCount = Math.max(0, slotCount - items.length);
29780
- const handleSelect = React90.useCallback(
30459
+ const handleSelect = React93.useCallback(
29781
30460
  (id) => {
29782
30461
  onSelect?.(id);
29783
30462
  if (selectEvent) {
@@ -30008,35 +30687,37 @@ function GameCanvas2D({
30008
30687
  drawEvent,
30009
30688
  fps = 60,
30010
30689
  backgroundImage = "",
30011
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
30690
+ assetBaseUrl,
30012
30691
  className
30013
30692
  }) {
30014
- const canvasRef = React90.useRef(null);
30015
- const rafRef = React90.useRef(0);
30016
- const frameRef = React90.useRef(0);
30017
- const lastTimeRef = React90.useRef(0);
30018
- const imageCache = React90.useRef(/* @__PURE__ */ new Map());
30693
+ const canvasRef = React93.useRef(null);
30694
+ const rafRef = React93.useRef(0);
30695
+ const frameRef = React93.useRef(0);
30696
+ const lastTimeRef = React93.useRef(0);
30697
+ const imageCache = React93.useRef(/* @__PURE__ */ new Map());
30019
30698
  const emit = useEmitEvent();
30020
- const onDrawRef = React90.useRef(onDraw);
30699
+ const onDrawRef = React93.useRef(onDraw);
30021
30700
  onDrawRef.current = onDraw;
30022
- const onTickRef = React90.useRef(onTick);
30701
+ const onTickRef = React93.useRef(onTick);
30023
30702
  onTickRef.current = onTick;
30024
- const tickEventRef = React90.useRef(tickEvent);
30703
+ const tickEventRef = React93.useRef(tickEvent);
30025
30704
  tickEventRef.current = tickEvent;
30026
- const drawEventRef = React90.useRef(drawEvent);
30705
+ const drawEventRef = React93.useRef(drawEvent);
30027
30706
  drawEventRef.current = drawEvent;
30028
- const emitRef = React90.useRef(emit);
30707
+ const emitRef = React93.useRef(emit);
30029
30708
  emitRef.current = emit;
30030
- const assetBaseUrlRef = React90.useRef(assetBaseUrl);
30709
+ const assetBaseUrlRef = React93.useRef(assetBaseUrl);
30031
30710
  assetBaseUrlRef.current = assetBaseUrl;
30032
- const backgroundImageRef = React90.useRef(backgroundImage);
30711
+ const backgroundImageRef = React93.useRef(backgroundImage);
30033
30712
  backgroundImageRef.current = backgroundImage;
30034
- const widthRef = React90.useRef(width);
30713
+ const widthRef = React93.useRef(width);
30035
30714
  widthRef.current = width;
30036
- const heightRef = React90.useRef(height);
30715
+ const heightRef = React93.useRef(height);
30037
30716
  heightRef.current = height;
30038
- const loadImage = React90.useCallback((url) => {
30039
- const fullUrl = url.startsWith("http") ? url : `${assetBaseUrlRef.current}${url}`;
30717
+ const loadImage = React93.useCallback((url) => {
30718
+ const base = assetBaseUrlRef.current;
30719
+ if (!url.startsWith("http") && !base) return null;
30720
+ const fullUrl = url.startsWith("http") ? url : `${base}${url}`;
30040
30721
  const cached = imageCache.current.get(fullUrl);
30041
30722
  if (cached?.complete && cached.naturalWidth > 0) return cached;
30042
30723
  if (!cached) {
@@ -30047,7 +30728,7 @@ function GameCanvas2D({
30047
30728
  }
30048
30729
  return null;
30049
30730
  }, []);
30050
- React90.useEffect(() => {
30731
+ React93.useEffect(() => {
30051
30732
  const canvas = canvasRef.current;
30052
30733
  if (!canvas) return;
30053
30734
  const ctx = canvas.getContext("2d");
@@ -30359,7 +31040,7 @@ function TurnPanel({
30359
31040
  className
30360
31041
  }) {
30361
31042
  const eventBus = useEventBus();
30362
- const handleAction = React90.useCallback(
31043
+ const handleAction = React93.useCallback(
30363
31044
  (event) => {
30364
31045
  if (event) {
30365
31046
  eventBus.emit(event, { turn: currentTurn, phase, activeTeam });
@@ -30417,7 +31098,7 @@ var init_TurnPanel = __esm({
30417
31098
  }
30418
31099
  });
30419
31100
  function EnemyPlate({
30420
- assetUrl = DEFAULT_ASSET_URL13,
31101
+ assetUrl,
30421
31102
  name = "Shadow Guard",
30422
31103
  health = 80,
30423
31104
  maxHealth = 100,
@@ -30501,7 +31182,7 @@ function EnemyPlate({
30501
31182
  }
30502
31183
  );
30503
31184
  }
30504
- var effectVariantMap2, DEFAULT_ENEMY_EFFECTS, DEFAULT_ASSET_URL13;
31185
+ var effectVariantMap2, DEFAULT_ENEMY_EFFECTS;
30505
31186
  var init_EnemyPlate = __esm({
30506
31187
  "components/game/molecules/EnemyPlate.tsx"() {
30507
31188
  "use client";
@@ -30518,7 +31199,6 @@ var init_EnemyPlate = __esm({
30518
31199
  DEFAULT_ENEMY_EFFECTS = [
30519
31200
  { icon: "flame", label: "Burn", variant: "debuff" }
30520
31201
  ];
30521
- DEFAULT_ASSET_URL13 = "https://almadar-kflow-assets.web.app/shared/portraits/shadow-legion.png";
30522
31202
  EnemyPlate.displayName = "EnemyPlate";
30523
31203
  }
30524
31204
  });
@@ -30528,7 +31208,7 @@ function UnitCommandBar({
30528
31208
  className
30529
31209
  }) {
30530
31210
  const eventBus = useEventBus();
30531
- const handleCommand = React90.useCallback(
31211
+ const handleCommand = React93.useCallback(
30532
31212
  (event) => {
30533
31213
  if (event) {
30534
31214
  eventBus.emit(event, { unitId: selectedUnitId });
@@ -30669,6 +31349,9 @@ function DialogueBox({
30669
31349
  completeEvent,
30670
31350
  choiceEvent,
30671
31351
  advanceEvent,
31352
+ backgroundImage,
31353
+ portraitUrl,
31354
+ portraitScale = 1,
30672
31355
  className
30673
31356
  }) {
30674
31357
  const eventBus = useEventBus();
@@ -30784,64 +31467,98 @@ function DialogueBox({
30784
31467
  }
30785
31468
  }, [isTyping, skipTypewriter, dialogue.choices, selectedChoice, onChoice, onAdvance, choiceEvent, advanceEvent, eventBus]);
30786
31469
  const enabledChoices = dialogue.choices?.filter((c) => !c.disabled) ?? [];
30787
- return /* @__PURE__ */ jsx(
30788
- "div",
30789
- {
30790
- className: cn(
30791
- "fixed left-0 right-0 z-40",
30792
- position === "top" ? "top-0" : "bottom-0",
30793
- className
30794
- ),
30795
- onClick: handleClick,
30796
- onKeyDown: handleKeyDown,
30797
- tabIndex: 0,
30798
- role: "dialog",
30799
- "aria-label": "Dialogue",
30800
- children: /* @__PURE__ */ jsx("div", { className: "mx-4 my-4 bg-[var(--color-card)] bg-opacity-95 border-2 border-border rounded-container overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
30801
- dialogue.portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 p-4 border-r border-border", children: /* @__PURE__ */ jsx(
31470
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
31471
+ backgroundImage && /* @__PURE__ */ jsx(
31472
+ "div",
31473
+ {
31474
+ className: "fixed inset-0 z-20 bg-center bg-cover bg-no-repeat",
31475
+ style: { backgroundImage: `url(${backgroundImage})` },
31476
+ "aria-hidden": "true"
31477
+ }
31478
+ ),
31479
+ portraitUrl && /* @__PURE__ */ jsx(
31480
+ "div",
31481
+ {
31482
+ className: cn(
31483
+ "fixed left-1/2 -translate-x-1/2 z-30 pointer-events-none flex items-end",
31484
+ position === "top" ? "top-0" : "bottom-0"
31485
+ ),
31486
+ style: { height: `${60 * portraitScale}vh` },
31487
+ children: /* @__PURE__ */ jsx(
30802
31488
  "img",
30803
31489
  {
30804
- src: dialogue.portrait,
31490
+ src: portraitUrl,
30805
31491
  alt: dialogue.speaker,
30806
- className: "w-24 h-24 object-contain",
30807
- style: { imageRendering: "pixelated" }
31492
+ className: "h-full w-auto object-contain drop-shadow-2xl"
30808
31493
  }
30809
- ) }),
30810
- /* @__PURE__ */ jsxs("div", { className: "flex-1 p-4", children: [
30811
- /* @__PURE__ */ jsx("div", { className: "text-warning font-bold mb-2", children: dialogue.speaker }),
30812
- /* @__PURE__ */ jsxs("div", { className: "text-[var(--color-foreground)] text-lg leading-relaxed min-h-[60px]", children: [
30813
- displayedText,
30814
- isTyping && /* @__PURE__ */ jsx("span", { className: "animate-pulse", children: "\u258C" })
30815
- ] }),
30816
- !isTyping && enabledChoices.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-2", children: enabledChoices.map((choice, index) => /* @__PURE__ */ jsxs(
30817
- "button",
31494
+ )
31495
+ }
31496
+ ),
31497
+ /* @__PURE__ */ jsx(
31498
+ "div",
31499
+ {
31500
+ className: cn(
31501
+ "fixed left-0 right-0 z-40",
31502
+ position === "top" ? "top-0" : "bottom-0",
31503
+ className
31504
+ ),
31505
+ onClick: handleClick,
31506
+ onKeyDown: handleKeyDown,
31507
+ tabIndex: 0,
31508
+ role: "dialog",
31509
+ "aria-label": "Dialogue",
31510
+ children: /* @__PURE__ */ jsx("div", { className: cn(
31511
+ "mx-4 my-4 border-2 rounded-container overflow-hidden",
31512
+ backgroundImage ? "bg-black/80 backdrop-blur-sm text-white border-white/20" : "bg-[var(--color-card)] bg-opacity-95 border-border"
31513
+ ), children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
31514
+ dialogue.portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 p-4 border-r border-border", children: /* @__PURE__ */ jsx(
31515
+ "img",
30818
31516
  {
30819
- type: "button",
30820
- className: cn(
30821
- "block w-full text-left px-4 py-2 rounded-interactive transition-colors",
30822
- "hover:bg-[var(--color-surface,#374151)] focus:outline-none focus:ring-2 focus:ring-warning",
30823
- selectedChoice === index ? "bg-[var(--color-surface,#374151)] text-warning" : "bg-[var(--color-card)] text-[var(--color-foreground)]"
30824
- ),
30825
- onClick: (e) => {
30826
- e.stopPropagation();
30827
- if (choiceEvent) eventBus.emit(`UI:${choiceEvent}`, { choice });
30828
- onChoice?.(choice);
31517
+ src: dialogue.portrait,
31518
+ alt: dialogue.speaker,
31519
+ className: "w-24 h-24 object-contain",
31520
+ style: { imageRendering: "pixelated" }
31521
+ }
31522
+ ) }),
31523
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 p-4", children: [
31524
+ /* @__PURE__ */ jsx("div", { className: "text-warning font-bold mb-2", children: dialogue.speaker }),
31525
+ /* @__PURE__ */ jsxs("div", { className: cn(
31526
+ "text-lg leading-relaxed min-h-[60px]",
31527
+ backgroundImage ? "text-white" : "text-[var(--color-foreground)]"
31528
+ ), children: [
31529
+ displayedText,
31530
+ isTyping && /* @__PURE__ */ jsx("span", { className: "animate-pulse", children: "\u258C" })
31531
+ ] }),
31532
+ !isTyping && enabledChoices.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-2", children: enabledChoices.map((choice, index) => /* @__PURE__ */ jsxs(
31533
+ "button",
31534
+ {
31535
+ type: "button",
31536
+ className: cn(
31537
+ "block w-full text-left px-4 py-2 rounded-interactive transition-colors",
31538
+ "hover:bg-[var(--color-surface,#374151)] focus:outline-none focus:ring-2 focus:ring-warning",
31539
+ selectedChoice === index ? "bg-[var(--color-surface,#374151)] text-warning" : backgroundImage ? "bg-white/10 text-white hover:bg-white/20" : "bg-[var(--color-card)] text-[var(--color-foreground)]"
31540
+ ),
31541
+ onClick: (e) => {
31542
+ e.stopPropagation();
31543
+ if (choiceEvent) eventBus.emit(`UI:${choiceEvent}`, { choice });
31544
+ onChoice?.(choice);
31545
+ },
31546
+ children: [
31547
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground mr-2", children: [
31548
+ index + 1,
31549
+ "."
31550
+ ] }),
31551
+ choice.text
31552
+ ]
30829
31553
  },
30830
- children: [
30831
- /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground mr-2", children: [
30832
- index + 1,
30833
- "."
30834
- ] }),
30835
- choice.text
30836
- ]
30837
- },
30838
- index
30839
- )) }),
30840
- !isTyping && !dialogue.choices?.length && /* @__PURE__ */ jsx("div", { className: "mt-4 text-muted-foreground text-sm animate-pulse", children: "Press SPACE or click to continue..." })
30841
- ] })
30842
- ] }) })
30843
- }
30844
- );
31554
+ index
31555
+ )) }),
31556
+ !isTyping && !dialogue.choices?.length && /* @__PURE__ */ jsx("div", { className: "mt-4 text-muted-foreground text-sm animate-pulse", children: "Press SPACE or click to continue..." })
31557
+ ] })
31558
+ ] }) })
31559
+ }
31560
+ )
31561
+ ] });
30845
31562
  }
30846
31563
  var DEFAULT_DIALOGUE;
30847
31564
  var init_DialogueBox = __esm({
@@ -31042,7 +31759,7 @@ function GameMenu({
31042
31759
  } catch {
31043
31760
  }
31044
31761
  const eventBus = eventBusProp || eventBusFromHook;
31045
- const handleOptionClick = React90.useCallback(
31762
+ const handleOptionClick = React93.useCallback(
31046
31763
  (option) => {
31047
31764
  if (option.event && eventBus) {
31048
31765
  eventBus.emit(`UI:${option.event}`, { option });
@@ -31161,7 +31878,7 @@ function GameOverScreen({
31161
31878
  } catch {
31162
31879
  }
31163
31880
  const eventBus = eventBusProp || eventBusFromHook;
31164
- const handleActionClick = React90.useCallback(
31881
+ const handleActionClick = React93.useCallback(
31165
31882
  (action) => {
31166
31883
  if (action.event && eventBus) {
31167
31884
  eventBus.emit(`UI:${action.event}`, { action });
@@ -31368,10 +32085,10 @@ function PlatformerCanvas({
31368
32085
  canvasHeight = 400,
31369
32086
  followCamera = true,
31370
32087
  bgColor = "#5c94fc",
31371
- playerSprite = "https://almadar-kflow-assets.web.app/shared/platformer/characters/platformChar_idle.png",
32088
+ playerSprite,
31372
32089
  tileSprites,
31373
32090
  backgroundImage = "",
31374
- assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/platformer/",
32091
+ assetBaseUrl,
31375
32092
  leftEvent = "MOVE_LEFT",
31376
32093
  rightEvent = "MOVE_RIGHT",
31377
32094
  jumpEvent = "JUMP",
@@ -31385,6 +32102,7 @@ function PlatformerCanvas({
31385
32102
  const imageCache = useRef(/* @__PURE__ */ new Map());
31386
32103
  const [loadedImages, setLoadedImages] = useState(/* @__PURE__ */ new Set());
31387
32104
  const loadImage = useCallback((url) => {
32105
+ if (!url.startsWith("http") && !assetBaseUrl) return null;
31388
32106
  const fullUrl = url.startsWith("http") ? url : `${assetBaseUrl}${url}`;
31389
32107
  const cached = imageCache.current.get(fullUrl);
31390
32108
  if (cached?.complete && cached.naturalWidth > 0) {
@@ -32083,13 +32801,13 @@ var init_MapView = __esm({
32083
32801
  shadowSize: [41, 41]
32084
32802
  });
32085
32803
  L.Marker.prototype.options.icon = defaultIcon;
32086
- const { useEffect: useEffect86, useRef: useRef77, useCallback: useCallback125, useState: useState121 } = React90__default;
32804
+ const { useEffect: useEffect87, useRef: useRef80, useCallback: useCallback130, useState: useState122 } = React93__default;
32087
32805
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
32088
32806
  const { useEventBus: useEventBus4 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
32089
32807
  function MapUpdater({ centerLat, centerLng, zoom }) {
32090
32808
  const map = useMap();
32091
- const prevRef = useRef77({ centerLat, centerLng, zoom });
32092
- useEffect86(() => {
32809
+ const prevRef = useRef80({ centerLat, centerLng, zoom });
32810
+ useEffect87(() => {
32093
32811
  const prev = prevRef.current;
32094
32812
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
32095
32813
  map.setView([centerLat, centerLng], zoom);
@@ -32100,7 +32818,7 @@ var init_MapView = __esm({
32100
32818
  }
32101
32819
  function MapClickHandler({ onMapClick }) {
32102
32820
  const map = useMap();
32103
- useEffect86(() => {
32821
+ useEffect87(() => {
32104
32822
  if (!onMapClick) return;
32105
32823
  const handler = (e) => {
32106
32824
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -32128,8 +32846,8 @@ var init_MapView = __esm({
32128
32846
  showAttribution = true
32129
32847
  }) {
32130
32848
  const eventBus = useEventBus4();
32131
- const [clickedPosition, setClickedPosition] = useState121(null);
32132
- const handleMapClick = useCallback125((lat, lng) => {
32849
+ const [clickedPosition, setClickedPosition] = useState122(null);
32850
+ const handleMapClick = useCallback130((lat, lng) => {
32133
32851
  if (showClickedPin) {
32134
32852
  setClickedPosition({ lat, lng });
32135
32853
  }
@@ -32138,7 +32856,7 @@ var init_MapView = __esm({
32138
32856
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
32139
32857
  }
32140
32858
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
32141
- const handleMarkerClick = useCallback125((marker) => {
32859
+ const handleMarkerClick = useCallback130((marker) => {
32142
32860
  onMarkerClick?.(marker);
32143
32861
  if (markerClickEvent) {
32144
32862
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -32989,8 +33707,8 @@ function TableView({
32989
33707
  }) {
32990
33708
  const eventBus = useEventBus();
32991
33709
  const { t } = useTranslate();
32992
- const [visibleCount, setVisibleCount] = React90__default.useState(pageSize > 0 ? pageSize : Infinity);
32993
- const [localSelected, setLocalSelected] = React90__default.useState(/* @__PURE__ */ new Set());
33710
+ const [visibleCount, setVisibleCount] = React93__default.useState(pageSize > 0 ? pageSize : Infinity);
33711
+ const [localSelected, setLocalSelected] = React93__default.useState(/* @__PURE__ */ new Set());
32994
33712
  const colDefs = columns ?? fields ?? [];
32995
33713
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
32996
33714
  const dnd = useDataDnd({
@@ -33185,12 +33903,12 @@ function TableView({
33185
33903
  ]
33186
33904
  }
33187
33905
  );
33188
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React90__default.Fragment, { children: rowInner }, id);
33906
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React93__default.Fragment, { children: rowInner }, id);
33189
33907
  };
33190
33908
  const items = data.map((row) => row);
33191
33909
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
33192
33910
  let runningIndex = 0;
33193
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
33911
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
33194
33912
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
33195
33913
  group.items.map((row) => renderRow(row, runningIndex++))
33196
33914
  ] }, gi)) });
@@ -34547,7 +35265,7 @@ var init_StepFlow = __esm({
34547
35265
  className
34548
35266
  }) => {
34549
35267
  if (orientation === "vertical") {
34550
- return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React90__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
35268
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React93__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
34551
35269
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
34552
35270
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
34553
35271
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -34558,7 +35276,7 @@ var init_StepFlow = __esm({
34558
35276
  ] })
34559
35277
  ] }) }, index)) });
34560
35278
  }
34561
- return /* @__PURE__ */ jsx(Box, { className: cn("w-full flex flex-col md:flex-row items-start gap-0", className), children: steps.map((step, index) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
35279
+ 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(React93__default.Fragment, { children: [
34562
35280
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
34563
35281
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
34564
35282
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -35543,7 +36261,7 @@ var init_LikertScale = __esm({
35543
36261
  md: "text-base",
35544
36262
  lg: "text-lg"
35545
36263
  };
35546
- LikertScale = React90__default.forwardRef(
36264
+ LikertScale = React93__default.forwardRef(
35547
36265
  ({
35548
36266
  question,
35549
36267
  options = DEFAULT_LIKERT_OPTIONS,
@@ -35555,7 +36273,7 @@ var init_LikertScale = __esm({
35555
36273
  variant = "radios",
35556
36274
  className
35557
36275
  }, ref) => {
35558
- const groupId = React90__default.useId();
36276
+ const groupId = React93__default.useId();
35559
36277
  const eventBus = useEventBus();
35560
36278
  const handleSelect = useCallback(
35561
36279
  (next) => {
@@ -37837,7 +38555,7 @@ var init_DocBreadcrumb = __esm({
37837
38555
  "aria-label": t("aria.breadcrumb"),
37838
38556
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
37839
38557
  const isLast = idx === items.length - 1;
37840
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
38558
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
37841
38559
  idx > 0 && /* @__PURE__ */ jsx(
37842
38560
  Icon,
37843
38561
  {
@@ -38501,7 +39219,7 @@ var init_PageHeader = __esm({
38501
39219
  info: "bg-info/10 text-info"
38502
39220
  };
38503
39221
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
38504
- breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
39222
+ 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(React93__default.Fragment, { children: [
38505
39223
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
38506
39224
  crumb.href ? /* @__PURE__ */ jsx(
38507
39225
  "a",
@@ -39183,8 +39901,8 @@ var init_WizardContainer = __esm({
39183
39901
  return void 0;
39184
39902
  if (typeof controlledStep === "number") return controlledStep;
39185
39903
  if (typeof controlledStep === "string") return parseInt(controlledStep, 10);
39186
- const num2 = Number(controlledStep);
39187
- return isNaN(num2) ? void 0 : num2;
39904
+ const num3 = Number(controlledStep);
39905
+ return isNaN(num3) ? void 0 : num3;
39188
39906
  })();
39189
39907
  const currentStep = normalizedControlledStep !== void 0 ? normalizedControlledStep : internalStep;
39190
39908
  const totalSteps = steps.length;
@@ -39230,7 +39948,7 @@ var init_WizardContainer = __esm({
39230
39948
  const isCompleted = index < currentStep;
39231
39949
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
39232
39950
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
39233
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
39951
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
39234
39952
  /* @__PURE__ */ jsx(
39235
39953
  Button,
39236
39954
  {
@@ -40157,10 +40875,13 @@ var init_GraphCanvas = __esm({
40157
40875
  draggable = true,
40158
40876
  actions,
40159
40877
  onNodeClick,
40878
+ onNodeDoubleClick,
40160
40879
  nodeClickEvent,
40161
40880
  selectedNodeId,
40162
40881
  repulsion = 800,
40163
40882
  linkDistance = 100,
40883
+ nodeSpacing = 28,
40884
+ linkOpacity = 0.18,
40164
40885
  layout = "force",
40165
40886
  entity,
40166
40887
  isLoading = false,
@@ -40176,6 +40897,19 @@ var init_GraphCanvas = __esm({
40176
40897
  const [hoveredNode, setHoveredNode] = useState(null);
40177
40898
  const nodesRef = useRef([]);
40178
40899
  const [, forceUpdate] = useState(0);
40900
+ const [logicalW, setLogicalW] = useState(800);
40901
+ useEffect(() => {
40902
+ const canvas = canvasRef.current;
40903
+ if (!canvas || typeof ResizeObserver === "undefined") return;
40904
+ const measure = () => {
40905
+ const width = Math.round(canvas.clientWidth);
40906
+ if (width > 0) setLogicalW(width);
40907
+ };
40908
+ measure();
40909
+ const ro = new ResizeObserver(measure);
40910
+ ro.observe(canvas);
40911
+ return () => ro.disconnect();
40912
+ }, []);
40179
40913
  const interactionRef = useRef({
40180
40914
  mode: "none",
40181
40915
  dragNodeId: null,
@@ -40188,10 +40922,8 @@ var init_GraphCanvas = __esm({
40188
40922
  const canvas = canvasRef.current;
40189
40923
  if (!canvas) return null;
40190
40924
  const rect = canvas.getBoundingClientRect();
40191
- const scaleX = rect.width > 0 ? canvas.width / rect.width : 1;
40192
- const scaleY = rect.height > 0 ? canvas.height / rect.height : 1;
40193
- const screenX = (e.clientX - rect.left) * scaleX;
40194
- const screenY = (e.clientY - rect.top) * scaleY;
40925
+ const screenX = e.clientX - rect.left;
40926
+ const screenY = e.clientY - rect.top;
40195
40927
  return {
40196
40928
  screenX,
40197
40929
  screenY,
@@ -40231,8 +40963,8 @@ var init_GraphCanvas = __esm({
40231
40963
  useEffect(() => {
40232
40964
  const canvas = canvasRef.current;
40233
40965
  if (!canvas || propNodes.length === 0) return;
40234
- const w = canvas.width;
40235
- const h = canvas.height;
40966
+ const w = logicalW;
40967
+ const h = height;
40236
40968
  const simNodes = propNodes.map((n, idx) => {
40237
40969
  let x = n.x ?? 0;
40238
40970
  let y = n.y ?? 0;
@@ -40309,6 +41041,25 @@ var init_GraphCanvas = __esm({
40309
41041
  node.x = Math.max(30, Math.min(w - 30, node.x));
40310
41042
  node.y = Math.max(30, Math.min(h - 30, node.y));
40311
41043
  }
41044
+ for (let i = 0; i < nodes.length; i++) {
41045
+ for (let j = i + 1; j < nodes.length; j++) {
41046
+ const a = nodes[i];
41047
+ const b = nodes[j];
41048
+ const dx = b.x - a.x;
41049
+ const dy = b.y - a.y;
41050
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
41051
+ const minDist = (a.size || 8) + (b.size || 8) + nodeSpacing;
41052
+ if (dist < minDist) {
41053
+ const push2 = (minDist - dist) / 2;
41054
+ const ux = dx / dist;
41055
+ const uy = dy / dist;
41056
+ a.x = Math.max(30, Math.min(w - 30, a.x - ux * push2));
41057
+ a.y = Math.max(30, Math.min(h - 30, a.y - uy * push2));
41058
+ b.x = Math.max(30, Math.min(w - 30, b.x + ux * push2));
41059
+ b.y = Math.max(30, Math.min(h - 30, b.y + uy * push2));
41060
+ }
41061
+ }
41062
+ }
40312
41063
  iterations++;
40313
41064
  forceUpdate((n) => n + 1);
40314
41065
  if (iterations < maxIterations) {
@@ -40322,29 +41073,41 @@ var init_GraphCanvas = __esm({
40322
41073
  return () => {
40323
41074
  cancelAnimationFrame(animRef.current);
40324
41075
  };
40325
- }, [propNodes, propEdges, layout, repulsion, linkDistance]);
41076
+ }, [propNodes, propEdges, layout, repulsion, linkDistance, nodeSpacing, logicalW, height]);
40326
41077
  useEffect(() => {
40327
41078
  const canvas = canvasRef.current;
40328
41079
  if (!canvas) return;
40329
41080
  const ctx = canvas.getContext("2d");
40330
41081
  if (!ctx) return;
40331
- const w = canvas.width;
40332
- const h = canvas.height;
41082
+ const w = logicalW;
41083
+ const h = height;
40333
41084
  const nodes = nodesRef.current;
40334
41085
  const accentColor = resolveColor2("var(--color-accent)", canvas);
41086
+ const dpr = typeof window !== "undefined" && window.devicePixelRatio || 1;
41087
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
40335
41088
  ctx.clearRect(0, 0, w, h);
40336
41089
  ctx.save();
40337
41090
  ctx.translate(offset.x, offset.y);
40338
41091
  ctx.scale(zoom, zoom);
41092
+ const neighbors = /* @__PURE__ */ new Set();
41093
+ if (hoveredNode) {
41094
+ neighbors.add(hoveredNode);
41095
+ for (const edge of propEdges) {
41096
+ if (edge.source === hoveredNode) neighbors.add(String(edge.target));
41097
+ else if (edge.target === hoveredNode) neighbors.add(String(edge.source));
41098
+ }
41099
+ }
40339
41100
  for (const edge of propEdges) {
40340
41101
  const source = nodes.find((n) => n.id === edge.source);
40341
41102
  const target = nodes.find((n) => n.id === edge.target);
40342
41103
  if (!source || !target) continue;
41104
+ const incident = !!hoveredNode && (edge.source === hoveredNode || edge.target === hoveredNode);
41105
+ ctx.globalAlpha = hoveredNode ? incident ? 1 : 0.05 : linkOpacity;
40343
41106
  ctx.beginPath();
40344
41107
  ctx.moveTo(source.x, source.y);
40345
41108
  ctx.lineTo(target.x, target.y);
40346
- ctx.strokeStyle = edge.color || "#88888866";
40347
- ctx.lineWidth = edge.weight ? Math.max(1, edge.weight) : 1;
41109
+ ctx.strokeStyle = incident ? accentColor : edge.color || "#888888";
41110
+ ctx.lineWidth = incident ? 2 : edge.weight ? Math.max(1, edge.weight) : 1;
40348
41111
  ctx.stroke();
40349
41112
  if (edge.label && showLabels) {
40350
41113
  const mx = (source.x + target.x) / 2;
@@ -40355,11 +41118,13 @@ var init_GraphCanvas = __esm({
40355
41118
  ctx.fillText(edge.label, mx, my - 4);
40356
41119
  }
40357
41120
  }
41121
+ ctx.globalAlpha = 1;
40358
41122
  for (const node of nodes) {
40359
41123
  const size = node.size || 8;
40360
41124
  const color = resolveColor2(node.color || getGroupColor(node.group, groups), canvas);
40361
41125
  const isHovered = hoveredNode === node.id;
40362
41126
  const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
41127
+ ctx.globalAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : 1;
40363
41128
  const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
40364
41129
  ctx.beginPath();
40365
41130
  ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
@@ -40479,6 +41244,15 @@ var init_GraphCanvas = __esm({
40479
41244
  interactionRef.current.dragNodeId = null;
40480
41245
  setHoveredNode(null);
40481
41246
  }, []);
41247
+ const handleDoubleClick = useCallback(
41248
+ (e) => {
41249
+ const coords = toCoords(e);
41250
+ if (!coords) return;
41251
+ const node = nodeAt(coords.graphX, coords.graphY);
41252
+ if (node) onNodeDoubleClick?.(node);
41253
+ },
41254
+ [toCoords, nodeAt, onNodeDoubleClick]
41255
+ );
40482
41256
  if (isLoading) {
40483
41257
  return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
40484
41258
  }
@@ -40536,15 +41310,16 @@ var init_GraphCanvas = __esm({
40536
41310
  "canvas",
40537
41311
  {
40538
41312
  ref: canvasRef,
40539
- width: 800,
40540
- height,
41313
+ width: Math.round(logicalW * (typeof window !== "undefined" && window.devicePixelRatio || 1)),
41314
+ height: Math.round(height * (typeof window !== "undefined" && window.devicePixelRatio || 1)),
40541
41315
  className: "w-full cursor-grab active:cursor-grabbing",
40542
41316
  style: { height },
40543
41317
  onWheel: handleWheel,
40544
41318
  onMouseDown: handleMouseDown,
40545
41319
  onMouseMove: handleMouseMove,
40546
41320
  onMouseUp: handleMouseUp,
40547
- onMouseLeave: handleMouseLeave
41321
+ onMouseLeave: handleMouseLeave,
41322
+ onDoubleClick: handleDoubleClick
40548
41323
  }
40549
41324
  ) }),
40550
41325
  groups.length > 1 && /* @__PURE__ */ jsx(HStack, { gap: "md", className: "px-4 py-2 border-t border-border", wrap: true, children: groups.map((group, idx) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
@@ -41695,7 +42470,7 @@ var init_DetailPanel = __esm({
41695
42470
  }
41696
42471
  });
41697
42472
  function extractTitle(children) {
41698
- if (!React90__default.isValidElement(children)) return void 0;
42473
+ if (!React93__default.isValidElement(children)) return void 0;
41699
42474
  const props = children.props;
41700
42475
  if (typeof props.title === "string") {
41701
42476
  return props.title;
@@ -41750,7 +42525,7 @@ function LinearView({
41750
42525
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
41751
42526
  const isDone = i < currentIdx;
41752
42527
  const isCurrent = i === currentIdx;
41753
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
42528
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
41754
42529
  i > 0 && /* @__PURE__ */ jsx(
41755
42530
  Typography,
41756
42531
  {
@@ -42700,12 +43475,12 @@ var init_Form = __esm({
42700
43475
  const isSchemaEntity = isOrbitalEntitySchema(entity);
42701
43476
  const resolvedEntity = isSchemaEntity ? entity : void 0;
42702
43477
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
42703
- const normalizedInitialData = React90__default.useMemo(() => {
43478
+ const normalizedInitialData = React93__default.useMemo(() => {
42704
43479
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
42705
43480
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
42706
43481
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
42707
43482
  }, [entity, initialData]);
42708
- const entityDerivedFields = React90__default.useMemo(() => {
43483
+ const entityDerivedFields = React93__default.useMemo(() => {
42709
43484
  if (fields && fields.length > 0) return void 0;
42710
43485
  if (!resolvedEntity) return void 0;
42711
43486
  return resolvedEntity.fields.map(
@@ -42725,16 +43500,16 @@ var init_Form = __esm({
42725
43500
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
42726
43501
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
42727
43502
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
42728
- const [formData, setFormData] = React90__default.useState(
43503
+ const [formData, setFormData] = React93__default.useState(
42729
43504
  normalizedInitialData
42730
43505
  );
42731
- const [collapsedSections, setCollapsedSections] = React90__default.useState(
43506
+ const [collapsedSections, setCollapsedSections] = React93__default.useState(
42732
43507
  /* @__PURE__ */ new Set()
42733
43508
  );
42734
- const [submitError, setSubmitError] = React90__default.useState(null);
42735
- const formRef = React90__default.useRef(null);
43509
+ const [submitError, setSubmitError] = React93__default.useState(null);
43510
+ const formRef = React93__default.useRef(null);
42736
43511
  const formMode = props.mode;
42737
- const mountedRef = React90__default.useRef(false);
43512
+ const mountedRef = React93__default.useRef(false);
42738
43513
  if (!mountedRef.current) {
42739
43514
  mountedRef.current = true;
42740
43515
  debug("forms", "mount", {
@@ -42747,7 +43522,7 @@ var init_Form = __esm({
42747
43522
  });
42748
43523
  }
42749
43524
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
42750
- const evalContext = React90__default.useMemo(
43525
+ const evalContext = React93__default.useMemo(
42751
43526
  () => ({
42752
43527
  formValues: formData,
42753
43528
  globalVariables: externalContext?.globalVariables ?? {},
@@ -42756,7 +43531,7 @@ var init_Form = __esm({
42756
43531
  }),
42757
43532
  [formData, externalContext]
42758
43533
  );
42759
- React90__default.useEffect(() => {
43534
+ React93__default.useEffect(() => {
42760
43535
  debug("forms", "initialData-sync", {
42761
43536
  mode: formMode,
42762
43537
  normalizedInitialData,
@@ -42767,7 +43542,7 @@ var init_Form = __esm({
42767
43542
  setFormData(normalizedInitialData);
42768
43543
  }
42769
43544
  }, [normalizedInitialData]);
42770
- const processCalculations = React90__default.useCallback(
43545
+ const processCalculations = React93__default.useCallback(
42771
43546
  (changedFieldId, newFormData) => {
42772
43547
  if (!hiddenCalculations.length) return;
42773
43548
  const context = {
@@ -42792,7 +43567,7 @@ var init_Form = __esm({
42792
43567
  },
42793
43568
  [hiddenCalculations, externalContext, eventBus]
42794
43569
  );
42795
- const checkViolations = React90__default.useCallback(
43570
+ const checkViolations = React93__default.useCallback(
42796
43571
  (changedFieldId, newFormData) => {
42797
43572
  if (!violationTriggers.length) return;
42798
43573
  const context = {
@@ -42830,7 +43605,7 @@ var init_Form = __esm({
42830
43605
  processCalculations(name, newFormData);
42831
43606
  checkViolations(name, newFormData);
42832
43607
  };
42833
- const isFieldVisible = React90__default.useCallback(
43608
+ const isFieldVisible = React93__default.useCallback(
42834
43609
  (fieldName) => {
42835
43610
  const condition = conditionalFields[fieldName];
42836
43611
  if (!condition) return true;
@@ -42838,7 +43613,7 @@ var init_Form = __esm({
42838
43613
  },
42839
43614
  [conditionalFields, evalContext]
42840
43615
  );
42841
- const isSectionVisible = React90__default.useCallback(
43616
+ const isSectionVisible = React93__default.useCallback(
42842
43617
  (section) => {
42843
43618
  if (!section.condition) return true;
42844
43619
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -42914,7 +43689,7 @@ var init_Form = __esm({
42914
43689
  eventBus.emit(`UI:${onCancel}`);
42915
43690
  }
42916
43691
  };
42917
- const renderField = React90__default.useCallback(
43692
+ const renderField = React93__default.useCallback(
42918
43693
  (field) => {
42919
43694
  const fieldName = field.name || field.field;
42920
43695
  if (!fieldName) return null;
@@ -42935,7 +43710,7 @@ var init_Form = __esm({
42935
43710
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
42936
43711
  );
42937
43712
  const effectiveFields = entityDerivedFields ?? fields;
42938
- const normalizedFields = React90__default.useMemo(() => {
43713
+ const normalizedFields = React93__default.useMemo(() => {
42939
43714
  if (!effectiveFields || effectiveFields.length === 0) return [];
42940
43715
  return effectiveFields.map((field) => {
42941
43716
  if (typeof field === "string") {
@@ -42958,7 +43733,7 @@ var init_Form = __esm({
42958
43733
  return field;
42959
43734
  });
42960
43735
  }, [effectiveFields, resolvedEntity]);
42961
- const schemaFields = React90__default.useMemo(() => {
43736
+ const schemaFields = React93__default.useMemo(() => {
42962
43737
  if (normalizedFields.length === 0) return null;
42963
43738
  if (isDebugEnabled()) {
42964
43739
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -42968,7 +43743,7 @@ var init_Form = __esm({
42968
43743
  }
42969
43744
  return normalizedFields.map(renderField).filter(Boolean);
42970
43745
  }, [normalizedFields, renderField, entityName, conditionalFields]);
42971
- const sectionElements = React90__default.useMemo(() => {
43746
+ const sectionElements = React93__default.useMemo(() => {
42972
43747
  if (!sections || sections.length === 0) return null;
42973
43748
  return sections.map((section) => {
42974
43749
  if (!isSectionVisible(section)) {
@@ -44138,11 +44913,11 @@ var init_Canvas3DErrorBoundary = __esm({
44138
44913
  "components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
44139
44914
  }
44140
44915
  });
44141
- var log9, Canvas3DErrorBoundary;
44916
+ var log8, Canvas3DErrorBoundary;
44142
44917
  var init_Canvas3DErrorBoundary2 = __esm({
44143
44918
  "components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
44144
44919
  init_Canvas3DErrorBoundary();
44145
- log9 = createLogger("almadar:ui:game:canvas3d:error-boundary");
44920
+ log8 = createLogger("almadar:ui:game:canvas3d:error-boundary");
44146
44921
  Canvas3DErrorBoundary = class extends Component {
44147
44922
  constructor(props) {
44148
44923
  super(props);
@@ -44170,8 +44945,8 @@ var init_Canvas3DErrorBoundary2 = __esm({
44170
44945
  componentDidCatch(error, errorInfo) {
44171
44946
  this.setState({ errorInfo });
44172
44947
  this.props.onError?.(error, errorInfo);
44173
- log9.error("Error caught", { error });
44174
- log9.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
44948
+ log8.error("Error caught", { error });
44949
+ log8.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
44175
44950
  }
44176
44951
  render() {
44177
44952
  if (this.state.hasError) {
@@ -44234,7 +45009,7 @@ function useGLTFModel(url, resourceBasePath) {
44234
45009
  setState({ model: null, isLoading: false, error: null });
44235
45010
  return;
44236
45011
  }
44237
- log10.debug("Loading", { url });
45012
+ log9.debug("Loading", { url });
44238
45013
  setState((prev) => ({ ...prev, isLoading: true, error: null }));
44239
45014
  const assetRoot = resourceBasePath || detectAssetRoot2(url);
44240
45015
  const loader = new GLTFLoader$1();
@@ -44242,7 +45017,7 @@ function useGLTFModel(url, resourceBasePath) {
44242
45017
  loader.load(
44243
45018
  url,
44244
45019
  (gltf) => {
44245
- log10.debug("Loaded", { url });
45020
+ log9.debug("Loaded", { url });
44246
45021
  setState({
44247
45022
  model: gltf.scene,
44248
45023
  isLoading: false,
@@ -44251,7 +45026,7 @@ function useGLTFModel(url, resourceBasePath) {
44251
45026
  },
44252
45027
  void 0,
44253
45028
  (err) => {
44254
- log10.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
45029
+ log9.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
44255
45030
  setState({
44256
45031
  model: null,
44257
45032
  isLoading: false,
@@ -44288,12 +45063,18 @@ function ModelLoader({
44288
45063
  });
44289
45064
  return cloned;
44290
45065
  }, [loadedModel, castShadow, receiveShadow]);
45066
+ const normFactor = useMemo(() => {
45067
+ if (!model) return 1;
45068
+ const box = new THREE3.Box3().setFromObject(model);
45069
+ const size = new THREE3.Vector3();
45070
+ box.getSize(size);
45071
+ const maxDim = Math.max(size.x, size.y, size.z);
45072
+ return maxDim > 0 && Number.isFinite(maxDim) ? 1 / maxDim : 1;
45073
+ }, [model]);
44291
45074
  const scaleArray = useMemo(() => {
44292
- if (typeof scale === "number") {
44293
- return [scale, scale, scale];
44294
- }
44295
- return scale;
44296
- }, [scale]);
45075
+ const base = typeof scale === "number" ? [scale, scale, scale] : scale;
45076
+ return [base[0] * normFactor, base[1] * normFactor, base[2] * normFactor];
45077
+ }, [scale, normFactor]);
44297
45078
  const rotationRad = useMemo(() => {
44298
45079
  return [
44299
45080
  rotation[0] * Math.PI / 180,
@@ -44367,11 +45148,11 @@ function ModelLoader({
44367
45148
  }
44368
45149
  );
44369
45150
  }
44370
- var log10;
45151
+ var log9;
44371
45152
  var init_ModelLoader = __esm({
44372
45153
  "components/game/molecules/three/components/ModelLoader.tsx"() {
44373
45154
  "use client";
44374
- log10 = createLogger("almadar:ui:game:model-loader");
45155
+ log9 = createLogger("almadar:ui:game:model-loader");
44375
45156
  }
44376
45157
  });
44377
45158
 
@@ -44504,6 +45285,29 @@ var init_GameCanvas3D2 = __esm({
44504
45285
  const controlsRef = useRef(null);
44505
45286
  const [hoveredTile, setHoveredTile] = useState(null);
44506
45287
  const [internalError, setInternalError] = useState(null);
45288
+ useEffect(() => {
45289
+ const el = containerRef.current;
45290
+ if (!el) return;
45291
+ let node = el;
45292
+ let depth = 0;
45293
+ while (node && depth < 8) {
45294
+ const cs = window.getComputedStyle(node);
45295
+ const rect = node.getBoundingClientRect();
45296
+ console.log("[almadar:ui:game:3d-height]", {
45297
+ depth,
45298
+ tag: node.tagName,
45299
+ id: node.id || void 0,
45300
+ className: node.className?.slice?.(0, 60) || void 0,
45301
+ rectHeight: rect.height,
45302
+ computedHeight: cs.height,
45303
+ computedMinHeight: cs.minHeight,
45304
+ computedFlex: cs.flex,
45305
+ computedOverflow: cs.overflow
45306
+ });
45307
+ node = node.parentElement;
45308
+ depth++;
45309
+ }
45310
+ }, []);
44507
45311
  const { sheetUrls: atlasSheetUrls, resolveUnitFrame } = useUnitSpriteAtlas(units);
44508
45312
  const preloadUrls = useMemo(() => [...preloadAssets, ...atlasSheetUrls], [preloadAssets, atlasSheetUrls]);
44509
45313
  const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
@@ -44632,24 +45436,28 @@ var init_GameCanvas3D2 = __esm({
44632
45436
  const cameraConfig = useMemo(() => {
44633
45437
  const size = Math.max(
44634
45438
  gridBounds.maxX - gridBounds.minX,
44635
- gridBounds.maxZ - gridBounds.minZ
45439
+ gridBounds.maxZ - gridBounds.minZ,
45440
+ 4
45441
+ // minimum framing distance so a tiny board isn't zoomed in
44636
45442
  );
44637
- const distance = size * 1.5;
45443
+ const cx = (gridBounds.minX + gridBounds.maxX) / 2;
45444
+ const cz = (gridBounds.minZ + gridBounds.maxZ) / 2;
45445
+ const d = size * 1.5;
44638
45446
  switch (cameraMode) {
44639
45447
  case "isometric":
44640
45448
  return {
44641
- position: [distance, distance * 0.8, distance],
45449
+ position: [cx + d, d * 0.8, cz + d],
44642
45450
  fov: 45
44643
45451
  };
44644
45452
  case "top-down":
44645
45453
  return {
44646
- position: [0, distance * 2, 0],
45454
+ position: [cx, d * 2, cz],
44647
45455
  fov: 45
44648
45456
  };
44649
45457
  case "perspective":
44650
45458
  default:
44651
45459
  return {
44652
- position: [distance, distance, distance],
45460
+ position: [cx + d, d, cz + d],
44653
45461
  fov: 45
44654
45462
  };
44655
45463
  }
@@ -44888,7 +45696,8 @@ var init_GameCanvas3D2 = __esm({
44888
45696
  "div",
44889
45697
  {
44890
45698
  ref: containerRef,
44891
- className: cn("game-canvas-3d relative w-full h-full min-h-[85vh] overflow-hidden", className),
45699
+ className: cn("game-canvas-3d relative w-full overflow-hidden", className),
45700
+ style: { height: "85vh" },
44892
45701
  "data-orientation": orientation,
44893
45702
  "data-camera-mode": cameraMode,
44894
45703
  "data-overlay": overlay,
@@ -44903,7 +45712,7 @@ var init_GameCanvas3D2 = __esm({
44903
45712
  near: 0.1,
44904
45713
  far: 1e3
44905
45714
  },
44906
- style: { background: backgroundColor },
45715
+ style: { background: backgroundColor, position: "absolute", inset: 0 },
44907
45716
  onClick: (e) => {
44908
45717
  if (e.target === e.currentTarget) {
44909
45718
  eventHandlers.handleCanvasClick(e);
@@ -45874,7 +46683,7 @@ var init_List = __esm({
45874
46683
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
45875
46684
  return [];
45876
46685
  }, [entity]);
45877
- const getItemActions = React90__default.useCallback(
46686
+ const getItemActions = React93__default.useCallback(
45878
46687
  (item) => {
45879
46688
  if (!itemActions) return [];
45880
46689
  if (typeof itemActions === "function") {
@@ -46350,7 +47159,7 @@ var init_MediaGallery = __esm({
46350
47159
  [selectable, selectedItems, selectionEvent, eventBus]
46351
47160
  );
46352
47161
  const entityData = Array.isArray(entity) ? entity : [];
46353
- const items = React90__default.useMemo(() => {
47162
+ const items = React93__default.useMemo(() => {
46354
47163
  if (propItems) return propItems;
46355
47164
  if (entityData.length === 0) return [];
46356
47165
  return entityData.map((record, idx) => ({
@@ -46511,7 +47320,7 @@ var init_MediaGallery = __esm({
46511
47320
  }
46512
47321
  });
46513
47322
  function extractTitle2(children) {
46514
- if (!React90__default.isValidElement(children)) return void 0;
47323
+ if (!React93__default.isValidElement(children)) return void 0;
46515
47324
  const props = children.props;
46516
47325
  if (typeof props.title === "string") {
46517
47326
  return props.title;
@@ -47087,31 +47896,33 @@ var init_PricingPageTemplate = __esm({
47087
47896
  PricingPageTemplate.displayName = "PricingPageTemplate";
47088
47897
  }
47089
47898
  });
47090
- function dungeonTerrain(x, y, stairsX, stairsY) {
47899
+ function resolveManifestUrl3(manifest, relative) {
47900
+ if (relative == null) return void 0;
47901
+ if (/^https?:\/\//.test(relative)) return relative;
47902
+ const base = manifest?.baseUrl;
47903
+ if (base == null) return relative;
47904
+ const cleanBase = base.replace(/\/$/, "");
47905
+ const cleanRel = relative.replace(/^\//, "");
47906
+ return `${cleanBase}/${cleanRel}`;
47907
+ }
47908
+ function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
47091
47909
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
47092
47910
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
47093
47911
  const isWall = isBorder || isPillar;
47912
+ const terrains = manifest?.terrains;
47094
47913
  if (x === stairsX && y === stairsY) {
47095
- return { terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` };
47914
+ return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
47096
47915
  }
47097
47916
  if (isWall) {
47098
- return { terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` };
47099
- }
47100
- const variant = (x * 3 + y * 7) % 5;
47101
- const sprites = [
47102
- `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
47103
- `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`,
47104
- `${CDN4}/isometric-dungeon/Isometric/planks_E.png`,
47105
- `${CDN4}/isometric-dungeon/Isometric/stoneTile_E.png`,
47106
- `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`
47107
- ];
47108
- return { terrain: "floor", passable: true, terrainSprite: sprites[variant] };
47917
+ return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
47918
+ }
47919
+ return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
47109
47920
  }
47110
- function buildDefaultDungeonTiles(stairsX, stairsY) {
47921
+ function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
47111
47922
  const tiles = [];
47112
47923
  for (let y = 0; y < DUNGEON_GRID_H; y++) {
47113
47924
  for (let x = 0; x < DUNGEON_GRID_W; x++) {
47114
- tiles.push({ x, y, ...dungeonTerrain(x, y, stairsX, stairsY) });
47925
+ tiles.push({ x, y, ...dungeonTerrain(x, y, stairsX, stairsY, manifest) });
47115
47926
  }
47116
47927
  }
47117
47928
  return tiles;
@@ -47141,20 +47952,48 @@ function RoguelikeBoard({
47141
47952
  className
47142
47953
  }) {
47143
47954
  const board = boardEntity(entity) ?? {};
47144
- const resolvedStairsX = propStairsX ?? num(board.stairsX, 14);
47145
- const resolvedStairsY = propStairsY ?? num(board.stairsY, 14);
47146
- const tiles = propTiles ?? (Array.isArray(board.tiles) && board.tiles.length >= DUNGEON_GRID_W * DUNGEON_GRID_H ? board.tiles : buildDefaultDungeonTiles(resolvedStairsX, resolvedStairsY));
47147
- const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
47148
- const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
47149
- const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
47955
+ const assetManifest = propAssetManifest ?? board.assetManifest;
47956
+ const stairsX = propStairsX ?? num(board.stairsX, 14);
47957
+ const stairsY = propStairsY ?? num(board.stairsY, 14);
47958
+ const entityTiles = useMemo(
47959
+ () => rows(board.tiles).map((r2) => ({
47960
+ x: num(r2.x),
47961
+ y: num(r2.y),
47962
+ terrain: r2.terrain == null ? void 0 : str(r2.terrain),
47963
+ terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
47964
+ passable: r2.passable !== false
47965
+ })),
47966
+ [board.tiles]
47967
+ );
47968
+ const tiles = propTiles ?? (entityTiles.length >= DUNGEON_GRID_W * DUNGEON_GRID_H ? entityTiles : buildDefaultDungeonTiles(stairsX, stairsY, assetManifest));
47969
+ const entityEnemies = useMemo(
47970
+ () => rows(board.enemies).map((r2) => ({
47971
+ id: str(r2.id),
47972
+ x: num(r2.x),
47973
+ y: num(r2.y),
47974
+ hp: num(r2.hp),
47975
+ attack: num(r2.attack)
47976
+ })),
47977
+ [board.enemies]
47978
+ );
47979
+ const enemies = propEnemies ?? (entityEnemies.length > 0 ? entityEnemies : DEFAULT_ENEMIES);
47980
+ const entityItems = useMemo(
47981
+ () => rows(board.items).map((r2) => ({
47982
+ id: str(r2.id),
47983
+ x: num(r2.x),
47984
+ y: num(r2.y),
47985
+ kind: str(r2.kind) || "health_potion"
47986
+ })),
47987
+ [board.items]
47988
+ );
47989
+ const items = propItems ?? (entityItems.length > 0 ? entityItems : DEFAULT_ITEMS);
47990
+ const player = propPlayer ?? (board.player == null ? { x: 1, y: 1 } : vec2(board.player));
47150
47991
  const playerHp = propPlayerHp ?? num(board.playerHp, 10);
47151
47992
  const playerMaxHp = propPlayerMaxHp ?? num(board.playerMaxHp, 10);
47152
47993
  const playerAttack = propPlayerAttack ?? num(board.playerAttack, 3);
47153
47994
  const depth = propDepth ?? num(board.depth, 1);
47154
47995
  const result = propResult ?? (str(board.result) || "none");
47155
47996
  const phase = propPhase ?? (str(board.phase) || "player_turn");
47156
- propStairsX ?? num(board.stairsX, 14);
47157
- propStairsY ?? num(board.stairsY, 14);
47158
47997
  const eventBus = useEventBus();
47159
47998
  const { t } = useTranslate();
47160
47999
  const [hoveredTile, setHoveredTile] = useState(null);
@@ -47201,7 +48040,7 @@ function RoguelikeBoard({
47201
48040
  health: playerHp,
47202
48041
  maxHealth: playerMaxHp,
47203
48042
  unitType: "player",
47204
- sprite: `${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`
48043
+ sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
47205
48044
  },
47206
48045
  ...liveEnemies.map((e) => ({
47207
48046
  id: e.id,
@@ -47211,19 +48050,19 @@ function RoguelikeBoard({
47211
48050
  health: e.hp,
47212
48051
  maxHealth: 6,
47213
48052
  unitType: "enemy",
47214
- sprite: `${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`
48053
+ sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
47215
48054
  }))
47216
48055
  ];
47217
- }, [player, enemies, playerHp, playerMaxHp, t]);
48056
+ }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
47218
48057
  const isoFeatures = useMemo(
47219
48058
  () => items.map((it) => ({
47220
48059
  id: it.id,
47221
48060
  x: it.x,
47222
48061
  y: it.y,
47223
48062
  type: it.kind,
47224
- sprite: FEATURE_SPRITE[it.kind] ?? FEATURE_SPRITE.health_potion
48063
+ sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
47225
48064
  })),
47226
- [items]
48065
+ [items, assetManifest]
47227
48066
  );
47228
48067
  const validMoves = useMemo(() => {
47229
48068
  if (result !== "none" || phase !== "player_turn") return [];
@@ -47282,8 +48121,8 @@ function RoguelikeBoard({
47282
48121
  onTileHover: (x, y) => setHoveredTile({ x, y }),
47283
48122
  onTileLeave: () => setHoveredTile(null),
47284
48123
  scale,
47285
- assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
47286
- assetManifest: propAssetManifest,
48124
+ assetBaseUrl: assetManifest?.baseUrl,
48125
+ assetManifest,
47287
48126
  unitScale,
47288
48127
  spriteHeightRatio,
47289
48128
  spriteMaxWidthRatio
@@ -47330,7 +48169,7 @@ function RoguelikeBoard({
47330
48169
  ] }) })
47331
48170
  ] });
47332
48171
  }
47333
- var CDN4, DUNGEON_GRID_W, DUNGEON_GRID_H, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
48172
+ var DUNGEON_GRID_W, DUNGEON_GRID_H, DEFAULT_ENEMIES, DEFAULT_ITEMS;
47334
48173
  var init_RoguelikeBoard = __esm({
47335
48174
  "components/game/organisms/RoguelikeBoard.tsx"() {
47336
48175
  "use client";
@@ -47342,10 +48181,8 @@ var init_RoguelikeBoard = __esm({
47342
48181
  init_Stack();
47343
48182
  init_IsometricCanvas();
47344
48183
  init_boardEntity();
47345
- CDN4 = "https://almadar-kflow-assets.web.app/shared";
47346
48184
  DUNGEON_GRID_W = 16;
47347
48185
  DUNGEON_GRID_H = 16;
47348
- buildDefaultDungeonTiles(14, 14);
47349
48186
  DEFAULT_ENEMIES = [
47350
48187
  { id: "e1", x: 5, y: 2, hp: 5, attack: 2 },
47351
48188
  { id: "e2", x: 9, y: 6, hp: 4, attack: 1 },
@@ -47357,11 +48194,6 @@ var init_RoguelikeBoard = __esm({
47357
48194
  { id: "i2", x: 7, y: 9, kind: "sword" },
47358
48195
  { id: "i3", x: 11, y: 5, kind: "shield" }
47359
48196
  ];
47360
- FEATURE_SPRITE = {
47361
- health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
47362
- sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
47363
- shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
47364
- };
47365
48197
  RoguelikeBoard.displayName = "RoguelikeBoard";
47366
48198
  }
47367
48199
  });
@@ -47399,40 +48231,40 @@ function RoguelikeTemplate({
47399
48231
  }
47400
48232
  );
47401
48233
  }
47402
- var CDN5, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
48234
+ var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
47403
48235
  var init_RoguelikeTemplate = __esm({
47404
48236
  "components/game/templates/RoguelikeTemplate.tsx"() {
47405
48237
  init_RoguelikeBoard();
47406
- CDN5 = "https://almadar-kflow-assets.web.app/shared";
48238
+ CDN4 = "https://almadar-kflow-assets.web.app/shared";
47407
48239
  DEFAULT_ROGUELIKE_TILES = [
47408
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47409
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47410
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47411
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47412
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47413
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47414
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
47415
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
47416
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
47417
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47418
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47419
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47420
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47421
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
47422
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47423
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47424
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
47425
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47426
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stairs_E.png` },
47427
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47428
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47429
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47430
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47431
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
47432
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` }
48240
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48241
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48242
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48243
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48244
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48245
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48246
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48247
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48248
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48249
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48250
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48251
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
48252
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
48253
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48254
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48255
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48256
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48257
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
48258
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
48259
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48260
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48261
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48262
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48263
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48264
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
47433
48265
  ];
47434
48266
  DEFAULT_ROGUELIKE_MANIFEST = {
47435
- baseUrl: CDN5,
48267
+ baseUrl: CDN4,
47436
48268
  terrains: {
47437
48269
  floor: "/isometric-dungeon/Isometric/dirt_E.png",
47438
48270
  wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
@@ -47558,7 +48390,7 @@ var init_debugRegistry = __esm({
47558
48390
  }
47559
48391
  });
47560
48392
  function useDebugData() {
47561
- const [data, setData] = React90.useState(() => ({
48393
+ const [data, setData] = React93.useState(() => ({
47562
48394
  traits: [],
47563
48395
  ticks: [],
47564
48396
  guards: [],
@@ -47572,7 +48404,7 @@ function useDebugData() {
47572
48404
  },
47573
48405
  lastUpdate: Date.now()
47574
48406
  }));
47575
- React90.useEffect(() => {
48407
+ React93.useEffect(() => {
47576
48408
  const updateData = () => {
47577
48409
  setData({
47578
48410
  traits: getAllTraits(),
@@ -47681,12 +48513,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
47681
48513
  return positions;
47682
48514
  }
47683
48515
  function WalkMinimap() {
47684
- const [walkStep, setWalkStep] = React90.useState(null);
47685
- const [traits2, setTraits] = React90.useState([]);
47686
- const [coveredEdges, setCoveredEdges] = React90.useState([]);
47687
- const [completedTraits, setCompletedTraits] = React90.useState(/* @__PURE__ */ new Set());
47688
- const prevTraitRef = React90.useRef(null);
47689
- React90.useEffect(() => {
48516
+ const [walkStep, setWalkStep] = React93.useState(null);
48517
+ const [traits2, setTraits] = React93.useState([]);
48518
+ const [coveredEdges, setCoveredEdges] = React93.useState([]);
48519
+ const [completedTraits, setCompletedTraits] = React93.useState(/* @__PURE__ */ new Set());
48520
+ const prevTraitRef = React93.useRef(null);
48521
+ React93.useEffect(() => {
47690
48522
  const interval = setInterval(() => {
47691
48523
  const w = window;
47692
48524
  const step = w.__orbitalWalkStep;
@@ -48122,15 +48954,15 @@ var init_EntitiesTab = __esm({
48122
48954
  });
48123
48955
  function EventFlowTab({ events: events2 }) {
48124
48956
  const { t } = useTranslate();
48125
- const [filter, setFilter] = React90.useState("all");
48126
- const containerRef = React90.useRef(null);
48127
- const [autoScroll, setAutoScroll] = React90.useState(true);
48128
- React90.useEffect(() => {
48957
+ const [filter, setFilter] = React93.useState("all");
48958
+ const containerRef = React93.useRef(null);
48959
+ const [autoScroll, setAutoScroll] = React93.useState(true);
48960
+ React93.useEffect(() => {
48129
48961
  if (autoScroll && containerRef.current) {
48130
48962
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
48131
48963
  }
48132
48964
  }, [events2.length, autoScroll]);
48133
- const filteredEvents = React90.useMemo(() => {
48965
+ const filteredEvents = React93.useMemo(() => {
48134
48966
  if (filter === "all") return events2;
48135
48967
  return events2.filter((e) => e.type === filter);
48136
48968
  }, [events2, filter]);
@@ -48246,7 +49078,7 @@ var init_EventFlowTab = __esm({
48246
49078
  });
48247
49079
  function GuardsPanel({ guards }) {
48248
49080
  const { t } = useTranslate();
48249
- const [filter, setFilter] = React90.useState("all");
49081
+ const [filter, setFilter] = React93.useState("all");
48250
49082
  if (guards.length === 0) {
48251
49083
  return /* @__PURE__ */ jsx(
48252
49084
  EmptyState,
@@ -48259,7 +49091,7 @@ function GuardsPanel({ guards }) {
48259
49091
  }
48260
49092
  const passedCount = guards.filter((g) => g.result).length;
48261
49093
  const failedCount = guards.length - passedCount;
48262
- const filteredGuards = React90.useMemo(() => {
49094
+ const filteredGuards = React93.useMemo(() => {
48263
49095
  if (filter === "all") return guards;
48264
49096
  if (filter === "passed") return guards.filter((g) => g.result);
48265
49097
  return guards.filter((g) => !g.result);
@@ -48422,10 +49254,10 @@ function EffectBadge({ effect }) {
48422
49254
  }
48423
49255
  function TransitionTimeline({ transitions }) {
48424
49256
  const { t } = useTranslate();
48425
- const containerRef = React90.useRef(null);
48426
- const [autoScroll, setAutoScroll] = React90.useState(true);
48427
- const [expandedId, setExpandedId] = React90.useState(null);
48428
- React90.useEffect(() => {
49257
+ const containerRef = React93.useRef(null);
49258
+ const [autoScroll, setAutoScroll] = React93.useState(true);
49259
+ const [expandedId, setExpandedId] = React93.useState(null);
49260
+ React93.useEffect(() => {
48429
49261
  if (autoScroll && containerRef.current) {
48430
49262
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
48431
49263
  }
@@ -48705,9 +49537,9 @@ function getAllEvents(traits2) {
48705
49537
  function EventDispatcherTab({ traits: traits2, schema }) {
48706
49538
  const eventBus = useEventBus();
48707
49539
  const { t } = useTranslate();
48708
- const [log16, setLog] = React90.useState([]);
48709
- const prevStatesRef = React90.useRef(/* @__PURE__ */ new Map());
48710
- React90.useEffect(() => {
49540
+ const [log15, setLog] = React93.useState([]);
49541
+ const prevStatesRef = React93.useRef(/* @__PURE__ */ new Map());
49542
+ React93.useEffect(() => {
48711
49543
  for (const trait of traits2) {
48712
49544
  const prev = prevStatesRef.current.get(trait.id);
48713
49545
  if (prev && prev !== trait.currentState) {
@@ -48769,9 +49601,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
48769
49601
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
48770
49602
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: unavailableEvents.map((event) => /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", className: "opacity-50", children: event }, event)) })
48771
49603
  ] }),
48772
- log16.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
49604
+ log15.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
48773
49605
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
48774
- /* @__PURE__ */ jsx(Stack, { gap: "xs", children: log16.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
49606
+ /* @__PURE__ */ jsx(Stack, { gap: "xs", children: log15.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
48775
49607
  /* @__PURE__ */ jsx("span", { className: "text-purple-400", children: entry.traitName }),
48776
49608
  " ",
48777
49609
  /* @__PURE__ */ jsx("span", { className: "text-gray-500", children: entry.from }),
@@ -48876,10 +49708,10 @@ function VerifyModePanel({
48876
49708
  localCount
48877
49709
  }) {
48878
49710
  const { t } = useTranslate();
48879
- const [expanded, setExpanded] = React90.useState(true);
48880
- const scrollRef = React90.useRef(null);
48881
- const prevCountRef = React90.useRef(0);
48882
- React90.useEffect(() => {
49711
+ const [expanded, setExpanded] = React93.useState(true);
49712
+ const scrollRef = React93.useRef(null);
49713
+ const prevCountRef = React93.useRef(0);
49714
+ React93.useEffect(() => {
48883
49715
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
48884
49716
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
48885
49717
  }
@@ -48936,10 +49768,10 @@ function RuntimeDebugger({
48936
49768
  schema
48937
49769
  }) {
48938
49770
  const { t } = useTranslate();
48939
- const [isCollapsed, setIsCollapsed] = React90.useState(mode === "verify" ? true : defaultCollapsed);
48940
- const [isVisible, setIsVisible] = React90.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
49771
+ const [isCollapsed, setIsCollapsed] = React93.useState(mode === "verify" ? true : defaultCollapsed);
49772
+ const [isVisible, setIsVisible] = React93.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
48941
49773
  const debugData = useDebugData();
48942
- React90.useEffect(() => {
49774
+ React93.useEffect(() => {
48943
49775
  if (mode === "inline") return;
48944
49776
  return onDebugToggle((enabled) => {
48945
49777
  setIsVisible(enabled);
@@ -48948,7 +49780,7 @@ function RuntimeDebugger({
48948
49780
  }
48949
49781
  });
48950
49782
  }, [mode]);
48951
- React90.useEffect(() => {
49783
+ React93.useEffect(() => {
48952
49784
  if (mode === "inline") return;
48953
49785
  const handleKeyDown = (e) => {
48954
49786
  if (e.key === "`" && isVisible) {
@@ -49508,7 +50340,7 @@ function SequenceBar({
49508
50340
  onSlotRemove(index);
49509
50341
  }, [onSlotRemove, playing]);
49510
50342
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
49511
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
50343
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
49512
50344
  i > 0 && /* @__PURE__ */ jsx(
49513
50345
  Typography,
49514
50346
  {
@@ -50397,7 +51229,7 @@ var init_StatCard = __esm({
50397
51229
  const labelToUse = propLabel ?? propTitle;
50398
51230
  const eventBus = useEventBus();
50399
51231
  const { t } = useTranslate();
50400
- const handleActionClick = React90__default.useCallback(() => {
51232
+ const handleActionClick = React93__default.useCallback(() => {
50401
51233
  if (action?.event) {
50402
51234
  eventBus.emit(`UI:${action.event}`, {});
50403
51235
  }
@@ -50408,7 +51240,7 @@ var init_StatCard = __esm({
50408
51240
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
50409
51241
  const isLoading = externalLoading ?? false;
50410
51242
  const error = externalError;
50411
- const computeMetricValue = React90__default.useCallback(
51243
+ const computeMetricValue = React93__default.useCallback(
50412
51244
  (metric, items) => {
50413
51245
  if (metric.value !== void 0) {
50414
51246
  return metric.value;
@@ -50447,7 +51279,7 @@ var init_StatCard = __esm({
50447
51279
  },
50448
51280
  []
50449
51281
  );
50450
- const schemaStats = React90__default.useMemo(() => {
51282
+ const schemaStats = React93__default.useMemo(() => {
50451
51283
  if (!metrics || metrics.length === 0) return null;
50452
51284
  return metrics.map((metric) => ({
50453
51285
  label: metric.label,
@@ -50455,7 +51287,7 @@ var init_StatCard = __esm({
50455
51287
  format: metric.format
50456
51288
  }));
50457
51289
  }, [metrics, data, computeMetricValue]);
50458
- const calculatedTrend = React90__default.useMemo(() => {
51290
+ const calculatedTrend = React93__default.useMemo(() => {
50459
51291
  if (manualTrend !== void 0) return manualTrend;
50460
51292
  if (previousValue === void 0 || currentValue === void 0)
50461
51293
  return void 0;
@@ -51421,7 +52253,7 @@ var init_Timeline = __esm({
51421
52253
  }) => {
51422
52254
  const { t } = useTranslate();
51423
52255
  const entityData = Array.isArray(entity) ? entity : [];
51424
- const items = React90__default.useMemo(() => {
52256
+ const items = React93__default.useMemo(() => {
51425
52257
  if (propItems) return propItems;
51426
52258
  if (entityData.length === 0) return [];
51427
52259
  return entityData.map((record, idx) => {
@@ -51528,7 +52360,7 @@ var init_Timeline = __esm({
51528
52360
  }
51529
52361
  });
51530
52362
  function extractToastProps(children) {
51531
- if (!React90__default.isValidElement(children)) {
52363
+ if (!React93__default.isValidElement(children)) {
51532
52364
  if (typeof children === "string") {
51533
52365
  return { message: children };
51534
52366
  }
@@ -51566,7 +52398,7 @@ var init_ToastSlot = __esm({
51566
52398
  eventBus.emit("UI:CLOSE");
51567
52399
  };
51568
52400
  if (!isVisible) return null;
51569
- const isCustomContent = React90__default.isValidElement(children) && !message;
52401
+ const isCustomContent = React93__default.isValidElement(children) && !message;
51570
52402
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
51571
52403
  Toast,
51572
52404
  {
@@ -51582,82 +52414,442 @@ var init_ToastSlot = __esm({
51582
52414
  ToastSlot.displayName = "ToastSlot";
51583
52415
  }
51584
52416
  });
52417
+ function resolveManifestUrl4(manifest, relative) {
52418
+ if (relative == null || relative === "") return void 0;
52419
+ if (/^https?:\/\//.test(relative)) return relative;
52420
+ const base = manifest?.baseUrl;
52421
+ if (base == null) return relative;
52422
+ const cleanBase = base.replace(/\/$/, "");
52423
+ const cleanRel = relative.replace(/^\//, "");
52424
+ return `${cleanBase}/${cleanRel}`;
52425
+ }
52426
+ function readPlayer(v) {
52427
+ if (v == null || typeof v !== "object") return void 0;
52428
+ const o = v;
52429
+ return { x: num(o.x), y: num(o.y) };
52430
+ }
52431
+ function TopDownShooterBoard({
52432
+ entity,
52433
+ player: propPlayer,
52434
+ enemies: propEnemies,
52435
+ projectiles: propProjectiles,
52436
+ score: propScore,
52437
+ wave: propWave,
52438
+ lives: propLives,
52439
+ result: propResult,
52440
+ assetManifest: propAssetManifest,
52441
+ width = DEFAULT_WIDTH,
52442
+ height = DEFAULT_HEIGHT,
52443
+ spriteSize = 32,
52444
+ moveEvent = "MOVE",
52445
+ fireEvent = "FIRE",
52446
+ playAgainEvent = "PLAY_AGAIN",
52447
+ gameEndEvent = "GAME_END",
52448
+ className
52449
+ }) {
52450
+ const board = boardEntity(entity) ?? {};
52451
+ const eventBus = useEventBus();
52452
+ const { t } = useTranslate();
52453
+ const assetManifest = propAssetManifest ?? board.assetManifest;
52454
+ const player = propPlayer ?? readPlayer(board.player) ?? { x: width / 2, y: height - spriteSize };
52455
+ const enemies = useMemo(
52456
+ () => propEnemies ?? rows(board.enemies).map((r2) => ({
52457
+ id: str(r2.id),
52458
+ x: num(r2.x),
52459
+ y: num(r2.y),
52460
+ hp: num(r2.hp, 1)
52461
+ })),
52462
+ [propEnemies, board.enemies]
52463
+ );
52464
+ const projectiles = useMemo(
52465
+ () => propProjectiles ?? rows(board.projectiles).map((r2) => ({
52466
+ id: str(r2.id),
52467
+ x: num(r2.x),
52468
+ y: num(r2.y),
52469
+ vx: num(r2.vx),
52470
+ vy: num(r2.vy)
52471
+ })),
52472
+ [propProjectiles, board.projectiles]
52473
+ );
52474
+ const score = propScore ?? num(board.score, 0);
52475
+ const wave = propWave ?? num(board.wave, 1);
52476
+ const lives = propLives ?? num(board.lives, 3);
52477
+ const result = propResult ?? (str(board.result) || "none");
52478
+ const playerSprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.player);
52479
+ const enemySprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.enemy);
52480
+ const projectileSprite = resolveManifestUrl4(assetManifest, assetManifest?.features?.projectile);
52481
+ const backgroundSprite = resolveManifestUrl4(assetManifest, assetManifest?.background);
52482
+ const spriteUrls = useMemo(
52483
+ () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
52484
+ [playerSprite, enemySprite, projectileSprite]
52485
+ );
52486
+ const { getImage } = useImageCache(spriteUrls);
52487
+ const sceneRef = useRef({ player, enemies, projectiles, playerSprite, enemySprite, projectileSprite });
52488
+ sceneRef.current = { player, enemies, projectiles, playerSprite, enemySprite, projectileSprite };
52489
+ boardLog2.debug("shooter-resolve", {
52490
+ player: { x: player.x, y: player.y },
52491
+ enemyCount: enemies.length,
52492
+ projectileCount: projectiles.length,
52493
+ wave,
52494
+ lives,
52495
+ result,
52496
+ hasPlayerSprite: playerSprite != null
52497
+ });
52498
+ const onDraw = useCallback(
52499
+ (ctx, _frame) => {
52500
+ const scene = sceneRef.current;
52501
+ ctx.fillStyle = "#10141c";
52502
+ ctx.fillRect(0, 0, width, height);
52503
+ const half = spriteSize / 2;
52504
+ for (const p2 of scene.projectiles) {
52505
+ const img = scene.projectileSprite ? getImage(scene.projectileSprite) : void 0;
52506
+ if (img) {
52507
+ ctx.drawImage(img, p2.x - half / 2, p2.y - half / 2, spriteSize / 2, spriteSize / 2);
52508
+ } else {
52509
+ ctx.fillStyle = "#ffd34d";
52510
+ ctx.beginPath();
52511
+ ctx.arc(p2.x, p2.y, spriteSize / 6, 0, Math.PI * 2);
52512
+ ctx.fill();
52513
+ }
52514
+ }
52515
+ for (const e of scene.enemies) {
52516
+ const img = scene.enemySprite ? getImage(scene.enemySprite) : void 0;
52517
+ if (img) {
52518
+ ctx.drawImage(img, e.x - half, e.y - half, spriteSize, spriteSize);
52519
+ } else {
52520
+ ctx.fillStyle = "#e0524d";
52521
+ ctx.fillRect(e.x - half, e.y - half, spriteSize, spriteSize);
52522
+ }
52523
+ }
52524
+ const pImg = scene.playerSprite ? getImage(scene.playerSprite) : void 0;
52525
+ if (pImg) {
52526
+ ctx.drawImage(pImg, scene.player.x - half, scene.player.y - half, spriteSize, spriteSize);
52527
+ } else {
52528
+ ctx.fillStyle = "#4da3ff";
52529
+ ctx.beginPath();
52530
+ ctx.moveTo(scene.player.x, scene.player.y - half);
52531
+ ctx.lineTo(scene.player.x + half, scene.player.y + half);
52532
+ ctx.lineTo(scene.player.x - half, scene.player.y + half);
52533
+ ctx.closePath();
52534
+ ctx.fill();
52535
+ }
52536
+ },
52537
+ [getImage, width, height, spriteSize]
52538
+ );
52539
+ const moveEventRef = useRef(moveEvent);
52540
+ moveEventRef.current = moveEvent;
52541
+ const fireEventRef = useRef(fireEvent);
52542
+ fireEventRef.current = fireEvent;
52543
+ const resultRef = useRef(result);
52544
+ resultRef.current = result;
52545
+ const playerRef = useRef(player);
52546
+ playerRef.current = player;
52547
+ useEffect(() => {
52548
+ function onKeyDown(e) {
52549
+ if (resultRef.current !== "none") return;
52550
+ let dx = 0;
52551
+ let dy = 0;
52552
+ switch (e.key) {
52553
+ case "ArrowUp":
52554
+ case "w":
52555
+ dy = -1;
52556
+ break;
52557
+ case "ArrowDown":
52558
+ case "s":
52559
+ dy = 1;
52560
+ break;
52561
+ case "ArrowLeft":
52562
+ case "a":
52563
+ dx = -1;
52564
+ break;
52565
+ case "ArrowRight":
52566
+ case "d":
52567
+ dx = 1;
52568
+ break;
52569
+ case " ": {
52570
+ e.preventDefault();
52571
+ const evt = fireEventRef.current;
52572
+ if (evt) {
52573
+ eventBus.emit(`UI:${evt}`, { tx: playerRef.current.x, ty: 0 });
52574
+ }
52575
+ return;
52576
+ }
52577
+ default:
52578
+ return;
52579
+ }
52580
+ e.preventDefault();
52581
+ const moveEvt = moveEventRef.current;
52582
+ if (moveEvt) {
52583
+ eventBus.emit(`UI:${moveEvt}`, { dx, dy });
52584
+ }
52585
+ }
52586
+ window.addEventListener("keydown", onKeyDown);
52587
+ return () => window.removeEventListener("keydown", onKeyDown);
52588
+ }, [eventBus]);
52589
+ const handleFireClick = useCallback(
52590
+ (e) => {
52591
+ if (result !== "none") return;
52592
+ const evt = fireEventRef.current;
52593
+ if (!evt) return;
52594
+ const rect = e.currentTarget.getBoundingClientRect();
52595
+ const tx = e.clientX - rect.left;
52596
+ const ty = e.clientY - rect.top;
52597
+ eventBus.emit(`UI:${evt}`, { tx, ty });
52598
+ },
52599
+ [result, eventBus]
52600
+ );
52601
+ const handlePlayAgain = useCallback(() => {
52602
+ if (playAgainEvent) {
52603
+ eventBus.emit(`UI:${playAgainEvent}`, {});
52604
+ }
52605
+ }, [playAgainEvent, eventBus]);
52606
+ const gameEndEmittedRef = useRef(false);
52607
+ useEffect(() => {
52608
+ if ((result === "won" || result === "lost") && gameEndEvent) {
52609
+ if (!gameEndEmittedRef.current) {
52610
+ gameEndEmittedRef.current = true;
52611
+ eventBus.emit(`UI:${gameEndEvent}`, { result });
52612
+ }
52613
+ } else {
52614
+ gameEndEmittedRef.current = false;
52615
+ }
52616
+ }, [result, gameEndEvent, eventBus]);
52617
+ const isGameOver = result === "won" || result === "lost";
52618
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("top-down-shooter-board relative bg-background", className), gap: "none", children: [
52619
+ /* @__PURE__ */ jsxs(HStack, { className: "px-4 py-2 border-b border-border bg-surface", gap: "lg", align: "center", children: [
52620
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
52621
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("shooter.score") ?? "Score" }),
52622
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-warning", children: score })
52623
+ ] }),
52624
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
52625
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("shooter.wave") ?? "Wave" }),
52626
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", children: wave })
52627
+ ] }),
52628
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
52629
+ /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("shooter.lives") ?? "Lives" }),
52630
+ /* @__PURE__ */ jsx(
52631
+ Typography,
52632
+ {
52633
+ variant: "body2",
52634
+ weight: "bold",
52635
+ className: lives <= 1 ? "text-error" : "text-success",
52636
+ children: lives
52637
+ }
52638
+ )
52639
+ ] })
52640
+ ] }),
52641
+ /* @__PURE__ */ jsxs(Box, { className: "relative", onClick: handleFireClick, children: [
52642
+ /* @__PURE__ */ jsx(
52643
+ GameCanvas2D,
52644
+ {
52645
+ width,
52646
+ height,
52647
+ backgroundImage: backgroundSprite,
52648
+ assetBaseUrl: assetManifest?.baseUrl,
52649
+ onDraw
52650
+ }
52651
+ ),
52652
+ isGameOver && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
52653
+ /* @__PURE__ */ jsx(
52654
+ Typography,
52655
+ {
52656
+ variant: "h2",
52657
+ className: cn(
52658
+ "text-4xl font-black tracking-widest uppercase",
52659
+ result === "won" ? "text-warning" : "text-error"
52660
+ ),
52661
+ children: result === "won" ? t("shooter.victory") ?? "Victory!" : t("shooter.defeat") ?? "Defeat!"
52662
+ }
52663
+ ),
52664
+ /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: result === "won" ? t("shooter.cleared") ?? `Cleared wave ${wave} \u2014 score ${score}` : t("shooter.overrun") ?? "You were overrun." }),
52665
+ /* @__PURE__ */ jsx(
52666
+ Button,
52667
+ {
52668
+ variant: "primary",
52669
+ className: "px-8 py-3 font-semibold",
52670
+ onClick: handlePlayAgain,
52671
+ children: t("shooter.playAgain") ?? "Play Again"
52672
+ }
52673
+ )
52674
+ ] }) })
52675
+ ] })
52676
+ ] });
52677
+ }
52678
+ var boardLog2, DEFAULT_WIDTH, DEFAULT_HEIGHT;
52679
+ var init_TopDownShooterBoard = __esm({
52680
+ "components/game/organisms/TopDownShooterBoard.tsx"() {
52681
+ "use client";
52682
+ init_cn();
52683
+ init_useEventBus();
52684
+ init_Box();
52685
+ init_Button();
52686
+ init_Typography();
52687
+ init_Stack();
52688
+ init_GameCanvas2D();
52689
+ init_useImageCache();
52690
+ init_boardEntity();
52691
+ boardLog2 = createLogger("almadar:ui:game:top-down-shooter-board");
52692
+ DEFAULT_WIDTH = 640;
52693
+ DEFAULT_HEIGHT = 480;
52694
+ TopDownShooterBoard.displayName = "TopDownShooterBoard";
52695
+ }
52696
+ });
52697
+ function isEntityRow3(value) {
52698
+ return value != null && typeof value === "object" && !Array.isArray(value);
52699
+ }
52700
+ function TopDownShooterTemplate({
52701
+ entity,
52702
+ title = "Arena Shooter",
52703
+ player,
52704
+ enemies,
52705
+ projectiles,
52706
+ score,
52707
+ wave,
52708
+ lives,
52709
+ result,
52710
+ assetManifest,
52711
+ width,
52712
+ height,
52713
+ spriteSize,
52714
+ moveEvent,
52715
+ fireEvent,
52716
+ playAgainEvent,
52717
+ gameEndEvent,
52718
+ className
52719
+ }) {
52720
+ const resolved = isEntityRow3(entity) ? entity : void 0;
52721
+ return /* @__PURE__ */ jsxs(
52722
+ Box,
52723
+ {
52724
+ display: "flex",
52725
+ fullHeight: true,
52726
+ className: cn("top-down-shooter-template flex-col", className),
52727
+ children: [
52728
+ /* @__PURE__ */ jsx(
52729
+ HStack,
52730
+ {
52731
+ gap: "sm",
52732
+ align: "center",
52733
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
52734
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
52735
+ }
52736
+ ),
52737
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
52738
+ TopDownShooterBoard,
52739
+ {
52740
+ entity: resolved,
52741
+ player,
52742
+ enemies,
52743
+ projectiles,
52744
+ score,
52745
+ wave,
52746
+ lives,
52747
+ result,
52748
+ assetManifest,
52749
+ width,
52750
+ height,
52751
+ spriteSize,
52752
+ moveEvent,
52753
+ fireEvent,
52754
+ playAgainEvent,
52755
+ gameEndEvent,
52756
+ className: "h-full"
52757
+ }
52758
+ ) })
52759
+ ]
52760
+ }
52761
+ );
52762
+ }
52763
+ var init_TopDownShooterTemplate = __esm({
52764
+ "components/game/templates/TopDownShooterTemplate.tsx"() {
52765
+ init_cn();
52766
+ init_Box();
52767
+ init_Stack();
52768
+ init_Typography();
52769
+ init_TopDownShooterBoard();
52770
+ TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
52771
+ }
52772
+ });
52773
+ function resolveManifestUrl5(manifest, relative) {
52774
+ if (relative == null) return void 0;
52775
+ if (/^https?:\/\//.test(relative)) return relative;
52776
+ const base = manifest?.baseUrl;
52777
+ if (base == null) return relative;
52778
+ const cleanBase = base.replace(/\/$/, "");
52779
+ const cleanRel = relative.replace(/^\//, "");
52780
+ return `${cleanBase}/${cleanRel}`;
52781
+ }
51585
52782
  function buildDefaultTDTiles() {
51586
52783
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
51587
52784
  const tiles = [];
51588
52785
  for (let y = 0; y < TD_GRID_H; y++) {
51589
52786
  for (let x = 0; x < TD_GRID_W; x++) {
51590
52787
  if (pathSet.has(`${x},${y}`)) {
51591
- tiles.push({ x, y, terrain: "path", passable: false, terrainSprite: TERRAIN_SPRITES.path });
52788
+ tiles.push({ x, y, terrain: "path", passable: false });
51592
52789
  } else {
51593
52790
  const variant = (x * 3 + y * 5 + (x ^ y)) % 3;
51594
- const terrainKey = ["ground", "grass", "dirt"][variant];
51595
- tiles.push({ x, y, terrain: terrainKey, passable: true, terrainSprite: TERRAIN_SPRITES[terrainKey] ?? TERRAIN_SPRITES.ground });
52791
+ const terrainKey = ["ground", "grass", "stone"][variant];
52792
+ tiles.push({ x, y, terrain: terrainKey, passable: true });
51596
52793
  }
51597
52794
  }
51598
52795
  }
51599
52796
  return tiles;
51600
52797
  }
51601
- function tilesToIso(tiles) {
51602
- return tiles.map((t) => ({
51603
- x: t.x,
51604
- y: t.y,
51605
- terrain: t.terrain,
51606
- terrainSprite: t.terrainSprite ?? TERRAIN_SPRITES[t.terrain ?? "ground"],
51607
- passable: t.passable
51608
- }));
51609
- }
51610
- function towersToUnits(towers) {
51611
- return towers.map((t) => ({
51612
- id: t.id,
51613
- position: { x: t.x, y: t.y },
51614
- name: "Tower",
51615
- team: "player",
51616
- sprite: TOWER_SPRITE,
51617
- unitType: "guardian",
51618
- health: 1,
51619
- maxHealth: 1
51620
- }));
52798
+ function tilesToIso2(tiles, manifest) {
52799
+ return tiles.map((t) => {
52800
+ const key = t.terrain ?? "ground";
52801
+ const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
52802
+ return {
52803
+ x: t.x,
52804
+ y: t.y,
52805
+ terrain: t.terrain,
52806
+ terrainSprite: sprite,
52807
+ passable: t.passable
52808
+ };
52809
+ });
51621
52810
  }
51622
- function creepsToUnits(creeps) {
52811
+ function creepsToUnits(creeps, manifest) {
52812
+ const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
51623
52813
  return creeps.map((c) => ({
51624
52814
  id: c.id,
51625
52815
  position: { x: c.x, y: c.y },
51626
52816
  name: "Creep",
51627
52817
  team: "enemy",
51628
- sprite: CREEP_SPRITE,
51629
- unitType: "scrapper",
52818
+ sprite,
52819
+ unitType: "creep",
51630
52820
  health: c.hp,
51631
52821
  maxHealth: c.maxHp
51632
52822
  }));
51633
52823
  }
51634
- function pathToFeatures(path) {
51635
- return path.map((p2, i) => ({
51636
- id: `path-${i}`,
51637
- x: p2.x,
51638
- y: p2.y,
51639
- type: "path-marker",
51640
- sprite: `${CDN6}world-map/road_straight.png`
51641
- }));
51642
- }
51643
- function heroToUnit(hero) {
52824
+ function heroToUnit(hero, manifest) {
51644
52825
  return {
51645
52826
  id: hero.id,
51646
52827
  position: { x: hero.x, y: hero.y },
51647
52828
  name: "Hero",
51648
52829
  team: "player",
51649
- sprite: HERO_SPRITE,
51650
- unitType: "amir",
52830
+ sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
52831
+ unitType: "hero",
51651
52832
  health: 1,
51652
52833
  maxHealth: 1
51653
52834
  };
51654
52835
  }
52836
+ function towersToFeatures(towers, manifest) {
52837
+ const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
52838
+ return towers.map((t) => ({
52839
+ id: t.id,
52840
+ x: t.x,
52841
+ y: t.y,
52842
+ type: "tower",
52843
+ sprite
52844
+ }));
52845
+ }
51655
52846
  function TowerDefenseBoard({
51656
52847
  entity,
51657
52848
  tiles: propTiles,
51658
52849
  path: propPath,
51659
52850
  towers: propTowers,
51660
52851
  creeps: propCreeps,
52852
+ assetManifest: propAssetManifest,
51661
52853
  hero: propHero,
51662
52854
  gold: propGold,
51663
52855
  lives: propLives,
@@ -51680,12 +52872,51 @@ function TowerDefenseBoard({
51680
52872
  const board = boardEntity(entity) ?? {};
51681
52873
  const eventBus = useEventBus();
51682
52874
  const { t } = useTranslate();
51683
- const rawTiles = propTiles ?? rows(board.tiles);
52875
+ const assetManifest = propAssetManifest ?? board.assetManifest;
52876
+ const entityTiles = useMemo(
52877
+ () => rows(board.tiles).map((r2) => ({
52878
+ x: num(r2.x),
52879
+ y: num(r2.y),
52880
+ terrain: r2.terrain == null ? void 0 : str(r2.terrain),
52881
+ terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
52882
+ passable: r2.passable !== false
52883
+ })),
52884
+ [board.tiles]
52885
+ );
52886
+ const rawTiles = propTiles ?? entityTiles;
51684
52887
  const tiles = rawTiles.length >= TD_GRID_W * TD_GRID_H ? rawTiles : DEFAULT_TD_TILES;
51685
- const rawPath = propPath ?? rows(board.path);
52888
+ const entityPath = useMemo(
52889
+ () => rows(board.path).map((r2) => ({ x: num(r2.x), y: num(r2.y) })),
52890
+ [board.path]
52891
+ );
52892
+ const rawPath = propPath ?? entityPath;
51686
52893
  const path = rawPath.length > 0 ? rawPath : DEFAULT_TD_PATH;
51687
- const towers = propTowers ?? rows(board.towers);
51688
- const creeps = propCreeps ?? rows(board.creeps);
52894
+ const entityTowers = useMemo(
52895
+ () => rows(board.towers).map((r2) => ({
52896
+ id: str(r2.id),
52897
+ x: num(r2.x),
52898
+ y: num(r2.y),
52899
+ range: num(r2.range),
52900
+ damage: num(r2.damage),
52901
+ cooldown: num(r2.cooldown),
52902
+ lastFiredAt: r2.lastFiredAt == null ? void 0 : num(r2.lastFiredAt)
52903
+ })),
52904
+ [board.towers]
52905
+ );
52906
+ const towers = propTowers ?? entityTowers;
52907
+ const entityCreeps = useMemo(
52908
+ () => rows(board.creeps).map((r2) => ({
52909
+ id: str(r2.id),
52910
+ x: num(r2.x),
52911
+ y: num(r2.y),
52912
+ hp: num(r2.hp),
52913
+ maxHp: num(r2.maxHp),
52914
+ pathIndex: num(r2.pathIndex),
52915
+ speed: num(r2.speed)
52916
+ })),
52917
+ [board.creeps]
52918
+ );
52919
+ const creeps = propCreeps ?? entityCreeps;
51689
52920
  const hero = propHero ?? { id: "hero", x: 8, y: 8 };
51690
52921
  const gold = propGold ?? num(board.gold, 100);
51691
52922
  const lives = propLives ?? num(board.lives, 20);
@@ -51737,12 +52968,11 @@ function TowerDefenseBoard({
51737
52968
  (t2) => t2.passable !== false && !towerPositions.has(`${t2.x},${t2.y}`) && !pathPositions.has(`${t2.x},${t2.y}`)
51738
52969
  ).map((t2) => ({ x: t2.x, y: t2.y }));
51739
52970
  }, [tiles, towerPositions, pathPositions, result, gold, towerCost]);
51740
- const isoTiles = useMemo(() => tilesToIso(tiles), [tiles]);
51741
- const towerUnits = useMemo(() => towersToUnits(towers), [towers]);
51742
- const creepUnits = useMemo(() => creepsToUnits(creeps), [creeps]);
51743
- const heroUnit = useMemo(() => heroToUnit(hero), [hero]);
51744
- const isoUnits = useMemo(() => [...towerUnits, ...creepUnits, heroUnit], [towerUnits, creepUnits, heroUnit]);
51745
- const pathFeatures = useMemo(() => pathToFeatures(path), [path]);
52971
+ const isoTiles = useMemo(() => tilesToIso2(tiles, assetManifest), [tiles, assetManifest]);
52972
+ const creepUnits = useMemo(() => creepsToUnits(creeps, assetManifest), [creeps, assetManifest]);
52973
+ const heroUnit = useMemo(() => heroToUnit(hero, assetManifest), [hero, assetManifest]);
52974
+ const isoUnits = useMemo(() => [...creepUnits, heroUnit], [creepUnits, heroUnit]);
52975
+ const towerFeatures = useMemo(() => towersToFeatures(towers, assetManifest), [towers, assetManifest]);
51746
52976
  const handleTileClick = useCallback((x, y) => {
51747
52977
  if (result !== "none") return;
51748
52978
  if (pathPositions.has(`${x},${y}`)) return;
@@ -51801,7 +53031,9 @@ function TowerDefenseBoard({
51801
53031
  {
51802
53032
  tiles: isoTiles,
51803
53033
  units: isoUnits,
51804
- features: pathFeatures,
53034
+ features: towerFeatures,
53035
+ assetBaseUrl: assetManifest?.baseUrl,
53036
+ assetManifest,
51805
53037
  validMoves,
51806
53038
  hoveredTile,
51807
53039
  onTileClick: handleTileClick,
@@ -51840,7 +53072,7 @@ function TowerDefenseBoard({
51840
53072
  ] }) })
51841
53073
  ] });
51842
53074
  }
51843
- var CDN6, TD_GRID_W, TD_GRID_H, TERRAIN_SPRITES, DEFAULT_TD_PATH, DEFAULT_TD_TILES, TOWER_SPRITE, CREEP_SPRITE, HERO_SPRITE;
53075
+ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
51844
53076
  var init_TowerDefenseBoard = __esm({
51845
53077
  "components/game/organisms/TowerDefenseBoard.tsx"() {
51846
53078
  "use client";
@@ -51852,16 +53084,8 @@ var init_TowerDefenseBoard = __esm({
51852
53084
  init_Stack();
51853
53085
  init_IsometricCanvas();
51854
53086
  init_boardEntity();
51855
- CDN6 = "https://almadar-kflow-assets.web.app/shared/";
51856
53087
  TD_GRID_W = 16;
51857
53088
  TD_GRID_H = 16;
51858
- TERRAIN_SPRITES = {
51859
- ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
51860
- path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
51861
- wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
51862
- grass: `${CDN6}isometric-dungeon/Isometric/dirt_E.png`,
51863
- dirt: `${CDN6}isometric-dungeon/Isometric/dirtTiles_E.png`
51864
- };
51865
53089
  DEFAULT_TD_PATH = [
51866
53090
  { x: 2, y: 0 },
51867
53091
  { x: 2, y: 1 },
@@ -51914,9 +53138,6 @@ var init_TowerDefenseBoard = __esm({
51914
53138
  { x: 13, y: 15 }
51915
53139
  ];
51916
53140
  DEFAULT_TD_TILES = buildDefaultTDTiles();
51917
- TOWER_SPRITE = `${CDN6}sprite-sheets/guardian-sprite-sheet-se.png`;
51918
- CREEP_SPRITE = `${CDN6}sprite-sheets/scrapper-sprite-sheet-se.png`;
51919
- HERO_SPRITE = `${CDN6}sprite-sheets/amir-sprite-sheet-se.png`;
51920
53141
  TowerDefenseBoard.displayName = "TowerDefenseBoard";
51921
53142
  }
51922
53143
  });
@@ -52184,6 +53405,214 @@ var init_UncontrolledBattleBoard = __esm({
52184
53405
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
52185
53406
  }
52186
53407
  });
53408
+ function resolveManifestUrl6(manifest, relative) {
53409
+ if (relative == null) return void 0;
53410
+ if (/^https?:\/\//.test(relative)) return relative;
53411
+ const base = manifest?.baseUrl;
53412
+ if (base == null) return relative;
53413
+ const cleanBase = base.replace(/\/$/, "");
53414
+ const cleanRel = relative.replace(/^\//, "");
53415
+ return `${cleanBase}/${cleanRel}`;
53416
+ }
53417
+ function VisualNovelBoard({
53418
+ entity,
53419
+ nodes: propNodes,
53420
+ currentNodeId: propCurrentNodeId,
53421
+ assetManifest: propAssetManifest,
53422
+ typewriterSpeed = 30,
53423
+ portraitScale = 1,
53424
+ chooseEvent,
53425
+ advanceEvent,
53426
+ restartEvent,
53427
+ className
53428
+ }) {
53429
+ const board = boardEntity(entity) ?? {};
53430
+ const eventBus = useEventBus();
53431
+ const assetManifest = propAssetManifest ?? board.assetManifest;
53432
+ const entityNodes = useMemo(
53433
+ () => rows(board.nodes).map((r2) => ({
53434
+ id: str(r2.id),
53435
+ speaker: str(r2.speaker),
53436
+ text: str(r2.text),
53437
+ backgroundKey: r2.backgroundKey == null ? void 0 : str(r2.backgroundKey),
53438
+ portraitKey: r2.portraitKey == null ? void 0 : str(r2.portraitKey),
53439
+ choices: rows(r2.choices).map((c) => ({
53440
+ label: str(c.label),
53441
+ nextId: str(c.nextId)
53442
+ }))
53443
+ })),
53444
+ [board.nodes]
53445
+ );
53446
+ const rawNodes = propNodes ?? entityNodes;
53447
+ const nodes = rawNodes.length > 0 ? rawNodes : DEFAULT_NODES;
53448
+ const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
53449
+ const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
53450
+ const backgroundImage = useMemo(
53451
+ () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
53452
+ [assetManifest, currentNode?.backgroundKey]
53453
+ );
53454
+ const portraitUrl = useMemo(
53455
+ () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
53456
+ [assetManifest, currentNode?.portraitKey]
53457
+ );
53458
+ const dialogueChoices = useMemo(
53459
+ () => (currentNode?.choices ?? []).map((c) => ({ text: c.label, next: c.nextId })),
53460
+ [currentNode?.choices]
53461
+ );
53462
+ const handleChoice = useCallback(
53463
+ (choice) => {
53464
+ const index = dialogueChoices.findIndex((c) => c.next === choice.next && c.text === choice.text);
53465
+ if (chooseEvent) {
53466
+ eventBus.emit(`UI:${chooseEvent}`, { choiceIndex: index });
53467
+ }
53468
+ },
53469
+ [dialogueChoices, chooseEvent, eventBus]
53470
+ );
53471
+ const handleAdvance = useCallback(() => {
53472
+ if (advanceEvent) {
53473
+ eventBus.emit(`UI:${advanceEvent}`, {});
53474
+ }
53475
+ }, [advanceEvent, eventBus]);
53476
+ const handleRestart = useCallback(() => {
53477
+ if (restartEvent) {
53478
+ eventBus.emit(`UI:${restartEvent}`, {});
53479
+ }
53480
+ }, [restartEvent, eventBus]);
53481
+ if (!currentNode) {
53482
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("visual-novel-board relative min-h-[600px] bg-background items-center justify-center", className), gap: "lg", children: [
53483
+ /* @__PURE__ */ jsx(Typography, { variant: "h3", color: "muted", children: "No dialogue nodes" }),
53484
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleRestart, children: "Restart" })
53485
+ ] });
53486
+ }
53487
+ return /* @__PURE__ */ jsx(Box, { className: cn("visual-novel-board relative min-h-[600px] bg-background overflow-hidden", className), children: /* @__PURE__ */ jsx(
53488
+ DialogueBox,
53489
+ {
53490
+ dialogue: {
53491
+ speaker: currentNode.speaker,
53492
+ text: currentNode.text,
53493
+ choices: dialogueChoices
53494
+ },
53495
+ typewriterSpeed,
53496
+ position: "bottom",
53497
+ backgroundImage,
53498
+ portraitUrl,
53499
+ portraitScale,
53500
+ onChoice: handleChoice,
53501
+ onAdvance: handleAdvance
53502
+ }
53503
+ ) });
53504
+ }
53505
+ var DEFAULT_NODES;
53506
+ var init_VisualNovelBoard = __esm({
53507
+ "components/game/organisms/VisualNovelBoard.tsx"() {
53508
+ "use client";
53509
+ init_cn();
53510
+ init_useEventBus();
53511
+ init_Box();
53512
+ init_Typography();
53513
+ init_Stack();
53514
+ init_Button();
53515
+ init_DialogueBox();
53516
+ init_boardEntity();
53517
+ DEFAULT_NODES = [
53518
+ {
53519
+ id: "start",
53520
+ speaker: "Narrator",
53521
+ text: "The corridor stretches into shadow. A lone sentinel blocks your path.",
53522
+ backgroundKey: "corridor",
53523
+ portraitKey: "guide",
53524
+ choices: [
53525
+ { label: "Approach the sentinel.", nextId: "meet" },
53526
+ { label: "Turn back.", nextId: "retreat" }
53527
+ ]
53528
+ },
53529
+ {
53530
+ id: "meet",
53531
+ speaker: "Sentinel",
53532
+ text: "You carry the old marks. Speak your purpose, traveler.",
53533
+ backgroundKey: "forge",
53534
+ portraitKey: "rival",
53535
+ choices: [
53536
+ { label: "I seek the core.", nextId: "end" },
53537
+ { label: "I am only passing through.", nextId: "retreat" }
53538
+ ]
53539
+ },
53540
+ {
53541
+ id: "retreat",
53542
+ speaker: "Narrator",
53543
+ text: "You withdraw into the dark. The path will wait for braver feet.",
53544
+ backgroundKey: "corridor",
53545
+ choices: [{ label: "Begin again.", nextId: "start" }]
53546
+ },
53547
+ {
53548
+ id: "end",
53549
+ speaker: "Sentinel",
53550
+ text: "Then the way is open. Walk it well.",
53551
+ backgroundKey: "core",
53552
+ portraitKey: "rival",
53553
+ choices: [{ label: "Begin again.", nextId: "start" }]
53554
+ }
53555
+ ];
53556
+ VisualNovelBoard.displayName = "VisualNovelBoard";
53557
+ }
53558
+ });
53559
+ function VisualNovelTemplate({
53560
+ entity,
53561
+ title = "Visual Novel",
53562
+ nodes,
53563
+ currentNodeId,
53564
+ typewriterSpeed,
53565
+ portraitScale,
53566
+ chooseEvent,
53567
+ advanceEvent,
53568
+ restartEvent,
53569
+ className
53570
+ }) {
53571
+ const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
53572
+ return /* @__PURE__ */ jsxs(
53573
+ Box,
53574
+ {
53575
+ display: "flex",
53576
+ fullHeight: true,
53577
+ className: cn("visual-novel-template flex-col", className),
53578
+ children: [
53579
+ /* @__PURE__ */ jsx(
53580
+ HStack,
53581
+ {
53582
+ gap: "sm",
53583
+ align: "center",
53584
+ className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
53585
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
53586
+ }
53587
+ ),
53588
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
53589
+ VisualNovelBoard,
53590
+ {
53591
+ entity: resolved,
53592
+ nodes,
53593
+ currentNodeId,
53594
+ typewriterSpeed,
53595
+ portraitScale,
53596
+ chooseEvent,
53597
+ advanceEvent,
53598
+ restartEvent,
53599
+ className: "h-full"
53600
+ }
53601
+ ) })
53602
+ ]
53603
+ }
53604
+ );
53605
+ }
53606
+ var init_VisualNovelTemplate = __esm({
53607
+ "components/game/templates/VisualNovelTemplate.tsx"() {
53608
+ init_cn();
53609
+ init_Box();
53610
+ init_Stack();
53611
+ init_Typography();
53612
+ init_VisualNovelBoard();
53613
+ VisualNovelTemplate.displayName = "VisualNovelTemplate";
53614
+ }
53615
+ });
52187
53616
  function heroPosition(h) {
52188
53617
  if ("position" in h && h.position != null) return h.position;
52189
53618
  return vec2(h.position);
@@ -52524,48 +53953,48 @@ function WorldMapTemplate({
52524
53953
  }
52525
53954
  );
52526
53955
  }
52527
- var CDN7, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
53956
+ var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
52528
53957
  var init_WorldMapTemplate = __esm({
52529
53958
  "components/game/templates/WorldMapTemplate.tsx"() {
52530
53959
  init_WorldMapBoard();
52531
- CDN7 = "https://almadar-kflow-assets.web.app/shared";
53960
+ CDN5 = "https://almadar-kflow-assets.web.app/shared";
52532
53961
  DEFAULT_WORLDMAP_TILES = [
52533
- { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52534
- { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52535
- { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52536
- { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52537
- { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52538
- { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52539
- { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52540
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52541
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52542
- { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52543
- { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52544
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52545
- { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
52546
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52547
- { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52548
- { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52549
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52550
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52551
- { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
52552
- { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52553
- { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52554
- { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
52555
- { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
52556
- { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
52557
- { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
53962
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53963
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53964
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53965
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53966
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53967
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53968
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53969
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53970
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53971
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53972
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53973
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53974
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
53975
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53976
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53977
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53978
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53979
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53980
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
53981
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53982
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53983
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53984
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53985
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53986
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
52558
53987
  ];
52559
53988
  DEFAULT_WORLDMAP_UNITS = [
52560
- { id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${CDN7}/sprite-sheets/amir-sprite-sheet-se.png` },
52561
- { id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${CDN7}/sprite-sheets/archivist-sprite-sheet-se.png` }
53989
+ { id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${CDN5}/sprite-sheets/amir-sprite-sheet-se.png` },
53990
+ { id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png` }
52562
53991
  ];
52563
53992
  DEFAULT_WORLDMAP_FEATURES = [
52564
- { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN7}/scenes/world/capital.png` },
52565
- { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN7}/world-map/power_node.png` }
53993
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN5}/scenes/world/capital.png` },
53994
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN5}/world-map/power_node.png` }
52566
53995
  ];
52567
53996
  DEFAULT_WORLDMAP_MANIFEST = {
52568
- baseUrl: CDN7,
53997
+ baseUrl: CDN5,
52569
53998
  terrains: {
52570
53999
  grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
52571
54000
  water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
@@ -52585,7 +54014,7 @@ var init_WorldMapTemplate = __esm({
52585
54014
  }
52586
54015
  });
52587
54016
  function lazyThree(name, loader) {
52588
- const Lazy = React90__default.lazy(
54017
+ const Lazy = React93__default.lazy(
52589
54018
  () => loader().then((m) => {
52590
54019
  const Resolved = m[name];
52591
54020
  if (!Resolved) {
@@ -52597,13 +54026,13 @@ function lazyThree(name, loader) {
52597
54026
  })
52598
54027
  );
52599
54028
  function ThreeWrapper(props) {
52600
- return React90__default.createElement(
54029
+ return React93__default.createElement(
52601
54030
  ThreeBoundary,
52602
54031
  { name },
52603
- React90__default.createElement(
52604
- React90__default.Suspense,
54032
+ React93__default.createElement(
54033
+ React93__default.Suspense,
52605
54034
  { fallback: null },
52606
- React90__default.createElement(Lazy, props)
54035
+ React93__default.createElement(Lazy, props)
52607
54036
  )
52608
54037
  );
52609
54038
  }
@@ -52647,7 +54076,10 @@ var init_component_registry_generated = __esm({
52647
54076
  init_CalendarGrid();
52648
54077
  init_CanvasEffect();
52649
54078
  init_Card();
54079
+ init_CardBattlerBoard();
54080
+ init_CardBattlerTemplate();
52650
54081
  init_CardGrid();
54082
+ init_CardHand();
52651
54083
  init_Carousel();
52652
54084
  init_CaseStudyCard();
52653
54085
  init_CaseStudyOrganism();
@@ -52658,6 +54090,8 @@ var init_component_registry_generated = __esm({
52658
54090
  init_ChartLegend();
52659
54091
  init_Checkbox();
52660
54092
  init_ChoiceButton();
54093
+ init_CityBuilderBoard();
54094
+ init_CityBuilderTemplate();
52661
54095
  init_ClassifierBoard();
52662
54096
  init_CodeBlock();
52663
54097
  init_CodeRunnerPanel();
@@ -52878,6 +54312,8 @@ var init_component_registry_generated = __esm({
52878
54312
  init_Toast();
52879
54313
  init_ToastSlot();
52880
54314
  init_Tooltip();
54315
+ init_TopDownShooterBoard();
54316
+ init_TopDownShooterTemplate();
52881
54317
  init_TowerDefenseBoard();
52882
54318
  init_TowerDefenseTemplate();
52883
54319
  init_TraitFrame();
@@ -52893,6 +54329,8 @@ var init_component_registry_generated = __esm({
52893
54329
  init_UploadDropZone();
52894
54330
  init_VersionDiff();
52895
54331
  init_ViolationAlert();
54332
+ init_VisualNovelBoard();
54333
+ init_VisualNovelTemplate();
52896
54334
  init_VoteStack();
52897
54335
  init_WaypointMarker();
52898
54336
  init_WizardContainer();
@@ -52901,7 +54339,7 @@ var init_component_registry_generated = __esm({
52901
54339
  init_WorldMapBoard();
52902
54340
  init_WorldMapTemplate();
52903
54341
  init_XPBar();
52904
- ThreeBoundary = class extends React90__default.Component {
54342
+ ThreeBoundary = class extends React93__default.Component {
52905
54343
  constructor() {
52906
54344
  super(...arguments);
52907
54345
  __publicField(this, "state", { failed: false });
@@ -52911,7 +54349,7 @@ var init_component_registry_generated = __esm({
52911
54349
  }
52912
54350
  render() {
52913
54351
  if (this.state.failed) {
52914
- return React90__default.createElement(
54352
+ return React93__default.createElement(
52915
54353
  "div",
52916
54354
  {
52917
54355
  "data-testid": "three-unavailable",
@@ -52967,7 +54405,10 @@ var init_component_registry_generated = __esm({
52967
54405
  "CalendarGrid": CalendarGrid,
52968
54406
  "CanvasEffect": CanvasEffect,
52969
54407
  "Card": Card,
54408
+ "CardBattlerBoard": CardBattlerBoard,
54409
+ "CardBattlerTemplate": CardBattlerTemplate,
52970
54410
  "CardGrid": CardGrid,
54411
+ "CardHand": CardHand,
52971
54412
  "Carousel": Carousel,
52972
54413
  "CaseStudyCard": CaseStudyCard,
52973
54414
  "CaseStudyOrganism": CaseStudyOrganism,
@@ -52978,6 +54419,8 @@ var init_component_registry_generated = __esm({
52978
54419
  "ChartLegend": ChartLegend,
52979
54420
  "Checkbox": Checkbox,
52980
54421
  "ChoiceButton": ChoiceButton,
54422
+ "CityBuilderBoard": CityBuilderBoard,
54423
+ "CityBuilderTemplate": CityBuilderTemplate,
52981
54424
  "ClassifierBoard": ClassifierBoard,
52982
54425
  "CodeBlock": CodeBlock,
52983
54426
  "CodeRunnerPanel": CodeRunnerPanel,
@@ -53210,6 +54653,8 @@ var init_component_registry_generated = __esm({
53210
54653
  "Toast": Toast,
53211
54654
  "ToastSlot": ToastSlot,
53212
54655
  "Tooltip": Tooltip,
54656
+ "TopDownShooterBoard": TopDownShooterBoard,
54657
+ "TopDownShooterTemplate": TopDownShooterTemplate,
53213
54658
  "TowerDefenseBoard": TowerDefenseBoard,
53214
54659
  "TowerDefenseTemplate": TowerDefenseTemplate,
53215
54660
  "TraitFrame": TraitFrame,
@@ -53226,6 +54671,8 @@ var init_component_registry_generated = __esm({
53226
54671
  "VStack": VStack,
53227
54672
  "VersionDiff": VersionDiff,
53228
54673
  "ViolationAlert": ViolationAlert,
54674
+ "VisualNovelBoard": VisualNovelBoard,
54675
+ "VisualNovelTemplate": VisualNovelTemplate,
53229
54676
  "VoteStack": VoteStack,
53230
54677
  "WaypointMarker": WaypointMarker,
53231
54678
  "WizardContainer": WizardContainer,
@@ -53252,7 +54699,7 @@ function SuspenseConfigProvider({
53252
54699
  config,
53253
54700
  children
53254
54701
  }) {
53255
- return React90__default.createElement(
54702
+ return React93__default.createElement(
53256
54703
  SuspenseConfigContext.Provider,
53257
54704
  { value: config },
53258
54705
  children
@@ -53742,7 +55189,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
53742
55189
  const key = `${parentId}-${index}-trait:${traitName}`;
53743
55190
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
53744
55191
  }
53745
- return /* @__PURE__ */ jsx(React90__default.Fragment, { children: child }, `${parentId}-${index}`);
55192
+ return /* @__PURE__ */ jsx(React93__default.Fragment, { children: child }, `${parentId}-${index}`);
53746
55193
  }
53747
55194
  if (!child || typeof child !== "object") return null;
53748
55195
  const childId = `${parentId}-${index}`;
@@ -53782,14 +55229,14 @@ function isPatternConfig(value) {
53782
55229
  if (value === null || value === void 0) return false;
53783
55230
  if (typeof value !== "object") return false;
53784
55231
  if (Array.isArray(value)) return false;
53785
- if (React90__default.isValidElement(value)) return false;
55232
+ if (React93__default.isValidElement(value)) return false;
53786
55233
  if (value instanceof Date) return false;
53787
55234
  if (typeof value === "function") return false;
53788
55235
  const record = value;
53789
- return "type" in record && typeof record.type === "string" && isKnownPattern(record.type);
55236
+ return "type" in record && typeof record.type === "string" && getComponentForPattern$1(record.type) !== null;
53790
55237
  }
53791
55238
  function isPlainConfigObject(value) {
53792
- if (React90__default.isValidElement(value)) return false;
55239
+ if (React93__default.isValidElement(value)) return false;
53793
55240
  if (value instanceof Date) return false;
53794
55241
  const proto = Object.getPrototypeOf(value);
53795
55242
  return proto === Object.prototype || proto === null;
@@ -53910,6 +55357,22 @@ function SlotContentRenderer({
53910
55357
  const childrenIsRenderFn = typeof incomingChildren === "function";
53911
55358
  const { children: _childrenConfig, ...restPropsNoChildren } = content.props;
53912
55359
  const restProps = childrenIsRenderFn ? { ...restPropsNoChildren, children: incomingChildren } : restPropsNoChildren;
55360
+ const nodeSlotOverrides = {};
55361
+ for (const slotKey of CONTENT_NODE_SLOTS) {
55362
+ const slotVal = restProps[slotKey];
55363
+ if (slotVal === void 0 || slotVal === null) continue;
55364
+ if (React93__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
55365
+ if (Array.isArray(slotVal) || typeof slotVal === "object" && "type" in slotVal) {
55366
+ nodeSlotOverrides[slotKey] = renderPatternChildren(
55367
+ slotVal,
55368
+ onDismiss,
55369
+ `${content.id}-${slotKey}`,
55370
+ `${myPath}.${slotKey}`,
55371
+ content.sourceTrait,
55372
+ { slot: content.slot, transitionEvent: content.transitionEvent, fromState: content.fromState, entity: content.entity }
55373
+ );
55374
+ }
55375
+ }
53913
55376
  const renderedProps = renderPatternProps(restProps, onDismiss);
53914
55377
  const patternDef = getPatternDefinition(content.pattern);
53915
55378
  const propsSchema = patternDef?.propsSchema;
@@ -53940,6 +55403,9 @@ function SlotContentRenderer({
53940
55403
  }
53941
55404
  }
53942
55405
  const finalProps = renderedProps;
55406
+ for (const [k, v] of Object.entries(nodeSlotOverrides)) {
55407
+ finalProps[k] = v;
55408
+ }
53943
55409
  const resolvedItems = Array.isArray(
53944
55410
  finalProps.entity
53945
55411
  ) ? finalProps.entity : null;
@@ -54060,7 +55526,7 @@ function UISlotRenderer({
54060
55526
  }
54061
55527
  return wrapped;
54062
55528
  }
54063
- var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, FORM_PATTERNS, SELF_OVERLAY_PATTERNS, PATTERNS_WITH_CHILDREN;
55529
+ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, FORM_PATTERNS, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN;
54064
55530
  var init_UISlotRenderer = __esm({
54065
55531
  "components/core/organisms/UISlotRenderer.tsx"() {
54066
55532
  "use client";
@@ -54097,6 +55563,16 @@ var init_UISlotRenderer = __esm({
54097
55563
  "wizard-step"
54098
55564
  ]);
54099
55565
  SELF_OVERLAY_PATTERNS = /* @__PURE__ */ new Set(["modal", "confirm-dialog"]);
55566
+ CONTENT_NODE_SLOTS = /* @__PURE__ */ new Set([
55567
+ "logo",
55568
+ "master",
55569
+ "detail",
55570
+ "trigger",
55571
+ "content",
55572
+ "addons",
55573
+ "hud",
55574
+ "fallback"
55575
+ ]);
54100
55576
  PATTERNS_WITH_CHILDREN = /* @__PURE__ */ new Set([
54101
55577
  "stack",
54102
55578
  "vstack",
@@ -54296,7 +55772,7 @@ var AvlTransition = ({
54296
55772
  opacity = 1,
54297
55773
  className
54298
55774
  }) => {
54299
- const ids = React90__default.useMemo(() => {
55775
+ const ids = React93__default.useMemo(() => {
54300
55776
  avlTransitionId += 1;
54301
55777
  return { arrow: `avl-tr-${avlTransitionId}-arrow` };
54302
55778
  }, []);
@@ -54857,7 +56333,7 @@ var AvlStateMachine = ({
54857
56333
  color = "var(--color-primary)",
54858
56334
  animated = false
54859
56335
  }) => {
54860
- const ids = React90__default.useMemo(() => {
56336
+ const ids = React93__default.useMemo(() => {
54861
56337
  avlSmId += 1;
54862
56338
  const base = `avl-sm-${avlSmId}`;
54863
56339
  return { glow: `${base}-glow`, grad: `${base}-grad` };
@@ -55056,7 +56532,7 @@ var AvlOrbitalUnit = ({
55056
56532
  color = "var(--color-primary)",
55057
56533
  animated = false
55058
56534
  }) => {
55059
- const ids = React90__default.useMemo(() => {
56535
+ const ids = React93__default.useMemo(() => {
55060
56536
  avlOuId += 1;
55061
56537
  const base = `avl-ou-${avlOuId}`;
55062
56538
  return { glow: `${base}-glow`, grad: `${base}-grad` };
@@ -55152,7 +56628,7 @@ var AvlClosedCircuit = ({
55152
56628
  color = "var(--color-primary)",
55153
56629
  animated = false
55154
56630
  }) => {
55155
- const ids = React90__default.useMemo(() => {
56631
+ const ids = React93__default.useMemo(() => {
55156
56632
  avlCcId += 1;
55157
56633
  const base = `avl-cc-${avlCcId}`;
55158
56634
  return { glow: `${base}-glow`, grad: `${base}-grad`, arrow: `${base}-arrow` };
@@ -55307,7 +56783,7 @@ var AvlEmitListen = ({
55307
56783
  color = "var(--color-primary)",
55308
56784
  animated = false
55309
56785
  }) => {
55310
- const ids = React90__default.useMemo(() => {
56786
+ const ids = React93__default.useMemo(() => {
55311
56787
  avlElId += 1;
55312
56788
  const base = `avl-el-${avlElId}`;
55313
56789
  return { arrow: `${base}-arrow`, grad: `${base}-grad` };
@@ -55581,7 +57057,7 @@ function renderNode(node, color, glowId) {
55581
57057
  const baseR = node.type === "operator" ? 20 : 16;
55582
57058
  const r2 = Math.max(baseR, labelLen * 3.5 + 6);
55583
57059
  const nc = nodeColor(node.type, color);
55584
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
57060
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
55585
57061
  node.children.map((child, i) => {
55586
57062
  const childR = Math.max(
55587
57063
  child.type === "operator" ? 20 : 16,
@@ -55638,7 +57114,7 @@ var AvlExprTree = ({
55638
57114
  className,
55639
57115
  color = "var(--color-primary)"
55640
57116
  }) => {
55641
- const ids = React90__default.useMemo(() => {
57117
+ const ids = React93__default.useMemo(() => {
55642
57118
  avlEtId += 1;
55643
57119
  return { glow: `avl-et-${avlEtId}-glow` };
55644
57120
  }, []);
@@ -56462,7 +57938,7 @@ var SystemNode = ({ data }) => {
56462
57938
  stateChain.length > 0 && /* @__PURE__ */ jsx("svg", { width: stateChain.length * 14 + 2, height: 10, viewBox: `0 0 ${stateChain.length * 14 + 2} 10`, children: stateChain.map((s, i) => {
56463
57939
  const tc = transitionCounts[s.name] ?? 0;
56464
57940
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
56465
- return /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
57941
+ return /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
56466
57942
  /* @__PURE__ */ jsx(AvlState, { x: i * 14 + 1, y: 1, width: 10, height: 8, name: "", role, isInitial: s.isInitial, isTerminal: s.isTerminal }),
56467
57943
  i < stateChain.length - 1 && /* @__PURE__ */ jsx("line", { x1: i * 14 + 12, y1: 5, x2: i * 14 + 15, y2: 5, stroke: "var(--color-border)", strokeWidth: 0.5 })
56468
57944
  ] }, s.name);
@@ -57614,7 +59090,7 @@ function resolveLambdaBindings(body, params, item, index) {
57614
59090
  if (Array.isArray(body)) {
57615
59091
  return body.map((b) => recur(b));
57616
59092
  }
57617
- if (body !== null && typeof body === "object" && !React90__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
59093
+ if (body !== null && typeof body === "object" && !React93__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
57618
59094
  const out = {};
57619
59095
  for (const [k, v] of Object.entries(body)) {
57620
59096
  out[k] = recur(v);
@@ -57633,7 +59109,7 @@ function getSlotContentRenderer2() {
57633
59109
  function makeLambdaFn(params, lambdaBody, callerKey) {
57634
59110
  return (item, index) => {
57635
59111
  const resolvedBody = resolveLambdaBindings(lambdaBody, params, item, index);
57636
- if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React90__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
59112
+ if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React93__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
57637
59113
  return null;
57638
59114
  }
57639
59115
  const record = resolvedBody;
@@ -57652,7 +59128,7 @@ function makeLambdaFn(params, lambdaBody, callerKey) {
57652
59128
  props: childProps,
57653
59129
  priority: 0
57654
59130
  };
57655
- return React90__default.createElement(SlotContentRenderer2, { content: childContent });
59131
+ return React93__default.createElement(SlotContentRenderer2, { content: childContent });
57656
59132
  };
57657
59133
  }
57658
59134
  function convertNode(node, callerKey) {
@@ -57671,7 +59147,7 @@ function convertNode(node, callerKey) {
57671
59147
  });
57672
59148
  return anyChanged ? mapped : node;
57673
59149
  }
57674
- if (typeof node === "object" && !React90__default.isValidElement(node) && !(node instanceof Date)) {
59150
+ if (typeof node === "object" && !React93__default.isValidElement(node) && !(node instanceof Date)) {
57675
59151
  return convertObjectProps(node);
57676
59152
  }
57677
59153
  return node;
@@ -57698,7 +59174,7 @@ function convertObjectProps(props) {
57698
59174
  function convertFnFormLambdasInProps(props) {
57699
59175
  return convertObjectProps(props);
57700
59176
  }
57701
- var log11 = createLogger("almadar:ui:effects:client-handlers");
59177
+ var log10 = createLogger("almadar:ui:effects:client-handlers");
57702
59178
  function createClientEffectHandlers(options) {
57703
59179
  const { eventBus, slotSetter, navigate, notify, callService, liveEntity } = options;
57704
59180
  return {
@@ -57707,11 +59183,11 @@ function createClientEffectHandlers(options) {
57707
59183
  eventBus.emit(prefixedEvent, payload);
57708
59184
  },
57709
59185
  persist: async () => {
57710
- log11.warn("persist is server-side only, ignored on client");
59186
+ log10.warn("persist is server-side only, ignored on client");
57711
59187
  },
57712
59188
  set: (_entityId, field, value) => {
57713
59189
  if (!liveEntity) {
57714
- log11.warn("set is server-side only, ignored on client (no live entity)");
59190
+ log10.warn("set is server-side only, ignored on client (no live entity)");
57715
59191
  return;
57716
59192
  }
57717
59193
  liveEntity[field] = value;
@@ -57743,10 +59219,10 @@ function createClientEffectHandlers(options) {
57743
59219
  slotSetter.addPattern(slot, pattern, props);
57744
59220
  },
57745
59221
  navigate: navigate ?? ((path) => {
57746
- log11.warn("No navigate handler, ignoring", { path });
59222
+ log10.warn("No navigate handler, ignoring", { path });
57747
59223
  }),
57748
59224
  notify: notify ?? ((msg, type) => {
57749
- log11.debug("notify", { type, message: msg });
59225
+ log10.debug("notify", { type, message: msg });
57750
59226
  })
57751
59227
  };
57752
59228
  }
@@ -57978,7 +59454,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
57978
59454
  };
57979
59455
  }, [traitBindings]);
57980
59456
  const executeTransitionEffects = useCallback(async (params) => {
57981
- const { binding, previousState, newState, payload, flushEvent, syncOnly, log: log16 } = params;
59457
+ const { binding, previousState, newState, payload, flushEvent, syncOnly, log: log15 } = params;
57982
59458
  const traitName = binding.trait.name;
57983
59459
  const linkedEntity = binding.linkedEntity || "";
57984
59460
  const entityId = payload?.entityId;
@@ -58066,7 +59542,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
58066
59542
  ...handlers,
58067
59543
  set: async (targetId, field, value) => {
58068
59544
  if (baseSet) await baseSet(targetId, field, value);
58069
- log16.debug("set:write", {
59545
+ log15.debug("set:write", {
58070
59546
  traitName,
58071
59547
  field,
58072
59548
  value: JSON.stringify(value),
@@ -58106,7 +59582,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
58106
59582
  const executor = new EffectExecutor({ handlers: trackingHandlers, bindings: bindingCtx, context: effectContext });
58107
59583
  try {
58108
59584
  await executor.executeAll(effects);
58109
- log16.debug("effects:executed", () => ({
59585
+ log15.debug("effects:executed", () => ({
58110
59586
  traitName,
58111
59587
  transition: `${previousState}->${newState}`,
58112
59588
  event: flushEvent,
@@ -58116,7 +59592,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
58116
59592
  slotsTouched: Array.from(pendingSlots.keys()).join(",")
58117
59593
  }));
58118
59594
  for (const [slot, patterns] of pendingSlots) {
58119
- log16.debug("flush:slot", {
59595
+ log15.debug("flush:slot", {
58120
59596
  traitName,
58121
59597
  slot,
58122
59598
  patternCount: patterns.length,
@@ -58131,7 +59607,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
58131
59607
  });
58132
59608
  }
58133
59609
  } catch (error) {
58134
- log16.error("effects:error", {
59610
+ log15.error("effects:error", {
58135
59611
  traitName,
58136
59612
  transition: `${previousState}->${newState}`,
58137
59613
  event: flushEvent,
@@ -59126,7 +60602,7 @@ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
59126
60602
  init_navigation();
59127
60603
  init_verificationRegistry();
59128
60604
  var PERF_NAMESPACE = "almadar:perf:canvas";
59129
- var log13 = createLogger(PERF_NAMESPACE);
60605
+ var log12 = createLogger(PERF_NAMESPACE);
59130
60606
  var RING_SIZE = 50;
59131
60607
  var ring = [];
59132
60608
  var writeIdx = 0;
@@ -59177,7 +60653,7 @@ function perfEnd(name, startToken, detail) {
59177
60653
  }
59178
60654
  }
59179
60655
  push({ name, durationMs, ts: endTs, detail });
59180
- log13.debug(name, () => ({ durationMs, ...detail ?? {} }));
60656
+ log12.debug(name, () => ({ durationMs, ...detail ?? {} }));
59181
60657
  }
59182
60658
  var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
59183
60659
  if (!isEnabled()) return;
@@ -59187,7 +60663,7 @@ var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, com
59187
60663
  ts: commitTime,
59188
60664
  detail: { baseDuration }
59189
60665
  });
59190
- log13.debug(`profiler:${id}:${phase}`, () => ({ actualDuration, baseDuration }));
60666
+ log12.debug(`profiler:${id}:${phase}`, () => ({ actualDuration, baseDuration }));
59191
60667
  };
59192
60668
 
59193
60669
  // runtime/prepareSchemaForPreview.ts
@@ -59830,7 +61306,7 @@ init_useEventBus();
59830
61306
  // components/avl/molecules/useCanvasDnd.tsx
59831
61307
  init_useEventBus();
59832
61308
  init_useAlmadarDndCollision();
59833
- var log14 = createLogger("almadar:ui:canvas-dnd");
61309
+ var log13 = createLogger("almadar:ui:canvas-dnd");
59834
61310
  function useCanvasDraggable({
59835
61311
  id,
59836
61312
  payload,
@@ -59869,7 +61345,7 @@ function defaultEmit(eventBus, drop) {
59869
61345
  if (payload.kind === "pattern") {
59870
61346
  const patternType = payload.data.type;
59871
61347
  if (typeof patternType !== "string") {
59872
- log14.warn("default-emit:pattern:missing-type");
61348
+ log13.warn("default-emit:pattern:missing-type");
59873
61349
  return;
59874
61350
  }
59875
61351
  const out = { patternType, containerNode: target.containerNode };
@@ -59878,23 +61354,23 @@ function defaultEmit(eventBus, drop) {
59878
61354
  out.index = resolved.index;
59879
61355
  }
59880
61356
  eventBus.emit("UI:PATTERN_DROP", out);
59881
- log14.info("default-emit:pattern", { patternType, level: target.level });
61357
+ log13.info("default-emit:pattern", { patternType, level: target.level });
59882
61358
  return;
59883
61359
  }
59884
61360
  if (payload.kind === "behavior") {
59885
61361
  const behaviorName = payload.data.name;
59886
61362
  if (typeof behaviorName !== "string") {
59887
- log14.warn("default-emit:behavior:missing-name");
61363
+ log13.warn("default-emit:behavior:missing-name");
59888
61364
  return;
59889
61365
  }
59890
61366
  eventBus.emit("UI:BEHAVIOR_DROP", {
59891
61367
  behaviorName,
59892
61368
  containerNode: target.containerNode
59893
61369
  });
59894
- log14.info("default-emit:behavior", { behaviorName, level: target.level });
61370
+ log13.info("default-emit:behavior", { behaviorName, level: target.level });
59895
61371
  return;
59896
61372
  }
59897
- log14.debug("default-emit:unhandled-kind", { kind: payload.kind });
61373
+ log13.debug("default-emit:unhandled-kind", { kind: payload.kind });
59898
61374
  }
59899
61375
  function CanvasDndProvider({
59900
61376
  children,
@@ -59903,26 +61379,26 @@ function CanvasDndProvider({
59903
61379
  }) {
59904
61380
  const eventBus = useEventBus();
59905
61381
  const sensors = useAlmadarDndSensors(false);
59906
- const [activePayload, setActivePayload] = React90__default.useState(null);
59907
- const handleDragStart = React90__default.useCallback((e) => {
61382
+ const [activePayload, setActivePayload] = React93__default.useState(null);
61383
+ const handleDragStart = React93__default.useCallback((e) => {
59908
61384
  const data = e.active.data.current;
59909
61385
  const payload = data?.payload;
59910
61386
  if (payload) {
59911
61387
  setActivePayload(payload);
59912
61388
  eventBus.emit("UI:DRAG_START", { kind: payload.kind, data: payload.data });
59913
- log14.info("dragStart", { id: e.active.id, kind: payload.kind });
61389
+ log13.info("dragStart", { id: e.active.id, kind: payload.kind });
59914
61390
  } else {
59915
- log14.warn("dragStart:missing-payload", { id: e.active.id });
61391
+ log13.warn("dragStart:missing-payload", { id: e.active.id });
59916
61392
  }
59917
61393
  }, [eventBus]);
59918
- const handleDragEnd = React90__default.useCallback((e) => {
61394
+ const handleDragEnd = React93__default.useCallback((e) => {
59919
61395
  setActivePayload(null);
59920
61396
  const activeData = e.active.data.current;
59921
61397
  const payload = activeData?.payload;
59922
61398
  const overData = e.over?.data.current;
59923
61399
  const target = overData?.target;
59924
61400
  const accepts = overData?.accepts;
59925
- log14.info("dragEnd", {
61401
+ log13.info("dragEnd", {
59926
61402
  activeId: e.active.id,
59927
61403
  overId: e.over?.id,
59928
61404
  hasPayload: !!payload,
@@ -59934,7 +61410,7 @@ function CanvasDndProvider({
59934
61410
  }
59935
61411
  if (!payload || !target) return;
59936
61412
  if (accepts && !accepts.includes(payload.kind)) {
59937
- log14.debug("dragEnd:rejected:kind", { kind: payload.kind, accepts: [...accepts] });
61413
+ log13.debug("dragEnd:rejected:kind", { kind: payload.kind, accepts: [...accepts] });
59938
61414
  return;
59939
61415
  }
59940
61416
  const activator = e.activatorEvent;
@@ -59944,9 +61420,9 @@ function CanvasDndProvider({
59944
61420
  const suppressed = onDrop ? onDrop(drop) === true : false;
59945
61421
  if (!suppressed) defaultEmit(eventBus, drop);
59946
61422
  }, [eventBus, onDrop]);
59947
- const handleDragCancel = React90__default.useCallback(() => {
61423
+ const handleDragCancel = React93__default.useCallback(() => {
59948
61424
  setActivePayload(null);
59949
- log14.info("dragCancel");
61425
+ log13.info("dragCancel");
59950
61426
  }, []);
59951
61427
  return /* @__PURE__ */ jsxs(
59952
61428
  DndContext,
@@ -60698,7 +62174,7 @@ var OrbPreviewNodeInner = (props) => {
60698
62174
  }
60699
62175
  );
60700
62176
  };
60701
- var OrbPreviewNode = React90__default.memo(OrbPreviewNodeInner);
62177
+ var OrbPreviewNode = React93__default.memo(OrbPreviewNodeInner);
60702
62178
  OrbPreviewNode.displayName = "OrbPreviewNode";
60703
62179
  orbPreviewLog.debug("export-resolved", () => ({
60704
62180
  type: typeof OrbPreviewNode,
@@ -60803,7 +62279,7 @@ var EventFlowEdgeInner = (props) => {
60803
62279
  ) })
60804
62280
  ] });
60805
62281
  };
60806
- var EventFlowEdge = React90__default.memo(EventFlowEdgeInner);
62282
+ var EventFlowEdge = React93__default.memo(EventFlowEdgeInner);
60807
62283
  EventFlowEdge.displayName = "EventFlowEdge";
60808
62284
 
60809
62285
  // components/avl/molecules/BehaviorComposeNode.tsx
@@ -60950,7 +62426,7 @@ var BehaviorComposeNodeInner = (props) => {
60950
62426
  }
60951
62427
  );
60952
62428
  };
60953
- var BehaviorComposeNode = React90__default.memo(BehaviorComposeNodeInner);
62429
+ var BehaviorComposeNode = React93__default.memo(BehaviorComposeNodeInner);
60954
62430
  BehaviorComposeNode.displayName = "BehaviorComposeNode";
60955
62431
 
60956
62432
  // components/avl/molecules/avl-behavior-compose-converter.ts
@@ -61761,7 +63237,7 @@ init_AvlTransitionLane();
61761
63237
  init_AvlSwimLane();
61762
63238
  init_types();
61763
63239
  init_avl_elk_layout();
61764
- var log15 = createLogger("almadar:ui:avl:trait-scene");
63240
+ var log14 = createLogger("almadar:ui:avl:trait-scene");
61765
63241
  var SWIM_GUTTER2 = 120;
61766
63242
  var CENTER_W2 = 360;
61767
63243
  var AvlTraitScene = ({
@@ -61774,7 +63250,7 @@ var AvlTraitScene = ({
61774
63250
  const dataKey = useMemo(() => JSON.stringify(data), [data]);
61775
63251
  useEffect(() => {
61776
63252
  computeTraitLayout(data).then(setLayout).catch((error) => {
61777
- log15.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
63253
+ log14.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
61778
63254
  });
61779
63255
  }, [dataKey]);
61780
63256
  if (!layout) {
@@ -61962,7 +63438,7 @@ var TraitCardNodeInner = (props) => {
61962
63438
  }
61963
63439
  );
61964
63440
  };
61965
- var TraitCardNode = React90__default.memo(TraitCardNodeInner);
63441
+ var TraitCardNode = React93__default.memo(TraitCardNodeInner);
61966
63442
  TraitCardNode.displayName = "TraitCardNode";
61967
63443
 
61968
63444
  // components/avl/organisms/FlowCanvas.tsx
@@ -62035,7 +63511,7 @@ function FlowCanvasInner({
62035
63511
  initialOrbital
62036
63512
  );
62037
63513
  const [expandedBehaviorAlias, setExpandedBehaviorAlias] = useState(void 0);
62038
- const screenSizeUserOverrideRef = React90__default.useRef(false);
63514
+ const screenSizeUserOverrideRef = React93__default.useRef(false);
62039
63515
  const [screenSize, setScreenSize] = useState(
62040
63516
  () => typeof window === "undefined" ? "laptop" : detectScreenSize(window.innerWidth)
62041
63517
  );
@@ -62419,7 +63895,7 @@ var ZoomBreadcrumb = ({
62419
63895
  if (eventName && band === "detail") {
62420
63896
  segments.push({ icon: "\u26A1", label: eventName });
62421
63897
  }
62422
- return /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 z-10 flex items-center gap-1 px-2 py-1 rounded-md bg-card/90 border border-border text-xs text-muted-foreground backdrop-blur-sm", children: segments.map((seg, i) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
63898
+ return /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 z-10 flex items-center gap-1 px-2 py-1 rounded-md bg-card/90 border border-border text-xs text-muted-foreground backdrop-blur-sm", children: segments.map((seg, i) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
62423
63899
  i > 0 && /* @__PURE__ */ jsx("span", { className: "opacity-40", children: ">" }),
62424
63900
  /* @__PURE__ */ jsx("span", { className: "opacity-60", children: seg.icon }),
62425
63901
  /* @__PURE__ */ jsx("span", { children: seg.label })
@@ -62760,7 +64236,7 @@ var EventWireOverlay = ({
62760
64236
  containerW,
62761
64237
  containerH
62762
64238
  }) => {
62763
- const ids = React90__default.useMemo(() => {
64239
+ const ids = React93__default.useMemo(() => {
62764
64240
  avlOczWireId += 1;
62765
64241
  return { arrow: `avl-ocz-wire-${avlOczWireId}-arrow` };
62766
64242
  }, []);
@@ -63127,7 +64603,7 @@ var AvlOrbitalsCosmicZoom = ({
63127
64603
  borderRadius: 6,
63128
64604
  border: `1px solid ${color}`
63129
64605
  },
63130
- children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxs(React90__default.Fragment, { children: [
64606
+ children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxs(React93__default.Fragment, { children: [
63131
64607
  i > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", style: { opacity: 0.5, color }, children: "/" }),
63132
64608
  i < breadcrumbs.length - 1 ? /* @__PURE__ */ jsx(
63133
64609
  Box,