@dreamboard-games/sdk 0.2.1-alpha.0 → 0.3.0-alpha.1

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 (363) hide show
  1. package/dist/{HandView-ncJIVLhN.d.ts → HandView-PYDmehVD.d.ts} +1 -1
  2. package/dist/{ResourceCounter-CTREyF73.d.ts → ResourceCounter-BTXklCEZ.d.ts} +1 -1
  3. package/dist/{ThemeProvider-fy0_QzgO.d.ts → ThemeProvider-DvMl17Ny.d.ts} +1 -1
  4. package/dist/attributes-BeRyboMS.d.ts +279 -0
  5. package/dist/browser-interaction.d.ts +708 -0
  6. package/dist/browser-interaction.js +106 -0
  7. package/dist/{chunk-KAELH4KC.js → chunk-3RQEICD3.js} +2 -2
  8. package/dist/{chunk-TDSWKVZ4.js → chunk-ADYH6PVT.js} +2457 -1265
  9. package/dist/chunk-ADYH6PVT.js.map +1 -0
  10. package/dist/{chunk-YFY3RL52.js → chunk-P7VMTJ5D.js} +2 -2
  11. package/dist/{chunk-YFY3RL52.js.map → chunk-P7VMTJ5D.js.map} +1 -1
  12. package/dist/chunk-QLG6VEMW.js +1691 -0
  13. package/dist/chunk-QLG6VEMW.js.map +1 -0
  14. package/dist/{chunk-WYPQ3GG5.js → chunk-QZ6X4B5P.js} +1177 -1106
  15. package/dist/chunk-QZ6X4B5P.js.map +1 -0
  16. package/dist/{chunk-GKKBPPSW.js → chunk-TXXLS3OI.js} +405 -309
  17. package/dist/chunk-TXXLS3OI.js.map +1 -0
  18. package/dist/{chunk-FDNZTDD6.js → chunk-W6SGFWXH.js} +48 -44
  19. package/dist/chunk-W6SGFWXH.js.map +1 -0
  20. package/dist/{chunk-MKXPVOUT.js → chunk-Y2AFYBMB.js} +48 -4
  21. package/dist/chunk-Y2AFYBMB.js.map +1 -0
  22. package/dist/{index-BwqPQtBu.d.ts → codegen.d.ts} +57 -565
  23. package/dist/{infrastructure/workspace-codegen.js → codegen.js} +3 -3
  24. package/dist/{components-D5ZRE2Hl.d.ts → components-DaIqi9QM.d.ts} +48 -37
  25. package/dist/{hex-board-view-D_07hO6O.d.ts → hex-board-view-UCUjMALd.d.ts} +3 -2
  26. package/dist/{infrastructure/reducer-bundle-abi.d.ts → index.d-BGqVifr_.d.ts} +289 -10
  27. package/dist/index.js +1 -1
  28. package/dist/package-set.d.ts +2 -2
  29. package/dist/package-set.js +1 -1
  30. package/dist/primitive-props-BNHDkgd7.d.ts +16 -0
  31. package/dist/reducer-contract.d.ts +3 -0
  32. package/dist/{infrastructure/reducer-bundle-abi.js → reducer-contract.js} +4 -4
  33. package/dist/reducer.d.ts +185 -179
  34. package/dist/reducer.js +1637 -1353
  35. package/dist/reducer.js.map +1 -1
  36. package/dist/runtime/primitives.d.ts +10 -9
  37. package/dist/runtime/primitives.js +8 -7
  38. package/dist/runtime/runtime-api.d.ts +2 -0
  39. package/dist/runtime/runtime-api.js +1 -0
  40. package/dist/runtime/workspace-contract.d.ts +63 -17
  41. package/dist/runtime/workspace-contract.js +5 -5
  42. package/dist/{runtime-api-DWxvTr-O.d.ts → runtime-api-tGL3ArsB.d.ts} +109 -4
  43. package/dist/runtime.d.ts +12 -57
  44. package/dist/runtime.js +487 -7
  45. package/dist/runtime.js.map +1 -1
  46. package/dist/testing.d.ts +4 -4
  47. package/dist/testing.js.map +1 -1
  48. package/dist/types.d.ts +1531 -85
  49. package/dist/types.js +1 -3
  50. package/dist/types.js.map +1 -1
  51. package/dist/ui/components.d.ts +7 -8
  52. package/dist/ui/components.js +1 -1
  53. package/dist/ui/defaults.d.ts +1 -1
  54. package/dist/ui/{types/player-state.d.ts → player-state.d.ts} +2 -2
  55. package/dist/{ui-contract-iQfTtUSL.d.ts → ui-contract-SctM4ibF.d.ts} +157 -150
  56. package/dist/ui.d.ts +10 -11
  57. package/dist/ui.js +2 -2
  58. package/package.json +35 -74
  59. package/dist/bundle-CDd5FKeD.d.ts +0 -283
  60. package/dist/cards-Sl3b40Mv.d.ts +0 -13
  61. package/dist/chunk-7YAHLYBR.js +0 -481
  62. package/dist/chunk-7YAHLYBR.js.map +0 -1
  63. package/dist/chunk-FDNZTDD6.js.map +0 -1
  64. package/dist/chunk-GKKBPPSW.js.map +0 -1
  65. package/dist/chunk-I46YJSOD.js +0 -1
  66. package/dist/chunk-MKXPVOUT.js.map +0 -1
  67. package/dist/chunk-T52J5RMF.js +0 -1
  68. package/dist/chunk-TDSWKVZ4.js.map +0 -1
  69. package/dist/chunk-U5C6BONG.js +0 -34
  70. package/dist/chunk-U5C6BONG.js.map +0 -1
  71. package/dist/chunk-WYPQ3GG5.js.map +0 -1
  72. package/dist/generated/runtime/primitives.d.ts +0 -12
  73. package/dist/generated/runtime/primitives.js +0 -180
  74. package/dist/generated/runtime/primitives.js.map +0 -1
  75. package/dist/generated/runtime-api.d.ts +0 -3
  76. package/dist/generated/runtime-api.js +0 -2
  77. package/dist/generated/runtime.d.ts +0 -14
  78. package/dist/generated/runtime.js +0 -18
  79. package/dist/generated/runtime.js.map +0 -1
  80. package/dist/generated/workspace-contract.d.ts +0 -14
  81. package/dist/generated/workspace-contract.js +0 -14
  82. package/dist/generated/workspace-contract.js.map +0 -1
  83. package/dist/infrastructure/reducer-bundle-abi.js.map +0 -1
  84. package/dist/infrastructure/workspace-codegen.d.ts +0 -53
  85. package/dist/infrastructure/workspace-codegen.js.map +0 -1
  86. package/dist/manifest-contract-BNHVGFtU.d.ts +0 -9
  87. package/dist/primitive-props-DpKs-GCr.d.ts +0 -11
  88. package/dist/runtime/types/runtime-api.d.ts +0 -1
  89. package/dist/runtime/types/runtime-api.js +0 -2
  90. package/dist/runtime-api-3dshj6kK.d.ts +0 -101
  91. package/dist/slots-1GPGihk8.d.ts +0 -8
  92. package/src/generated/reducer-contract/builders.ts +0 -90
  93. package/src/generated/reducer-contract/version.ts +0 -9
  94. package/src/generated/reducer-contract/wire.ts +0 -100
  95. package/src/generated/reducer-contract/zod.ts +0 -103
  96. package/src/generated/runtime/primitives.ts +0 -2
  97. package/src/generated/runtime-api.ts +0 -5
  98. package/src/generated/runtime.ts +0 -35
  99. package/src/generated/workspace-contract.ts +0 -2
  100. package/src/index.ts +0 -7
  101. package/src/infrastructure/reducer-bundle-abi.ts +0 -8
  102. package/src/infrastructure/reducer-contract/bundle.ts +0 -37
  103. package/src/infrastructure/workspace-codegen/hex-geometry.ts +0 -69
  104. package/src/infrastructure/workspace-codegen/index.ts +0 -64
  105. package/src/infrastructure/workspace-codegen/manifest-contract.ts +0 -6632
  106. package/src/infrastructure/workspace-codegen/manifest-validation.ts +0 -795
  107. package/src/infrastructure/workspace-codegen/ownership.ts +0 -131
  108. package/src/infrastructure/workspace-codegen/preset-card-sets.ts +0 -169
  109. package/src/infrastructure/workspace-codegen/seeds.ts +0 -1705
  110. package/src/infrastructure/workspace-codegen.ts +0 -1
  111. package/src/package-set.ts +0 -19
  112. package/src/reducer/authoring/contract.ts +0 -157
  113. package/src/reducer/authoring/effect.ts +0 -224
  114. package/src/reducer/authoring/game.ts +0 -23
  115. package/src/reducer/authoring/interaction.ts +0 -98
  116. package/src/reducer/authoring/phase.ts +0 -300
  117. package/src/reducer/authoring/types.ts +0 -70
  118. package/src/reducer/authoring/validation.ts +0 -382
  119. package/src/reducer/authoring/view-stage.ts +0 -68
  120. package/src/reducer/authoring.ts +0 -29
  121. package/src/reducer/bundle/ingress-bundle.ts +0 -491
  122. package/src/reducer/bundle/trusted/engine-instruction-resolver.ts +0 -254
  123. package/src/reducer/bundle/trusted/flow-instruction-resolver.ts +0 -73
  124. package/src/reducer/bundle/trusted/instruction-runner.ts +0 -414
  125. package/src/reducer/bundle/trusted/interaction-authorization.ts +0 -137
  126. package/src/reducer/bundle/trusted/interaction-collectors.ts +0 -859
  127. package/src/reducer/bundle/trusted/interaction-decision.ts +0 -747
  128. package/src/reducer/bundle/trusted/interaction-resolver.ts +0 -95
  129. package/src/reducer/bundle/trusted/interaction-types.ts +0 -171
  130. package/src/reducer/bundle/trusted/lifecycle-runner.ts +0 -427
  131. package/src/reducer/bundle/trusted/projection-builder.ts +0 -356
  132. package/src/reducer/bundle/trusted/projection-context.ts +0 -39
  133. package/src/reducer/bundle/trusted/rng-sampler.ts +0 -150
  134. package/src/reducer/bundle/trusted/runtime-registry.ts +0 -120
  135. package/src/reducer/bundle/trusted/runtime-scope.ts +0 -336
  136. package/src/reducer/bundle/trusted/simultaneous-player.ts +0 -97
  137. package/src/reducer/bundle/trusted/stage-resolver.ts +0 -87
  138. package/src/reducer/bundle/trusted/static-projection.ts +0 -116
  139. package/src/reducer/bundle/trusted/trusted-runtime-args.ts +0 -97
  140. package/src/reducer/bundle/trusted/trusted-runtime-result.ts +0 -39
  141. package/src/reducer/bundle/trusted/trusted-setup-profiles.ts +0 -43
  142. package/src/reducer/bundle/trusted/trusted-state-codec.ts +0 -48
  143. package/src/reducer/bundle/trusted-bundle.ts +0 -97
  144. package/src/reducer/bundle/types.ts +0 -171
  145. package/src/reducer/bundle.ts +0 -2
  146. package/src/reducer/client-param-schemas.ts +0 -57
  147. package/src/reducer/compose.ts +0 -34
  148. package/src/reducer/core/runtime-input.ts +0 -30
  149. package/src/reducer/core/runtime-instruction.ts +0 -59
  150. package/src/reducer/core/types.ts +0 -62
  151. package/src/reducer/definition-index.ts +0 -277
  152. package/src/reducer/derived.ts +0 -106
  153. package/src/reducer/effects.ts +0 -92
  154. package/src/reducer/engine/runtime-instruction-engine.ts +0 -155
  155. package/src/reducer/ingress/decode-runtime-input.ts +0 -7
  156. package/src/reducer/ingress/decode-session-state.ts +0 -9
  157. package/src/reducer/ingress/encode-session-state.ts +0 -6
  158. package/src/reducer/ingress/input-codec.ts +0 -18
  159. package/src/reducer/ingress/phase-schemas.ts +0 -62
  160. package/src/reducer/ingress/raw-types.ts +0 -107
  161. package/src/reducer/ingress/runtime-codec.ts +0 -14
  162. package/src/reducer/ingress/runtime-payload.ts +0 -13
  163. package/src/reducer/ingress/session-codec.ts +0 -392
  164. package/src/reducer/ingress/types.ts +0 -6
  165. package/src/reducer/inputs/boardInput.ts +0 -217
  166. package/src/reducer/inputs/boardTarget.ts +0 -190
  167. package/src/reducer/inputs/cardInput.ts +0 -86
  168. package/src/reducer/inputs/cardTarget.ts +0 -101
  169. package/src/reducer/inputs/choiceTarget.ts +0 -104
  170. package/src/reducer/inputs/defineInputs.ts +0 -71
  171. package/src/reducer/inputs/formInput.ts +0 -809
  172. package/src/reducer/inputs/many.ts +0 -120
  173. package/src/reducer/inputs/promptInput.ts +0 -87
  174. package/src/reducer/inputs/rngInput.ts +0 -58
  175. package/src/reducer/inputs/targetRule.ts +0 -123
  176. package/src/reducer/inputs.ts +0 -41
  177. package/src/reducer/model/definition.ts +0 -1072
  178. package/src/reducer/model/extract.ts +0 -745
  179. package/src/reducer/model/manifest.ts +0 -570
  180. package/src/reducer/model/queries.ts +0 -641
  181. package/src/reducer/model/runtime.ts +0 -264
  182. package/src/reducer/model/spec.ts +0 -1386
  183. package/src/reducer/model/table.ts +0 -260
  184. package/src/reducer/model.ts +0 -7
  185. package/src/reducer/ops.ts +0 -1034
  186. package/src/reducer/parse-utils.ts +0 -28
  187. package/src/reducer/per-player.ts +0 -422
  188. package/src/reducer/rng.ts +0 -69
  189. package/src/reducer/schema-helpers.ts +0 -185
  190. package/src/reducer/setup-bootstrap-helpers.ts +0 -171
  191. package/src/reducer/setup-bootstrap.ts +0 -481
  192. package/src/reducer/table-ops.ts +0 -2671
  193. package/src/reducer/table-queries.ts +0 -372
  194. package/src/reducer/transaction.ts +0 -120
  195. package/src/reducer.ts +0 -314
  196. package/src/runtime/primitives.ts +0 -1
  197. package/src/runtime/types/runtime-api.ts +0 -1
  198. package/src/runtime/workspace-contract.ts +0 -32
  199. package/src/runtime-internal/components/InteractionForm.tsx +0 -1309
  200. package/src/runtime-internal/components/PluginRuntime.tsx +0 -103
  201. package/src/runtime-internal/components/board/target-layer.ts +0 -70
  202. package/src/runtime-internal/context/ClientParamSchemaContext.tsx +0 -44
  203. package/src/runtime-internal/context/InteractionDraftContext.tsx +0 -279
  204. package/src/runtime-internal/context/PluginSessionContext.tsx +0 -47
  205. package/src/runtime-internal/context/PluginStateContext.tsx +0 -262
  206. package/src/runtime-internal/context/RuntimeContext.tsx +0 -96
  207. package/src/runtime-internal/defaults/components.tsx +0 -409
  208. package/src/runtime-internal/defaults/index.ts +0 -11
  209. package/src/runtime-internal/errors/ValidationError.ts +0 -29
  210. package/src/runtime-internal/hooks/useActivePlayers.ts +0 -33
  211. package/src/runtime-internal/hooks/useBoardInteractions.ts +0 -665
  212. package/src/runtime-internal/hooks/useGameSelector.ts +0 -105
  213. package/src/runtime-internal/hooks/useGameView.ts +0 -9
  214. package/src/runtime-internal/hooks/useInteractionByKey.ts +0 -354
  215. package/src/runtime-internal/hooks/useInteractionHandle.ts +0 -438
  216. package/src/runtime-internal/hooks/useIsMyTurn.ts +0 -20
  217. package/src/runtime-internal/hooks/useLobby.ts +0 -76
  218. package/src/runtime-internal/hooks/useMe.ts +0 -48
  219. package/src/runtime-internal/hooks/usePlayerInfo.ts +0 -28
  220. package/src/runtime-internal/hooks/usePlayerTurnOrder.ts +0 -23
  221. package/src/runtime-internal/hooks/usePluginRuntime.ts +0 -147
  222. package/src/runtime-internal/hooks/useSeatInbox.ts +0 -61
  223. package/src/runtime-internal/hooks/useSimultaneousPhase.ts +0 -10
  224. package/src/runtime-internal/index.ts +0 -42
  225. package/src/runtime-internal/internal.ts +0 -43
  226. package/src/runtime-internal/plugin-styles.css +0 -250
  227. package/src/runtime-internal/primitives/board.tsx +0 -459
  228. package/src/runtime-internal/primitives/dialog-lifecycle.ts +0 -58
  229. package/src/runtime-internal/primitives/dice.tsx +0 -79
  230. package/src/runtime-internal/primitives/game-ui-provider.tsx +0 -35
  231. package/src/runtime-internal/primitives/game.tsx +0 -387
  232. package/src/runtime-internal/primitives/hand-intent-adapter.ts +0 -147
  233. package/src/runtime-internal/primitives/hand-surface.tsx +0 -594
  234. package/src/runtime-internal/primitives/index.ts +0 -196
  235. package/src/runtime-internal/primitives/interaction-form-binding.tsx +0 -56
  236. package/src/runtime-internal/primitives/interaction-submit.ts +0 -90
  237. package/src/runtime-internal/primitives/interaction.tsx +0 -987
  238. package/src/runtime-internal/primitives/phase.tsx +0 -43
  239. package/src/runtime-internal/primitives/player-roster.tsx +0 -302
  240. package/src/runtime-internal/primitives/primitive-props.tsx +0 -101
  241. package/src/runtime-internal/primitives/prompt.tsx +0 -255
  242. package/src/runtime-internal/primitives/ui.tsx +0 -60
  243. package/src/runtime-internal/primitives/zone.tsx +0 -791
  244. package/src/runtime-internal/reducer.ts +0 -30
  245. package/src/runtime-internal/runtime/createPluginRuntimeAPI.ts +0 -605
  246. package/src/runtime-internal/types/plugin-state.ts +0 -508
  247. package/src/runtime-internal/types/reducer-state.ts +0 -24
  248. package/src/runtime-internal/types/runtime-api.ts +0 -114
  249. package/src/runtime-internal/ui-contract.ts +0 -519
  250. package/src/runtime-internal/utils/card-intent-adapter.ts +0 -546
  251. package/src/runtime-internal/utils/interaction-inputs.ts +0 -492
  252. package/src/runtime-internal/utils/interaction-labels.ts +0 -23
  253. package/src/runtime-internal/utils/interaction-router.ts +0 -273
  254. package/src/runtime-internal/utils/interaction-status.ts +0 -74
  255. package/src/runtime-internal/workspace-contract.ts +0 -1170
  256. package/src/runtime.ts +0 -34
  257. package/src/testing/create-expect-api.ts +0 -352
  258. package/src/testing/create-test-runtime.ts +0 -381
  259. package/src/testing/definitions.ts +0 -127
  260. package/src/testing/index.ts +0 -3
  261. package/src/testing.ts +0 -1
  262. package/src/type-stubs/manifest-contract.d.ts +0 -42
  263. package/src/type-stubs/manifest-contract.js +0 -72
  264. package/src/type-stubs/ui-contract.d.ts +0 -5
  265. package/src/type-stubs/ui-contract.js +0 -1
  266. package/src/types/authoring-card-properties.type-test.ts +0 -266
  267. package/src/types/authoring.ts +0 -1282
  268. package/src/types/cards.ts +0 -19
  269. package/src/types/contracts.ts +0 -1550
  270. package/src/types/generated-helpers.ts +0 -35
  271. package/src/types/index.ts +0 -147
  272. package/src/types/slots.ts +0 -11
  273. package/src/types.ts +0 -1
  274. package/src/ui/components/ActionButton.tsx +0 -97
  275. package/src/ui/components/ActionPanel.tsx +0 -315
  276. package/src/ui/components/Card.tsx +0 -378
  277. package/src/ui/components/CardDragSurface.tsx +0 -1076
  278. package/src/ui/components/ChromeSuppressionContext.tsx +0 -70
  279. package/src/ui/components/CostDisplay.tsx +0 -145
  280. package/src/ui/components/DiceRoller.tsx +0 -581
  281. package/src/ui/components/Drawer.tsx +0 -180
  282. package/src/ui/components/ErrorBoundary.tsx +0 -275
  283. package/src/ui/components/GameEndDisplay.tsx +0 -398
  284. package/src/ui/components/GameSkeleton.tsx +0 -260
  285. package/src/ui/components/Hand.tsx +0 -468
  286. package/src/ui/components/HandDock.tsx +0 -299
  287. package/src/ui/components/HandView.tsx +0 -441
  288. package/src/ui/components/MobileHandTray.tsx +0 -381
  289. package/src/ui/components/MoreActions.tsx +0 -143
  290. package/src/ui/components/PhaseIndicator.tsx +0 -341
  291. package/src/ui/components/PlayArea.tsx +0 -146
  292. package/src/ui/components/PrimaryActionButton.tsx +0 -336
  293. package/src/ui/components/PrimaryButton.tsx +0 -45
  294. package/src/ui/components/ResourceCounter.tsx +0 -270
  295. package/src/ui/components/StagingZone.tsx +0 -134
  296. package/src/ui/components/ThemedButton.tsx +0 -113
  297. package/src/ui/components/Toast.tsx +0 -264
  298. package/src/ui/components/board/HexGrid.tsx +0 -1294
  299. package/src/ui/components/board/NetworkGraph.tsx +0 -476
  300. package/src/ui/components/board/SlotSystem.tsx +0 -388
  301. package/src/ui/components/board/SquareGrid.tsx +0 -1165
  302. package/src/ui/components/board/TrackBoard.tsx +0 -496
  303. package/src/ui/components/board/ZoneMap.tsx +0 -448
  304. package/src/ui/components/board/hex-board-view.ts +0 -123
  305. package/src/ui/components/board/index.ts +0 -142
  306. package/src/ui/components/board/interaction-accessibility.ts +0 -21
  307. package/src/ui/components/board/target-layer.ts +0 -66
  308. package/src/ui/components/card-render-content.type-test.ts +0 -27
  309. package/src/ui/components/hand-layout-math.ts +0 -163
  310. package/src/ui/components/hand-pointer-engine.ts +0 -413
  311. package/src/ui/components/index.ts +0 -245
  312. package/src/ui/components.ts +0 -1
  313. package/src/ui/defaults/components.tsx +0 -106
  314. package/src/ui/defaults/index.ts +0 -8
  315. package/src/ui/defaults.ts +0 -1
  316. package/src/ui/errors/ValidationError.ts +0 -29
  317. package/src/ui/helpers/cards.ts +0 -19
  318. package/src/ui/helpers/track-board.ts +0 -211
  319. package/src/ui/hooks/useBoardTopology.ts +0 -316
  320. package/src/ui/hooks/useCards.ts +0 -10
  321. package/src/ui/hooks/useHandCardPointer.ts +0 -381
  322. package/src/ui/hooks/useHandLayout.ts +0 -378
  323. package/src/ui/hooks/useHandPresentation.ts +0 -121
  324. package/src/ui/hooks/useHexBoard.ts +0 -74
  325. package/src/ui/hooks/useHexGrid.ts +0 -185
  326. package/src/ui/hooks/useIsMobile.ts +0 -35
  327. package/src/ui/hooks/usePanZoom.ts +0 -278
  328. package/src/ui/hooks/useSquareBoard.ts +0 -124
  329. package/src/ui/hooks/useSquareGrid.ts +0 -328
  330. package/src/ui/index.ts +0 -98
  331. package/src/ui/internal/ui/alert.tsx +0 -51
  332. package/src/ui/internal/ui/button.tsx +0 -58
  333. package/src/ui/internal/ui/dialog.tsx +0 -134
  334. package/src/ui/internal/ui/input.tsx +0 -21
  335. package/src/ui/internal/ui/label.tsx +0 -21
  336. package/src/ui/internal/ui/select.tsx +0 -129
  337. package/src/ui/internal/ui/tooltip.tsx +0 -54
  338. package/src/ui/internal/ui/utils.ts +0 -5
  339. package/src/ui/plugin-styles.css +0 -250
  340. package/src/ui/primitives/dialog-lifecycle.ts +0 -58
  341. package/src/ui/primitives/dice.tsx +0 -79
  342. package/src/ui/primitives/primitive-props.tsx +0 -101
  343. package/src/ui/theme/ThemeProvider.tsx +0 -252
  344. package/src/ui/theme/board.ts +0 -61
  345. package/src/ui/theme/css-vars.ts +0 -105
  346. package/src/ui/theme/derive.ts +0 -240
  347. package/src/ui/theme/index.ts +0 -61
  348. package/src/ui/theme/presets/arcade.ts +0 -261
  349. package/src/ui/theme/presets/studio.ts +0 -261
  350. package/src/ui/theme/presets/tabletop.ts +0 -266
  351. package/src/ui/theme/tokens.ts +0 -392
  352. package/src/ui/types/hex-color.ts +0 -20
  353. package/src/ui/types/player-state.ts +0 -463
  354. package/src/ui/types/tiled-board.ts +0 -785
  355. package/src/ui/types/visual-state.ts +0 -137
  356. package/src/ui.ts +0 -1
  357. /package/dist/{chunk-I46YJSOD.js.map → browser-interaction.js.map} +0 -0
  358. /package/dist/{chunk-KAELH4KC.js.map → chunk-3RQEICD3.js.map} +0 -0
  359. /package/dist/{chunk-T52J5RMF.js.map → codegen.js.map} +0 -0
  360. /package/dist/{generated/runtime-api.js.map → reducer-contract.js.map} +0 -0
  361. /package/dist/runtime/{types/runtime-api.js.map → runtime-api.js.map} +0 -0
  362. /package/dist/ui/{types/player-state.js → player-state.js} +0 -0
  363. /package/dist/ui/{types/player-state.js.map → player-state.js.map} +0 -0
@@ -2964,25 +2964,235 @@ function StagingZone({
2964
2964
  );
2965
2965
  }
2966
2966
 
2967
- // src/ui/components/CardDragSurface.tsx
2967
+ // src/ui/components/card-drag/use-drop-target-registry.ts
2968
+ import { createContext as createContext3, useCallback as useCallback5, useContext as useContext3, useRef as useRef2 } from "react";
2969
+ var CardDragSurfaceContext = createContext3(null);
2970
+ function useCardDragSurface() {
2971
+ return useContext3(CardDragSurfaceContext);
2972
+ }
2973
+ function useDropTargetRegistry({
2974
+ hitTestInsetPx,
2975
+ activeDragRef,
2976
+ setActive
2977
+ }) {
2978
+ const targetsRef = useRef2(/* @__PURE__ */ new Map());
2979
+ const orderCounterRef = useRef2(0);
2980
+ const registerTarget = useCallback5(
2981
+ (target) => {
2982
+ targetsRef.current.set(target.targetId, {
2983
+ ...target,
2984
+ order: target.order || ++orderCounterRef.current
2985
+ });
2986
+ return () => {
2987
+ targetsRef.current.delete(target.targetId);
2988
+ const active = activeDragRef.current;
2989
+ if (active && active.keyboardFocusedTargetId === target.targetId) {
2990
+ setActive({ ...active, keyboardFocusedTargetId: null });
2991
+ }
2992
+ };
2993
+ },
2994
+ [activeDragRef, setActive]
2995
+ );
2996
+ const updateTarget = useCallback5(
2997
+ (targetId, patch) => {
2998
+ const existing = targetsRef.current.get(targetId);
2999
+ if (!existing) return;
3000
+ targetsRef.current.set(targetId, { ...existing, ...patch });
3001
+ },
3002
+ []
3003
+ );
3004
+ const isTargetUsable = useCallback5((target) => {
3005
+ return !target.disabled && target.eligible !== false;
3006
+ }, []);
3007
+ const resolveDropTarget = useCallback5(
3008
+ (point) => {
3009
+ for (const target of targetsRef.current.values()) {
3010
+ if (!isTargetUsable(target)) continue;
3011
+ const rect = target.element.getBoundingClientRect();
3012
+ if (point.x >= rect.left + hitTestInsetPx && point.x <= rect.right - hitTestInsetPx && point.y >= rect.top + hitTestInsetPx && point.y <= rect.bottom - hitTestInsetPx) {
3013
+ return target.targetId;
3014
+ }
3015
+ }
3016
+ return null;
3017
+ },
3018
+ [hitTestInsetPx, isTargetUsable]
3019
+ );
3020
+ const sortedUsableTargetIds = useCallback5(() => {
3021
+ const entries = Array.from(targetsRef.current.values()).filter(
3022
+ (t) => isTargetUsable(t)
3023
+ );
3024
+ entries.sort((a, b) => a.order - b.order);
3025
+ return entries.map((t) => t.targetId);
3026
+ }, [isTargetUsable]);
3027
+ return {
3028
+ targetsRef,
3029
+ registerTarget,
3030
+ updateTarget,
3031
+ isTargetUsable,
3032
+ resolveDropTarget,
3033
+ sortedUsableTargetIds
3034
+ };
3035
+ }
3036
+
3037
+ // src/ui/components/card-drag/CardDragSurface.tsx
2968
3038
  import {
2969
- createContext as createContext3,
2970
- useCallback as useCallback5,
2971
- useContext as useContext3,
3039
+ useCallback as useCallback6,
2972
3040
  useEffect as useEffect6,
2973
3041
  useId as useId2,
2974
3042
  useMemo as useMemo5,
2975
- useRef as useRef2,
3043
+ useRef as useRef3,
2976
3044
  useState as useState8
2977
3045
  } from "react";
2978
3046
  import { createPortal } from "react-dom";
2979
3047
  import { clsx as clsx7 } from "clsx";
2980
- import { AnimatePresence, motion } from "framer-motion";
2981
- import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
2982
- var CardDragSurfaceContext = createContext3(null);
2983
- function useCardDragSurface() {
2984
- return useContext3(CardDragSurfaceContext);
3048
+ import { AnimatePresence } from "framer-motion";
3049
+
3050
+ // src/ui/components/card-drag/overlays.tsx
3051
+ import { motion } from "framer-motion";
3052
+ import { jsx as jsx10 } from "react/jsx-runtime";
3053
+ var REDUCED_TRANSITION = { duration: 0 };
3054
+ function DragOverlay({ session, reducedMotion }) {
3055
+ if (session.source === "keyboard") {
3056
+ return /* @__PURE__ */ jsx10(
3057
+ motion.div,
3058
+ {
3059
+ "data-dreamboard-card-drag-overlay": "",
3060
+ "data-source": "keyboard",
3061
+ initial: { opacity: 0 },
3062
+ animate: { opacity: 1 },
3063
+ exit: { opacity: 0 },
3064
+ transition: reducedMotion ? REDUCED_TRANSITION : { duration: 0.12 },
3065
+ style: {
3066
+ position: "fixed",
3067
+ left: session.sourceRect.left,
3068
+ top: session.sourceRect.top,
3069
+ width: session.sourceRect.width,
3070
+ height: session.sourceRect.height,
3071
+ pointerEvents: "none",
3072
+ zIndex: 1e3,
3073
+ boxShadow: reducedMotion ? "none" : "0 12px 32px rgba(0,0,0,0.18)",
3074
+ borderRadius: 12
3075
+ },
3076
+ children: session.content
3077
+ },
3078
+ "overlay-keyboard"
3079
+ );
3080
+ }
3081
+ const liftedAnimate = reducedMotion ? {
3082
+ scale: 1,
3083
+ rotate: 0,
3084
+ filter: "drop-shadow(0 0 0 rgba(0,0,0,0))"
3085
+ } : {
3086
+ scale: [1, 1.42, 1.35],
3087
+ rotate: [0, -3, 3, -1.8, 1.8, 0],
3088
+ filter: [
3089
+ "drop-shadow(0 4px 8px rgba(0,0,0,0.18))",
3090
+ "drop-shadow(0 24px 36px rgba(0,0,0,0.36))"
3091
+ ]
3092
+ };
3093
+ const liftedTransition = reducedMotion ? REDUCED_TRANSITION : {
3094
+ scale: { type: "spring", stiffness: 420, damping: 22, mass: 0.7 },
3095
+ rotate: { duration: 0.55, ease: "easeInOut" },
3096
+ filter: { duration: 0.18, ease: "easeOut" }
3097
+ };
3098
+ return /* @__PURE__ */ jsx10(
3099
+ motion.div,
3100
+ {
3101
+ "data-dreamboard-card-drag-overlay": "",
3102
+ "data-source": "pointer",
3103
+ initial: {
3104
+ scale: 1,
3105
+ rotate: 0,
3106
+ opacity: 1,
3107
+ filter: "drop-shadow(0 2px 6px rgba(0,0,0,0.15))"
3108
+ },
3109
+ animate: liftedAnimate,
3110
+ exit: { opacity: 0 },
3111
+ transition: liftedTransition,
3112
+ style: {
3113
+ position: "fixed",
3114
+ left: session.pointerX - session.sourceRect.width / 2,
3115
+ top: session.pointerY - session.sourceRect.height / 2,
3116
+ width: session.sourceRect.width,
3117
+ height: session.sourceRect.height,
3118
+ zIndex: 1e3,
3119
+ pointerEvents: "none",
3120
+ touchAction: "none",
3121
+ transformOrigin: "center center",
3122
+ willChange: "transform, filter"
3123
+ },
3124
+ children: session.content
3125
+ },
3126
+ "overlay-pointer"
3127
+ );
3128
+ }
3129
+ function SettleOverlay({
3130
+ session,
3131
+ transition,
3132
+ onDone
3133
+ }) {
3134
+ const startLeft = session.pointerX - session.sourceRect.width / 2;
3135
+ const startTop = session.pointerY - session.sourceRect.height / 2;
3136
+ const endLeft = session.targetRect.left + session.targetRect.width / 2 - session.sourceRect.width / 2;
3137
+ const endTop = session.targetRect.top + session.targetRect.height / 2 - session.sourceRect.height / 2;
3138
+ return /* @__PURE__ */ jsx10(
3139
+ motion.div,
3140
+ {
3141
+ "data-dreamboard-card-drag-overlay": "",
3142
+ "data-source": session.source,
3143
+ "data-drag-phase": "settling",
3144
+ initial: { left: startLeft, top: startTop, scale: 1.06, opacity: 1 },
3145
+ animate: { left: endLeft, top: endTop, scale: 0.92, opacity: 0 },
3146
+ transition,
3147
+ onAnimationComplete: onDone,
3148
+ style: {
3149
+ position: "fixed",
3150
+ width: session.sourceRect.width,
3151
+ height: session.sourceRect.height,
3152
+ zIndex: 1e3,
3153
+ pointerEvents: "none"
3154
+ },
3155
+ children: session.content
3156
+ }
3157
+ );
3158
+ }
3159
+ function ReturnOverlay({
3160
+ session,
3161
+ transition,
3162
+ onDone
3163
+ }) {
3164
+ const startLeft = session.pointerX - session.sourceRect.width / 2;
3165
+ const startTop = session.pointerY - session.sourceRect.height / 2;
3166
+ return /* @__PURE__ */ jsx10(
3167
+ motion.div,
3168
+ {
3169
+ "data-dreamboard-card-drag-overlay": "",
3170
+ "data-source": session.source,
3171
+ "data-drag-phase": "returning",
3172
+ initial: { left: startLeft, top: startTop, scale: 1.06, opacity: 1 },
3173
+ animate: {
3174
+ left: session.sourceRect.left,
3175
+ top: session.sourceRect.top,
3176
+ scale: 1,
3177
+ opacity: 1
3178
+ },
3179
+ exit: { opacity: 0 },
3180
+ transition,
3181
+ onAnimationComplete: onDone,
3182
+ style: {
3183
+ position: "fixed",
3184
+ width: session.sourceRect.width,
3185
+ height: session.sourceRect.height,
3186
+ zIndex: 1e3,
3187
+ pointerEvents: "none"
3188
+ },
3189
+ children: session.content
3190
+ }
3191
+ );
2985
3192
  }
3193
+
3194
+ // src/ui/components/card-drag/CardDragSurface.tsx
3195
+ import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
2986
3196
  var SETTLE_TRANSITION = {
2987
3197
  type: "spring",
2988
3198
  stiffness: 380,
@@ -2995,7 +3205,6 @@ var RETURN_TRANSITION = {
2995
3205
  damping: 26,
2996
3206
  mass: 0.8
2997
3207
  };
2998
- var REDUCED_TRANSITION = { duration: 0 };
2999
3208
  function CardDragSurface({
3000
3209
  onCardIntent,
3001
3210
  hitTestInsetPx = 8,
@@ -3008,10 +3217,8 @@ function CardDragSurface({
3008
3217
  const theme = useTheme();
3009
3218
  const reducedMotion = theme.motion.reducedMotion === "true";
3010
3219
  const liveRegionId = useId2();
3011
- const targetsRef = useRef2(/* @__PURE__ */ new Map());
3012
- const orderCounterRef = useRef2(0);
3013
- const activeDragRef = useRef2(null);
3014
- const inspectingRef = useRef2(null);
3220
+ const activeDragRef = useRef3(null);
3221
+ const inspectingRef = useRef3(null);
3015
3222
  const [activeDrag, setActiveDrag] = useState8(null);
3016
3223
  const [inspectingCardId, setInspectingCardId] = useState8(null);
3017
3224
  const [settlingState, setSettlingState] = useState8(
@@ -3020,19 +3227,27 @@ function CardDragSurface({
3020
3227
  const [returningState, setReturningState] = useState8(
3021
3228
  null
3022
3229
  );
3023
- const onIntentRef = useRef2(onCardIntent);
3230
+ const onIntentRef = useRef3(onCardIntent);
3024
3231
  onIntentRef.current = onCardIntent;
3025
3232
  const settleTransition = motionTransition ?? SETTLE_TRANSITION;
3026
3233
  const returnTransition = motionTransition ?? RETURN_TRANSITION;
3027
- const setActive = useCallback5((next) => {
3234
+ const setActive = useCallback6((next) => {
3028
3235
  activeDragRef.current = next;
3029
3236
  setActiveDrag(next);
3030
3237
  }, []);
3031
- const setInspecting = useCallback5((next) => {
3238
+ const setInspecting = useCallback6((next) => {
3032
3239
  inspectingRef.current = next;
3033
3240
  setInspectingCardId(next);
3034
3241
  }, []);
3035
- const finalizeInteraction = useCallback5((sourceFocus) => {
3242
+ const {
3243
+ targetsRef,
3244
+ registerTarget,
3245
+ updateTarget,
3246
+ isTargetUsable,
3247
+ resolveDropTarget,
3248
+ sortedUsableTargetIds
3249
+ } = useDropTargetRegistry({ hitTestInsetPx, activeDragRef, setActive });
3250
+ const finalizeInteraction = useCallback6((sourceFocus) => {
3036
3251
  if (sourceFocus) {
3037
3252
  queueMicrotask(() => {
3038
3253
  try {
@@ -3042,76 +3257,29 @@ function CardDragSurface({
3042
3257
  });
3043
3258
  }
3044
3259
  }, []);
3045
- const registerTarget = useCallback5(
3046
- (target) => {
3047
- targetsRef.current.set(target.targetId, {
3048
- ...target,
3049
- order: target.order || ++orderCounterRef.current
3050
- });
3051
- return () => {
3052
- targetsRef.current.delete(target.targetId);
3053
- const active = activeDragRef.current;
3054
- if (active && active.keyboardFocusedTargetId === target.targetId) {
3055
- setActive({ ...active, keyboardFocusedTargetId: null });
3056
- }
3057
- };
3058
- },
3059
- [setActive]
3060
- );
3061
- const updateTarget = useCallback5(
3062
- (targetId, patch) => {
3063
- const existing = targetsRef.current.get(targetId);
3064
- if (!existing) return;
3065
- targetsRef.current.set(targetId, { ...existing, ...patch });
3066
- },
3067
- []
3068
- );
3069
- const isTargetUsable = useCallback5((target) => {
3070
- return !target.disabled && target.eligible !== false;
3071
- }, []);
3072
- const resolveDropTarget = useCallback5(
3073
- (point) => {
3074
- for (const target of targetsRef.current.values()) {
3075
- if (!isTargetUsable(target)) continue;
3076
- const rect = target.element.getBoundingClientRect();
3077
- if (point.x >= rect.left + hitTestInsetPx && point.x <= rect.right - hitTestInsetPx && point.y >= rect.top + hitTestInsetPx && point.y <= rect.bottom - hitTestInsetPx) {
3078
- return target.targetId;
3079
- }
3080
- }
3081
- return null;
3082
- },
3083
- [hitTestInsetPx, isTargetUsable]
3084
- );
3085
- const sortedUsableTargetIds = useCallback5(() => {
3086
- const entries = Array.from(targetsRef.current.values()).filter(
3087
- (t) => isTargetUsable(t)
3088
- );
3089
- entries.sort((a, b) => a.order - b.order);
3090
- return entries.map((t) => t.targetId);
3091
- }, [isTargetUsable]);
3092
- const recordTap = useCallback5(
3260
+ const recordTap = useCallback6(
3093
3261
  (input) => {
3094
3262
  if (input.cardDisabled || !input.cardEligible) return;
3095
3263
  setInspecting(input.cardId);
3096
3264
  },
3097
3265
  [setInspecting]
3098
3266
  );
3099
- const recordPreviewStart = useCallback5((cardId) => {
3267
+ const recordPreviewStart = useCallback6((cardId) => {
3100
3268
  onIntentRef.current?.({ type: "previewStart", cardId });
3101
3269
  }, []);
3102
- const recordPreviewEnd = useCallback5((cardId) => {
3270
+ const recordPreviewEnd = useCallback6((cardId) => {
3103
3271
  onIntentRef.current?.({ type: "previewEnd", cardId });
3104
3272
  }, []);
3105
- const recordActivate = useCallback5(
3273
+ const recordActivate = useCallback6(
3106
3274
  (cardId, source) => {
3107
3275
  onIntentRef.current?.({ type: "activate", cardId, source });
3108
3276
  },
3109
3277
  []
3110
3278
  );
3111
- const clearInspect = useCallback5(() => {
3279
+ const clearInspect = useCallback6(() => {
3112
3280
  if (inspectingRef.current !== null) setInspecting(null);
3113
3281
  }, [setInspecting]);
3114
- const startPointerDrag = useCallback5(
3282
+ const startPointerDrag = useCallback6(
3115
3283
  (input) => {
3116
3284
  if (activeDragRef.current) return false;
3117
3285
  if (inspectingRef.current) setInspecting(null);
@@ -3139,7 +3307,7 @@ function CardDragSurface({
3139
3307
  },
3140
3308
  [resolveDropTarget, setActive, setInspecting]
3141
3309
  );
3142
- const updatePointer = useCallback5(
3310
+ const updatePointer = useCallback6(
3143
3311
  (point) => {
3144
3312
  const active = activeDragRef.current;
3145
3313
  if (!active || active.source !== "pointer") return;
@@ -3153,7 +3321,7 @@ function CardDragSurface({
3153
3321
  },
3154
3322
  [resolveDropTarget, setActive]
3155
3323
  );
3156
- const completeWithDrop = useCallback5(
3324
+ const completeWithDrop = useCallback6(
3157
3325
  (active, targetId, releaseX, releaseY) => {
3158
3326
  const target = targetsRef.current.get(targetId);
3159
3327
  const targetRect = target?.element.getBoundingClientRect();
@@ -3184,9 +3352,9 @@ function CardDragSurface({
3184
3352
  setActive(null);
3185
3353
  finalizeInteraction(active.sourceFocus);
3186
3354
  },
3187
- [finalizeInteraction, setActive]
3355
+ [finalizeInteraction, setActive, targetsRef]
3188
3356
  );
3189
- const completeWithReturn = useCallback5(
3357
+ const completeWithReturn = useCallback6(
3190
3358
  (active, releaseX, releaseY) => {
3191
3359
  const returning = {
3192
3360
  cardId: active.cardId,
@@ -3205,7 +3373,7 @@ function CardDragSurface({
3205
3373
  },
3206
3374
  [finalizeInteraction, setActive]
3207
3375
  );
3208
- const releasePointer = useCallback5(
3376
+ const releasePointer = useCallback6(
3209
3377
  (point) => {
3210
3378
  const active = activeDragRef.current;
3211
3379
  if (!active || active.source !== "pointer") return;
@@ -3218,12 +3386,12 @@ function CardDragSurface({
3218
3386
  },
3219
3387
  [completeWithDrop, completeWithReturn, resolveDropTarget]
3220
3388
  );
3221
- const cancelDrag = useCallback5(() => {
3389
+ const cancelDrag = useCallback6(() => {
3222
3390
  const active = activeDragRef.current;
3223
3391
  if (!active) return;
3224
3392
  completeWithReturn(active, active.pointerX, active.pointerY);
3225
3393
  }, [completeWithReturn]);
3226
- const startKeyboardDrag = useCallback5(
3394
+ const startKeyboardDrag = useCallback6(
3227
3395
  (input) => {
3228
3396
  if (activeDragRef.current) return false;
3229
3397
  if (!input.cardEligible) return false;
@@ -3251,9 +3419,9 @@ function CardDragSurface({
3251
3419
  setActive(next);
3252
3420
  return true;
3253
3421
  },
3254
- [setActive, setInspecting, sortedUsableTargetIds]
3422
+ [setActive, setInspecting, sortedUsableTargetIds, targetsRef]
3255
3423
  );
3256
- const moveKeyboardFocus = useCallback5(
3424
+ const moveKeyboardFocus = useCallback6(
3257
3425
  (direction) => {
3258
3426
  const active = activeDragRef.current;
3259
3427
  if (!active || active.source !== "keyboard") return;
@@ -3272,9 +3440,9 @@ function CardDragSurface({
3272
3440
  pointerY: rect ? rect.top + rect.height / 2 : active.pointerY
3273
3441
  });
3274
3442
  },
3275
- [setActive, sortedUsableTargetIds]
3443
+ [setActive, sortedUsableTargetIds, targetsRef]
3276
3444
  );
3277
- const commitKeyboardDrop = useCallback5(() => {
3445
+ const commitKeyboardDrop = useCallback6(() => {
3278
3446
  const active = activeDragRef.current;
3279
3447
  if (!active || active.source !== "keyboard") return;
3280
3448
  const targetId = active.keyboardFocusedTargetId;
@@ -3288,7 +3456,7 @@ function CardDragSurface({
3288
3456
  rect.left + rect.width / 2,
3289
3457
  rect.top + rect.height / 2
3290
3458
  );
3291
- }, [completeWithDrop, isTargetUsable]);
3459
+ }, [completeWithDrop, isTargetUsable, targetsRef]);
3292
3460
  const phase = useMemo5(() => {
3293
3461
  if (activeDrag) return "dragging";
3294
3462
  if (settlingState) return "settling";
@@ -3350,230 +3518,107 @@ function CardDragSurface({
3350
3518
  registerTarget,
3351
3519
  updateTarget,
3352
3520
  controller,
3353
- activeCardId: controller.activeCardId,
3354
- overTargetId: activeDrag?.overTargetId ?? null,
3355
- dragActive: activeDrag !== null,
3356
- keyboardFocusedTargetId: activeDrag?.keyboardFocusedTargetId ?? null
3357
- }),
3358
- [activeDrag, controller, registerTarget, updateTarget]
3359
- );
3360
- useEffect6(() => {
3361
- if (!activeDrag) return;
3362
- function onKeyDown(event) {
3363
- if (event.key === "Escape") {
3364
- event.preventDefault();
3365
- cancelDrag();
3366
- }
3367
- }
3368
- window.addEventListener("keydown", onKeyDown);
3369
- return () => window.removeEventListener("keydown", onKeyDown);
3370
- }, [activeDrag, cancelDrag]);
3371
- const announcement = useMemo5(() => {
3372
- if (!activeDrag) return null;
3373
- const overTarget = activeDrag.overTargetId ? targetsRef.current.get(activeDrag.overTargetId) : null;
3374
- const overLabel = overTarget?.label ?? null;
3375
- const cardLabel = activeDrag.cardLabel ?? "Card";
3376
- if (overLabel) {
3377
- return `${cardLabel} over ${overLabel}. Press Enter to drop or Escape to cancel.`;
3378
- }
3379
- return `${cardLabel} picked up. Move to a target or press Escape to cancel.`;
3380
- }, [activeDrag]);
3381
- const overlayContent = activeDrag ? /* @__PURE__ */ jsx10(DragOverlay, { session: activeDrag, reducedMotion }) : null;
3382
- const settleOverlay = settlingState ? /* @__PURE__ */ jsx10(
3383
- SettleOverlay,
3384
- {
3385
- session: settlingState,
3386
- transition: reducedMotion ? REDUCED_TRANSITION : settleTransition,
3387
- onDone: () => setSettlingState(null)
3388
- },
3389
- `settle-${settlingState.cardId}`
3390
- ) : null;
3391
- const returnOverlay = returningState ? /* @__PURE__ */ jsx10(
3392
- ReturnOverlay,
3393
- {
3394
- session: returningState,
3395
- transition: reducedMotion ? REDUCED_TRANSITION : returnTransition,
3396
- onDone: () => setReturningState(null)
3397
- },
3398
- `return-${returningState.cardId}`
3399
- ) : null;
3400
- const portalRoot = typeof document !== "undefined" ? document.body : null;
3401
- return /* @__PURE__ */ jsxs5(CardDragSurfaceContext.Provider, { value: contextValue, children: [
3402
- /* @__PURE__ */ jsx10(
3403
- "div",
3404
- {
3405
- "data-dreamboard-card-drag-surface": "",
3406
- "data-drag-active": activeDrag ? "true" : void 0,
3407
- "data-drag-source": activeDrag?.source,
3408
- "data-drag-phase": phase,
3409
- className: clsx7("relative", className),
3410
- style,
3411
- children
3412
- }
3413
- ),
3414
- portalRoot ? createPortal(
3415
- /* @__PURE__ */ jsxs5(AnimatePresence, { initial: false, children: [
3416
- overlayContent,
3417
- settleOverlay,
3418
- returnOverlay
3419
- ] }),
3420
- portalRoot
3421
- ) : null,
3422
- !suppressLiveAnnouncement ? /* @__PURE__ */ jsx10(
3423
- "div",
3424
- {
3425
- id: liveRegionId,
3426
- role: "status",
3427
- "aria-live": "polite",
3428
- className: "sr-only",
3429
- "data-dreamboard-card-drag-announcement": "",
3430
- style: {
3431
- position: "absolute",
3432
- width: 1,
3433
- height: 1,
3434
- padding: 0,
3435
- margin: -1,
3436
- overflow: "hidden",
3437
- clip: "rect(0,0,0,0)",
3438
- whiteSpace: "nowrap",
3439
- border: 0
3440
- },
3441
- children: announcement ?? ""
3442
- }
3443
- ) : null
3444
- ] });
3445
- }
3446
- function DragOverlay({ session, reducedMotion }) {
3447
- if (session.source === "keyboard") {
3448
- return /* @__PURE__ */ jsx10(
3449
- motion.div,
3450
- {
3451
- "data-dreamboard-card-drag-overlay": "",
3452
- "data-source": "keyboard",
3453
- initial: { opacity: 0 },
3454
- animate: { opacity: 1 },
3455
- exit: { opacity: 0 },
3456
- transition: reducedMotion ? REDUCED_TRANSITION : { duration: 0.12 },
3457
- style: {
3458
- position: "fixed",
3459
- left: session.sourceRect.left,
3460
- top: session.sourceRect.top,
3461
- width: session.sourceRect.width,
3462
- height: session.sourceRect.height,
3463
- pointerEvents: "none",
3464
- zIndex: 1e3,
3465
- boxShadow: reducedMotion ? "none" : "0 12px 32px rgba(0,0,0,0.18)",
3466
- borderRadius: 12
3467
- },
3468
- children: session.content
3469
- },
3470
- "overlay-keyboard"
3471
- );
3472
- }
3473
- const liftedAnimate = reducedMotion ? {
3474
- scale: 1,
3475
- rotate: 0,
3476
- filter: "drop-shadow(0 0 0 rgba(0,0,0,0))"
3477
- } : {
3478
- scale: [1, 1.42, 1.35],
3479
- rotate: [0, -3, 3, -1.8, 1.8, 0],
3480
- filter: [
3481
- "drop-shadow(0 4px 8px rgba(0,0,0,0.18))",
3482
- "drop-shadow(0 24px 36px rgba(0,0,0,0.36))"
3483
- ]
3484
- };
3485
- const liftedTransition = reducedMotion ? REDUCED_TRANSITION : {
3486
- scale: { type: "spring", stiffness: 420, damping: 22, mass: 0.7 },
3487
- rotate: { duration: 0.55, ease: "easeInOut" },
3488
- filter: { duration: 0.18, ease: "easeOut" }
3489
- };
3490
- return /* @__PURE__ */ jsx10(
3491
- motion.div,
3492
- {
3493
- "data-dreamboard-card-drag-overlay": "",
3494
- "data-source": "pointer",
3495
- initial: {
3496
- scale: 1,
3497
- rotate: 0,
3498
- opacity: 1,
3499
- filter: "drop-shadow(0 2px 6px rgba(0,0,0,0.15))"
3500
- },
3501
- animate: liftedAnimate,
3502
- exit: { opacity: 0 },
3503
- transition: liftedTransition,
3504
- style: {
3505
- position: "fixed",
3506
- left: session.pointerX - session.sourceRect.width / 2,
3507
- top: session.pointerY - session.sourceRect.height / 2,
3508
- width: session.sourceRect.width,
3509
- height: session.sourceRect.height,
3510
- zIndex: 1e3,
3511
- pointerEvents: "none",
3512
- touchAction: "none",
3513
- transformOrigin: "center center",
3514
- willChange: "transform, filter"
3515
- },
3516
- children: session.content
3517
- },
3518
- "overlay-pointer"
3519
- );
3520
- }
3521
- function SettleOverlay({ session, transition, onDone }) {
3522
- const startLeft = session.pointerX - session.sourceRect.width / 2;
3523
- const startTop = session.pointerY - session.sourceRect.height / 2;
3524
- const endLeft = session.targetRect.left + session.targetRect.width / 2 - session.sourceRect.width / 2;
3525
- const endTop = session.targetRect.top + session.targetRect.height / 2 - session.sourceRect.height / 2;
3526
- return /* @__PURE__ */ jsx10(
3527
- motion.div,
3528
- {
3529
- "data-dreamboard-card-drag-overlay": "",
3530
- "data-source": session.source,
3531
- "data-drag-phase": "settling",
3532
- initial: { left: startLeft, top: startTop, scale: 1.06, opacity: 1 },
3533
- animate: { left: endLeft, top: endTop, scale: 0.92, opacity: 0 },
3534
- transition,
3535
- onAnimationComplete: onDone,
3536
- style: {
3537
- position: "fixed",
3538
- width: session.sourceRect.width,
3539
- height: session.sourceRect.height,
3540
- zIndex: 1e3,
3541
- pointerEvents: "none"
3542
- },
3543
- children: session.content
3544
- }
3545
- );
3546
- }
3547
- function ReturnOverlay({ session, transition, onDone }) {
3548
- const startLeft = session.pointerX - session.sourceRect.width / 2;
3549
- const startTop = session.pointerY - session.sourceRect.height / 2;
3550
- return /* @__PURE__ */ jsx10(
3551
- motion.div,
3552
- {
3553
- "data-dreamboard-card-drag-overlay": "",
3554
- "data-source": session.source,
3555
- "data-drag-phase": "returning",
3556
- initial: { left: startLeft, top: startTop, scale: 1.06, opacity: 1 },
3557
- animate: {
3558
- left: session.sourceRect.left,
3559
- top: session.sourceRect.top,
3560
- scale: 1,
3561
- opacity: 1
3562
- },
3563
- exit: { opacity: 0 },
3564
- transition,
3565
- onAnimationComplete: onDone,
3566
- style: {
3567
- position: "fixed",
3568
- width: session.sourceRect.width,
3569
- height: session.sourceRect.height,
3570
- zIndex: 1e3,
3571
- pointerEvents: "none"
3572
- },
3573
- children: session.content
3574
- }
3521
+ activeCardId: controller.activeCardId,
3522
+ overTargetId: activeDrag?.overTargetId ?? null,
3523
+ dragActive: activeDrag !== null,
3524
+ keyboardFocusedTargetId: activeDrag?.keyboardFocusedTargetId ?? null
3525
+ }),
3526
+ [activeDrag, controller, registerTarget, updateTarget]
3575
3527
  );
3528
+ useEffect6(() => {
3529
+ if (!activeDrag) return;
3530
+ function onKeyDown(event) {
3531
+ if (event.key === "Escape") {
3532
+ event.preventDefault();
3533
+ cancelDrag();
3534
+ }
3535
+ }
3536
+ window.addEventListener("keydown", onKeyDown);
3537
+ return () => window.removeEventListener("keydown", onKeyDown);
3538
+ }, [activeDrag, cancelDrag]);
3539
+ const announcement = useMemo5(() => {
3540
+ if (!activeDrag) return null;
3541
+ const overTarget = activeDrag.overTargetId ? targetsRef.current.get(activeDrag.overTargetId) : null;
3542
+ const overLabel = overTarget?.label ?? null;
3543
+ const cardLabel = activeDrag.cardLabel ?? "Card";
3544
+ if (overLabel) {
3545
+ return `${cardLabel} over ${overLabel}. Press Enter to drop or Escape to cancel.`;
3546
+ }
3547
+ return `${cardLabel} picked up. Move to a target or press Escape to cancel.`;
3548
+ }, [activeDrag, targetsRef]);
3549
+ const overlayContent = activeDrag ? /* @__PURE__ */ jsx11(DragOverlay, { session: activeDrag, reducedMotion }) : null;
3550
+ const settleOverlay = settlingState ? /* @__PURE__ */ jsx11(
3551
+ SettleOverlay,
3552
+ {
3553
+ session: settlingState,
3554
+ transition: reducedMotion ? REDUCED_TRANSITION : settleTransition,
3555
+ onDone: () => setSettlingState(null)
3556
+ },
3557
+ `settle-${settlingState.cardId}`
3558
+ ) : null;
3559
+ const returnOverlay = returningState ? /* @__PURE__ */ jsx11(
3560
+ ReturnOverlay,
3561
+ {
3562
+ session: returningState,
3563
+ transition: reducedMotion ? REDUCED_TRANSITION : returnTransition,
3564
+ onDone: () => setReturningState(null)
3565
+ },
3566
+ `return-${returningState.cardId}`
3567
+ ) : null;
3568
+ const portalRoot = typeof document !== "undefined" ? document.body : null;
3569
+ return /* @__PURE__ */ jsxs5(CardDragSurfaceContext.Provider, { value: contextValue, children: [
3570
+ /* @__PURE__ */ jsx11(
3571
+ "div",
3572
+ {
3573
+ "data-dreamboard-card-drag-surface": "",
3574
+ "data-drag-active": activeDrag ? "true" : void 0,
3575
+ "data-drag-source": activeDrag?.source,
3576
+ "data-drag-phase": phase,
3577
+ className: clsx7("relative", className),
3578
+ style,
3579
+ children
3580
+ }
3581
+ ),
3582
+ portalRoot ? createPortal(
3583
+ /* @__PURE__ */ jsxs5(AnimatePresence, { initial: false, children: [
3584
+ overlayContent,
3585
+ settleOverlay,
3586
+ returnOverlay
3587
+ ] }),
3588
+ portalRoot
3589
+ ) : null,
3590
+ !suppressLiveAnnouncement ? /* @__PURE__ */ jsx11(
3591
+ "div",
3592
+ {
3593
+ id: liveRegionId,
3594
+ role: "status",
3595
+ "aria-live": "polite",
3596
+ className: "sr-only",
3597
+ "data-dreamboard-card-drag-announcement": "",
3598
+ style: {
3599
+ position: "absolute",
3600
+ width: 1,
3601
+ height: 1,
3602
+ padding: 0,
3603
+ margin: -1,
3604
+ overflow: "hidden",
3605
+ clip: "rect(0,0,0,0)",
3606
+ whiteSpace: "nowrap",
3607
+ border: 0
3608
+ },
3609
+ children: announcement ?? ""
3610
+ }
3611
+ ) : null
3612
+ ] });
3576
3613
  }
3614
+
3615
+ // src/ui/components/card-drag/CardDropTargetView.tsx
3616
+ import {
3617
+ useCallback as useCallback7,
3618
+ useEffect as useEffect7,
3619
+ useRef as useRef4
3620
+ } from "react";
3621
+ import { jsx as jsx12 } from "react/jsx-runtime";
3577
3622
  function CardDropTargetView({
3578
3623
  targetId,
3579
3624
  state,
@@ -3585,16 +3630,16 @@ function CardDropTargetView({
3585
3630
  role = "button"
3586
3631
  }) {
3587
3632
  const surface = useCardDragSurface();
3588
- const ref = useRef2(null);
3633
+ const ref = useRef4(null);
3589
3634
  const disabled = state?.disabled ?? false;
3590
3635
  const baseEligible = state?.eligible ?? true;
3591
3636
  const baseLabel = label ?? null;
3592
3637
  const orderProp = order ?? 0;
3593
- const registerTargetRef = useRef2(surface?.registerTarget);
3638
+ const registerTargetRef = useRef4(surface?.registerTarget);
3594
3639
  registerTargetRef.current = surface?.registerTarget;
3595
- const updateTargetRef = useRef2(surface?.updateTarget);
3640
+ const updateTargetRef = useRef4(surface?.updateTarget);
3596
3641
  updateTargetRef.current = surface?.updateTarget;
3597
- useEffect6(() => {
3642
+ useEffect7(() => {
3598
3643
  const element = ref.current;
3599
3644
  const register = registerTargetRef.current;
3600
3645
  if (!register || !element) return;
@@ -3608,7 +3653,7 @@ function CardDropTargetView({
3608
3653
  });
3609
3654
  return unregister;
3610
3655
  }, [targetId]);
3611
- useEffect6(() => {
3656
+ useEffect7(() => {
3612
3657
  updateTargetRef.current?.(targetId, {
3613
3658
  disabled,
3614
3659
  eligible: baseEligible,
@@ -3619,7 +3664,7 @@ function CardDropTargetView({
3619
3664
  const dragActive = surface?.dragActive ?? false;
3620
3665
  const overTargetId = surface?.overTargetId ?? null;
3621
3666
  const keyboardFocused = surface?.keyboardFocusedTargetId === targetId;
3622
- useEffect6(() => {
3667
+ useEffect7(() => {
3623
3668
  if (!keyboardFocused) return;
3624
3669
  const el = ref.current;
3625
3670
  if (!el) return;
@@ -3635,7 +3680,7 @@ function CardDropTargetView({
3635
3680
  active: dragActive ? true : state?.active,
3636
3681
  over: overTargetId === targetId && baseEligible ? true : state?.over ?? false
3637
3682
  };
3638
- const handleKeyDown = useCallback5(
3683
+ const handleKeyDown = useCallback7(
3639
3684
  (event) => {
3640
3685
  if (!surface) return;
3641
3686
  const controller = surface.controller;
@@ -3662,7 +3707,7 @@ function CardDropTargetView({
3662
3707
  },
3663
3708
  [surface]
3664
3709
  );
3665
- return /* @__PURE__ */ jsx10(
3710
+ return /* @__PURE__ */ jsx12(
3666
3711
  "div",
3667
3712
  {
3668
3713
  ref,
@@ -3684,14 +3729,14 @@ function CardDropTargetView({
3684
3729
 
3685
3730
  // src/ui/components/HandView.tsx
3686
3731
  import {
3687
- useCallback as useCallback7,
3732
+ useCallback as useCallback9,
3688
3733
  useId as useId3,
3689
3734
  useMemo as useMemo8
3690
3735
  } from "react";
3691
3736
  import { clsx as clsx8 } from "clsx";
3692
3737
 
3693
3738
  // src/ui/hooks/useHandPresentation.ts
3694
- import { useEffect as useEffect7, useMemo as useMemo6, useRef as useRef3, useState as useState9 } from "react";
3739
+ import { useEffect as useEffect8, useMemo as useMemo6, useRef as useRef5, useState as useState9 } from "react";
3695
3740
 
3696
3741
  // src/ui/components/hand-layout-math.ts
3697
3742
  function computeFanLayout(options) {
@@ -3777,9 +3822,9 @@ function useHandPresentation({
3777
3822
  mobile = "tray",
3778
3823
  containerPadding = DEFAULT_PADDING
3779
3824
  }) {
3780
- const containerRef = useRef3(null);
3825
+ const containerRef = useRef5(null);
3781
3826
  const [containerWidth, setContainerWidth] = useState9(0);
3782
- useEffect7(() => {
3827
+ useEffect8(() => {
3783
3828
  const node = containerRef.current;
3784
3829
  if (!node) return;
3785
3830
  let frame = 0;
@@ -3844,7 +3889,7 @@ function useHandPresentation({
3844
3889
  }
3845
3890
 
3846
3891
  // src/ui/hooks/useHandCardPointer.ts
3847
- import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo7, useRef as useRef4, useState as useState10 } from "react";
3892
+ import { useCallback as useCallback8, useEffect as useEffect9, useMemo as useMemo7, useRef as useRef6, useState as useState10 } from "react";
3848
3893
 
3849
3894
  // src/ui/components/hand-pointer-engine.ts
3850
3895
  var DEFAULT_POINTER_THRESHOLDS = {
@@ -4083,21 +4128,21 @@ function useHandCardPointer({
4083
4128
  renderLiftedCard,
4084
4129
  resolveCardLabel
4085
4130
  } = {}) {
4086
- const intentRef = useRef4(onIntent);
4131
+ const intentRef = useRef6(onIntent);
4087
4132
  intentRef.current = onIntent;
4088
- const policyRef = useRef4(policy);
4133
+ const policyRef = useRef6(policy);
4089
4134
  policyRef.current = policy;
4090
- const surfaceRef = useRef4(surface);
4135
+ const surfaceRef = useRef6(surface);
4091
4136
  surfaceRef.current = surface;
4092
- const renderLiftedCardRef = useRef4(renderLiftedCard);
4137
+ const renderLiftedCardRef = useRef6(renderLiftedCard);
4093
4138
  renderLiftedCardRef.current = renderLiftedCard;
4094
- const resolveCardLabelRef = useRef4(resolveCardLabel);
4139
+ const resolveCardLabelRef = useRef6(resolveCardLabel);
4095
4140
  resolveCardLabelRef.current = resolveCardLabel;
4096
- const cardElementsRef = useRef4(/* @__PURE__ */ new Map());
4097
- const cardRefsRef = useRef4(
4141
+ const cardElementsRef = useRef6(/* @__PURE__ */ new Map());
4142
+ const cardRefsRef = useRef6(
4098
4143
  /* @__PURE__ */ new Map()
4099
4144
  );
4100
- const getCardRef = useCallback6((cardId) => {
4145
+ const getCardRef = useCallback8((cardId) => {
4101
4146
  let stable = cardRefsRef.current.get(cardId);
4102
4147
  if (!stable) {
4103
4148
  stable = (element) => {
@@ -4116,7 +4161,7 @@ function useHandCardPointer({
4116
4161
  kind: "idle"
4117
4162
  });
4118
4163
  const [scrollLocked, setScrollLocked] = useState10(false);
4119
- const captureSourceRect = useCallback6((cardId) => {
4164
+ const captureSourceRect = useCallback8((cardId) => {
4120
4165
  const el = cardElementsRef.current.get(cardId);
4121
4166
  if (!el) return { left: 0, top: 0, width: 0, height: 0 };
4122
4167
  const rect = el.getBoundingClientRect();
@@ -4217,8 +4262,8 @@ function useHandCardPointer({
4217
4262
  ),
4218
4263
  [captureSourceRect, thresholds]
4219
4264
  );
4220
- useEffect8(() => () => engine.dispose(), [engine]);
4221
- const bindCard = useCallback6(
4265
+ useEffect9(() => () => engine.dispose(), [engine]);
4266
+ const bindCard = useCallback8(
4222
4267
  (card) => {
4223
4268
  const isActive = activeCardId === card.cardId;
4224
4269
  const pointerStateKind = isActive ? recognitionState.kind : "idle";
@@ -4329,7 +4374,7 @@ function useHandCardPointer({
4329
4374
  scrollLocked
4330
4375
  ]
4331
4376
  );
4332
- const activateKeyboard = useCallback6((card) => {
4377
+ const activateKeyboard = useCallback8((card) => {
4333
4378
  if (card.disabled || !card.eligible) return;
4334
4379
  if (policyRef.current === "drag-to-target") return;
4335
4380
  if (surfaceRef.current) {
@@ -4352,7 +4397,7 @@ function useHandCardPointer({
4352
4397
  }
4353
4398
 
4354
4399
  // src/ui/components/HandView.tsx
4355
- import { jsx as jsx11 } from "react/jsx-runtime";
4400
+ import { jsx as jsx13 } from "react/jsx-runtime";
4356
4401
  var CARD_DIMENSIONS2 = {
4357
4402
  sm: { width: 80, height: 112 },
4358
4403
  md: { width: 96, height: 144 },
@@ -4404,7 +4449,7 @@ function HandView({
4404
4449
  });
4405
4450
  const surface = useCardDragSurface();
4406
4451
  const surfaceController = surface?.controller ?? null;
4407
- const emit = useCallback7(
4452
+ const emit = useCallback9(
4408
4453
  (intent) => {
4409
4454
  onCardIntent?.(intent);
4410
4455
  },
@@ -4417,7 +4462,7 @@ function HandView({
4417
4462
  }),
4418
4463
  [cards, stateForCard]
4419
4464
  );
4420
- const renderLiftedCard = useCallback7(
4465
+ const renderLiftedCard = useCallback9(
4421
4466
  (cardId) => {
4422
4467
  const found = items.find((item) => item.card.id === cardId);
4423
4468
  if (!found) return null;
@@ -4425,7 +4470,7 @@ function HandView({
4425
4470
  },
4426
4471
  [items, renderCard]
4427
4472
  );
4428
- const resolveCardLabel = useCallback7(
4473
+ const resolveCardLabel = useCallback9(
4429
4474
  (cardId) => {
4430
4475
  const found = items.find((item) => item.card.id === cardId);
4431
4476
  if (!found) return null;
@@ -4442,7 +4487,7 @@ function HandView({
4442
4487
  resolveCardLabel
4443
4488
  });
4444
4489
  if (cards.length === 0) {
4445
- return /* @__PURE__ */ jsx11(
4490
+ return /* @__PURE__ */ jsx13(
4446
4491
  "div",
4447
4492
  {
4448
4493
  ref: presentation.containerRef,
@@ -4502,7 +4547,7 @@ function HandView({
4502
4547
  const transform = transformParts.length ? transformParts.join(" ") : void 0;
4503
4548
  const liftVisualOpacity = isLifted ? 0.25 : 1;
4504
4549
  const inspectShadow = isInspecting && !reducedMotion ? "0 14px 28px rgba(0,0,0,0.18)" : void 0;
4505
- return /* @__PURE__ */ jsx11(
4550
+ return /* @__PURE__ */ jsx13(
4506
4551
  "div",
4507
4552
  {
4508
4553
  role: "gridcell",
@@ -4539,7 +4584,7 @@ function HandView({
4539
4584
  };
4540
4585
  if (presentation.mode === "fan" || presentation.mode === "compressed-fan") {
4541
4586
  const totalHeight = dims.height + 24;
4542
- return /* @__PURE__ */ jsx11(
4587
+ return /* @__PURE__ */ jsx13(
4543
4588
  "div",
4544
4589
  {
4545
4590
  ref: presentation.containerRef,
@@ -4560,7 +4605,7 @@ function HandView({
4560
4605
  touchAction: "pan-x",
4561
4606
  ...style
4562
4607
  },
4563
- children: /* @__PURE__ */ jsx11(
4608
+ children: /* @__PURE__ */ jsx13(
4564
4609
  "div",
4565
4610
  {
4566
4611
  role: "row",
@@ -4580,7 +4625,7 @@ function HandView({
4580
4625
  );
4581
4626
  }
4582
4627
  if (presentation.mode === "tray") {
4583
- return /* @__PURE__ */ jsx11(
4628
+ return /* @__PURE__ */ jsx13(
4584
4629
  "div",
4585
4630
  {
4586
4631
  ref: presentation.containerRef,
@@ -4595,7 +4640,7 @@ function HandView({
4595
4640
  "aria-colcount": cards.length,
4596
4641
  className: clsx8("relative w-full min-w-0", className),
4597
4642
  style,
4598
- children: /* @__PURE__ */ jsx11(
4643
+ children: /* @__PURE__ */ jsx13(
4599
4644
  "div",
4600
4645
  {
4601
4646
  role: "row",
@@ -4609,7 +4654,7 @@ function HandView({
4609
4654
  paddingBottom: "max(1rem, env(safe-area-inset-bottom, 0px))",
4610
4655
  scrollBehavior: reducedMotion ? "auto" : "smooth"
4611
4656
  },
4612
- children: items.map((item) => /* @__PURE__ */ jsx11(
4657
+ children: items.map((item) => /* @__PURE__ */ jsx13(
4613
4658
  "div",
4614
4659
  {
4615
4660
  className: "snap-start shrink-0",
@@ -4623,7 +4668,7 @@ function HandView({
4623
4668
  }
4624
4669
  );
4625
4670
  }
4626
- return /* @__PURE__ */ jsx11(
4671
+ return /* @__PURE__ */ jsx13(
4627
4672
  "div",
4628
4673
  {
4629
4674
  ref: presentation.containerRef,
@@ -4641,7 +4686,7 @@ function HandView({
4641
4686
  className
4642
4687
  ),
4643
4688
  style: { touchAction: "pan-x", ...style },
4644
- children: /* @__PURE__ */ jsx11("div", { role: "row", className: "flex flex-wrap justify-center gap-1", children: items.map((item) => renderItem(item)) })
4689
+ children: /* @__PURE__ */ jsx13("div", { role: "row", className: "flex flex-wrap justify-center gap-1", children: items.map((item) => renderItem(item)) })
4645
4690
  }
4646
4691
  );
4647
4692
  }
@@ -4649,16 +4694,16 @@ function HandView({
4649
4694
  // src/ui/components/MobileHandTray.tsx
4650
4695
  import {
4651
4696
  createContext as createContext4,
4652
- useCallback as useCallback8,
4697
+ useCallback as useCallback10,
4653
4698
  useContext as useContext4,
4654
- useEffect as useEffect9,
4699
+ useEffect as useEffect10,
4655
4700
  useMemo as useMemo9,
4656
- useRef as useRef5,
4701
+ useRef as useRef7,
4657
4702
  useState as useState11
4658
4703
  } from "react";
4659
4704
  import { useDrag as useDrag2 } from "@use-gesture/react";
4660
4705
  import { clsx as clsx9 } from "clsx";
4661
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
4706
+ import { jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
4662
4707
  var MobileHandTrayContext = createContext4(
4663
4708
  null
4664
4709
  );
@@ -4680,7 +4725,7 @@ var DOCK_SNAP_MAX_HEIGHT = {
4680
4725
  function MobileHandTrayProvider({ children }) {
4681
4726
  const [handsById, setHandsById] = useState11(() => /* @__PURE__ */ new Map());
4682
4727
  const isMobile = useIsMobile();
4683
- const registerHand = useCallback8((hand) => {
4728
+ const registerHand = useCallback10((hand) => {
4684
4729
  setHandsById((current) => {
4685
4730
  const previous = current.get(hand.id);
4686
4731
  if (previous && previous.zone === hand.zone && previous.label === hand.label && previous.role === hand.role && previous.order === hand.order && previous.version === hand.version && previous.count === hand.count && previous.active === hand.active && previous.autoOpen === hand.autoOpen) {
@@ -4711,8 +4756,8 @@ function MobileHandTrayProvider({ children }) {
4711
4756
  );
4712
4757
  const trayActive = isMobile && hands.length > 0;
4713
4758
  const stateValue = useMemo9(() => ({ active: trayActive }), [trayActive]);
4714
- return /* @__PURE__ */ jsx12(MobileHandTrayContext.Provider, { value, children: /* @__PURE__ */ jsxs6(MobileHandTrayStateContext.Provider, { value: stateValue, children: [
4715
- /* @__PURE__ */ jsx12(
4759
+ return /* @__PURE__ */ jsx14(MobileHandTrayContext.Provider, { value, children: /* @__PURE__ */ jsxs6(MobileHandTrayStateContext.Provider, { value: stateValue, children: [
4760
+ /* @__PURE__ */ jsx14(
4716
4761
  "div",
4717
4762
  {
4718
4763
  "data-dreamboard-mobile-hand-shell": "",
@@ -4725,7 +4770,7 @@ function MobileHandTrayProvider({ children }) {
4725
4770
  children
4726
4771
  }
4727
4772
  ),
4728
- trayActive ? /* @__PURE__ */ jsx12(MobileHandTray, { hands }) : null
4773
+ trayActive ? /* @__PURE__ */ jsx14(MobileHandTray, { hands }) : null
4729
4774
  ] }) });
4730
4775
  }
4731
4776
  function useRegisterMobileHand(hand) {
@@ -4735,7 +4780,7 @@ function useRegisterMobileHand(hand) {
4735
4780
  "Generated hand surfaces must be rendered inside <UI.Root>; mobile hand tray registration is unavailable."
4736
4781
  );
4737
4782
  }
4738
- useEffect9(() => context.registerHand(hand), [context, hand]);
4783
+ useEffect10(() => context.registerHand(hand), [context, hand]);
4739
4784
  }
4740
4785
  function useMobileHandTrayActive() {
4741
4786
  return useContext4(MobileHandTrayStateContext).active;
@@ -4745,7 +4790,7 @@ function MobileHandTray({
4745
4790
  }) {
4746
4791
  const [snap, setSnap] = useState11("peek");
4747
4792
  const open = snap !== "peek";
4748
- const advanceSnap = useCallback8((direction) => {
4793
+ const advanceSnap = useCallback10((direction) => {
4749
4794
  setSnap((current) => {
4750
4795
  const index = DOCK_SNAPS.indexOf(current);
4751
4796
  const next = Math.min(
@@ -4759,7 +4804,7 @@ function MobileHandTray({
4759
4804
  const themeCssVars = useThemeCssVars();
4760
4805
  const preferredHand = hands.find((hand) => hand.id === activeId) ?? hands.find((hand) => hand.active) ?? hands.find((hand) => hand.role === "primary") ?? hands[0] ?? null;
4761
4806
  const selectedHand = hands.find((hand) => hand.id === activeId) ?? preferredHand;
4762
- useEffect9(() => {
4807
+ useEffect10(() => {
4763
4808
  if (!preferredHand) {
4764
4809
  setActiveId(null);
4765
4810
  return;
@@ -4769,8 +4814,8 @@ function MobileHandTray({
4769
4814
  );
4770
4815
  }, [hands, preferredHand]);
4771
4816
  const active = selectedHand?.active ?? false;
4772
- const prevActiveRef = useRef5(false);
4773
- useEffect9(() => {
4817
+ const prevActiveRef = useRef7(false);
4818
+ useEffect10(() => {
4774
4819
  if (active !== prevActiveRef.current) {
4775
4820
  prevActiveRef.current = active;
4776
4821
  setSnap(active ? "raised" : "peek");
@@ -4788,7 +4833,7 @@ function MobileHandTray({
4788
4833
  const activeBadges = hands.filter(
4789
4834
  (hand) => hand.id !== selectedHand.id && hand.active
4790
4835
  );
4791
- return /* @__PURE__ */ jsx12(
4836
+ return /* @__PURE__ */ jsx14(
4792
4837
  "div",
4793
4838
  {
4794
4839
  "data-dreamboard-mobile-hand-tray": "",
@@ -4841,7 +4886,7 @@ function MobileHandTray({
4841
4886
  cursor: "pointer"
4842
4887
  },
4843
4888
  children: [
4844
- /* @__PURE__ */ jsx12(
4889
+ /* @__PURE__ */ jsx14(
4845
4890
  "span",
4846
4891
  {
4847
4892
  "aria-hidden": true,
@@ -4851,8 +4896,8 @@ function MobileHandTray({
4851
4896
  ),
4852
4897
  /* @__PURE__ */ jsxs6("span", { className: "flex items-center justify-between gap-2", children: [
4853
4898
  /* @__PURE__ */ jsxs6("span", { className: "flex min-w-0 items-center gap-2 text-sm font-semibold", children: [
4854
- /* @__PURE__ */ jsx12("span", { className: "truncate", children: selectedHand.label }),
4855
- /* @__PURE__ */ jsx12(
4899
+ /* @__PURE__ */ jsx14("span", { className: "truncate", children: selectedHand.label }),
4900
+ /* @__PURE__ */ jsx14(
4856
4901
  "span",
4857
4902
  {
4858
4903
  className: "rounded-full px-2 py-0.5 text-xs font-bold",
@@ -4860,9 +4905,9 @@ function MobileHandTray({
4860
4905
  children: selectedHand.count
4861
4906
  }
4862
4907
  ),
4863
- active ? /* @__PURE__ */ jsx12("span", { className: "rounded-full bg-amber-400 px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-amber-950", children: "your turn" }) : null
4908
+ active ? /* @__PURE__ */ jsx14("span", { className: "rounded-full bg-amber-400 px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-amber-950", children: "your turn" }) : null
4864
4909
  ] }),
4865
- activeBadges.length > 0 ? /* @__PURE__ */ jsx12(
4910
+ activeBadges.length > 0 ? /* @__PURE__ */ jsx14(
4866
4911
  "span",
4867
4912
  {
4868
4913
  "aria-label": `${activeBadges.length} other active hand sections`,
@@ -4889,7 +4934,7 @@ function MobileHandTray({
4889
4934
  transition: "max-height 240ms ease"
4890
4935
  },
4891
4936
  children: [
4892
- hands.length > 1 ? /* @__PURE__ */ jsx12(
4937
+ hands.length > 1 ? /* @__PURE__ */ jsx14(
4893
4938
  "div",
4894
4939
  {
4895
4940
  role: "tablist",
@@ -4920,7 +4965,7 @@ function MobileHandTray({
4920
4965
  ))
4921
4966
  }
4922
4967
  ) : null,
4923
- /* @__PURE__ */ jsx12(
4968
+ /* @__PURE__ */ jsx14(
4924
4969
  "div",
4925
4970
  {
4926
4971
  className: "px-3 pt-2 sm:px-4",
@@ -4943,7 +4988,7 @@ function MobileHandTray({
4943
4988
  // src/ui/components/PlayArea.tsx
4944
4989
  import { motion as motion2, AnimatePresence as AnimatePresence2 } from "framer-motion";
4945
4990
  import { clsx as clsx10 } from "clsx";
4946
- import { jsx as jsx13 } from "react/jsx-runtime";
4991
+ import { jsx as jsx15 } from "react/jsx-runtime";
4947
4992
  function PlayArea({
4948
4993
  cards,
4949
4994
  filter,
@@ -4962,7 +5007,7 @@ function PlayArea({
4962
5007
  grid: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3 sm:gap-6",
4963
5008
  row: "flex flex-wrap items-center justify-center gap-3 sm:gap-6"
4964
5009
  };
4965
- return /* @__PURE__ */ jsx13(
5010
+ return /* @__PURE__ */ jsx15(
4966
5011
  "div",
4967
5012
  {
4968
5013
  className: clsx10(
@@ -4978,7 +5023,7 @@ function PlayArea({
4978
5023
  },
4979
5024
  role: "region",
4980
5025
  "aria-label": `${ariaLabel} - ${visibleCards.length} item${visibleCards.length !== 1 ? "s" : ""}`,
4981
- children: /* @__PURE__ */ jsx13(AnimatePresence2, { mode: "popLayout", children: visibleCards.length === 0 ? /* @__PURE__ */ jsx13(
5026
+ children: /* @__PURE__ */ jsx15(AnimatePresence2, { mode: "popLayout", children: visibleCards.length === 0 ? /* @__PURE__ */ jsx15(
4982
5027
  motion2.div,
4983
5028
  {
4984
5029
  className: "flex items-center justify-center h-full absolute inset-0 pointer-events-none",
@@ -4987,7 +5032,7 @@ function PlayArea({
4987
5032
  exit: { opacity: 0 },
4988
5033
  role: "status",
4989
5034
  "aria-live": "polite",
4990
- children: /* @__PURE__ */ jsx13(
5035
+ children: /* @__PURE__ */ jsx15(
4991
5036
  "div",
4992
5037
  {
4993
5038
  style: {
@@ -5000,7 +5045,7 @@ function PlayArea({
5000
5045
  }
5001
5046
  )
5002
5047
  }
5003
- ) : /* @__PURE__ */ jsx13("div", { className: layoutClasses[layout], children: visibleCards.map((card, index) => /* @__PURE__ */ jsx13(
5048
+ ) : /* @__PURE__ */ jsx15("div", { className: layoutClasses[layout], children: visibleCards.map((card, index) => /* @__PURE__ */ jsx15(
5004
5049
  motion2.div,
5005
5050
  {
5006
5051
  layout: !reducedMotion,
@@ -5013,7 +5058,7 @@ function PlayArea({
5013
5058
  damping: 20,
5014
5059
  delay: reducedMotion ? 0 : index * 0.05
5015
5060
  },
5016
- children: interactive && onCardClick ? /* @__PURE__ */ jsx13(
5061
+ children: interactive && onCardClick ? /* @__PURE__ */ jsx15(
5017
5062
  "button",
5018
5063
  {
5019
5064
  type: "button",
@@ -5027,7 +5072,7 @@ function PlayArea({
5027
5072
  },
5028
5073
  className: "border-0 bg-transparent p-0 cursor-pointer focus-visible:outline-none",
5029
5074
  style: { all: "unset", cursor: "pointer" },
5030
- children: /* @__PURE__ */ jsx13(
5075
+ children: /* @__PURE__ */ jsx15(
5031
5076
  CardFace,
5032
5077
  {
5033
5078
  card,
@@ -5036,7 +5081,7 @@ function PlayArea({
5036
5081
  }
5037
5082
  )
5038
5083
  }
5039
- ) : /* @__PURE__ */ jsx13(
5084
+ ) : /* @__PURE__ */ jsx15(
5040
5085
  CardFace,
5041
5086
  {
5042
5087
  card,
@@ -5056,7 +5101,7 @@ function PlayArea({
5056
5101
  import { motion as motion3 } from "framer-motion";
5057
5102
  import { clsx as clsx11 } from "clsx";
5058
5103
  import { Loader2 } from "lucide-react";
5059
- import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
5104
+ import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
5060
5105
  var CARD_SKELETON_KEYS = ["card-1", "card-2", "card-3", "card-4", "card-5"];
5061
5106
  var PLAYER_SKELETON_KEYS = ["player-1", "player-2", "player-3", "player-4"];
5062
5107
  var HAND_SKELETON_KEYS = [
@@ -5071,7 +5116,7 @@ function SkeletonBox({
5071
5116
  className,
5072
5117
  animate = true
5073
5118
  }) {
5074
- return /* @__PURE__ */ jsx14(
5119
+ return /* @__PURE__ */ jsx16(
5075
5120
  motion3.div,
5076
5121
  {
5077
5122
  className: clsx11("bg-slate-200 rounded", className),
@@ -5093,7 +5138,7 @@ function CardSkeleton({ size = "md" }) {
5093
5138
  md: "w-20 h-32 sm:w-24 sm:h-36",
5094
5139
  lg: "w-24 h-36 sm:w-32 sm:h-48"
5095
5140
  };
5096
- return /* @__PURE__ */ jsx14(
5141
+ return /* @__PURE__ */ jsx16(
5097
5142
  motion3.div,
5098
5143
  {
5099
5144
  className: clsx11(
@@ -5103,16 +5148,16 @@ function CardSkeleton({ size = "md" }) {
5103
5148
  initial: { opacity: 0, y: 20 },
5104
5149
  animate: { opacity: 1, y: 0 },
5105
5150
  transition: { type: "spring", stiffness: 300, damping: 25 },
5106
- children: /* @__PURE__ */ jsx14(SkeletonBox, { className: "w-full h-full" })
5151
+ children: /* @__PURE__ */ jsx16(SkeletonBox, { className: "w-full h-full" })
5107
5152
  }
5108
5153
  );
5109
5154
  }
5110
5155
  function PlayerSkeleton() {
5111
5156
  return /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3 p-3 bg-white/80 rounded-xl border-2 border-slate-200", children: [
5112
- /* @__PURE__ */ jsx14(SkeletonBox, { className: "w-12 h-12 sm:w-14 sm:h-14 rounded-full" }),
5157
+ /* @__PURE__ */ jsx16(SkeletonBox, { className: "w-12 h-12 sm:w-14 sm:h-14 rounded-full" }),
5113
5158
  /* @__PURE__ */ jsxs7("div", { className: "flex-1 space-y-2", children: [
5114
- /* @__PURE__ */ jsx14(SkeletonBox, { className: "h-4 w-24 sm:w-32" }),
5115
- /* @__PURE__ */ jsx14(SkeletonBox, { className: "h-3 w-16 sm:w-20" })
5159
+ /* @__PURE__ */ jsx16(SkeletonBox, { className: "h-4 w-24 sm:w-32" }),
5160
+ /* @__PURE__ */ jsx16(SkeletonBox, { className: "h-3 w-16 sm:w-20" })
5116
5161
  ] })
5117
5162
  ] });
5118
5163
  }
@@ -5133,15 +5178,15 @@ function GameSkeleton({
5133
5178
  "aria-live": "polite",
5134
5179
  "aria-label": message,
5135
5180
  children: [
5136
- /* @__PURE__ */ jsx14(
5181
+ /* @__PURE__ */ jsx16(
5137
5182
  motion3.div,
5138
5183
  {
5139
5184
  animate: { rotate: 360 },
5140
5185
  transition: { duration: 1, repeat: Infinity, ease: "linear" },
5141
- children: /* @__PURE__ */ jsx14(Loader2, { size: 48, className: "text-blue-500", "aria-hidden": "true" })
5186
+ children: /* @__PURE__ */ jsx16(Loader2, { size: 48, className: "text-blue-500", "aria-hidden": "true" })
5142
5187
  }
5143
5188
  ),
5144
- /* @__PURE__ */ jsx14(
5189
+ /* @__PURE__ */ jsx16(
5145
5190
  motion3.p,
5146
5191
  {
5147
5192
  className: "mt-4 text-slate-600 text-lg font-medium",
@@ -5167,17 +5212,17 @@ function GameSkeleton({
5167
5212
  "aria-live": "polite",
5168
5213
  "aria-label": message,
5169
5214
  children: [
5170
- /* @__PURE__ */ jsx14("div", { className: "flex gap-2 sm:gap-4 mb-8", children: CARD_SKELETON_KEYS.map((key, i) => /* @__PURE__ */ jsx14(
5215
+ /* @__PURE__ */ jsx16("div", { className: "flex gap-2 sm:gap-4 mb-8", children: CARD_SKELETON_KEYS.map((key, i) => /* @__PURE__ */ jsx16(
5171
5216
  motion3.div,
5172
5217
  {
5173
5218
  initial: { opacity: 0, y: 20 },
5174
5219
  animate: { opacity: 1, y: 0 },
5175
5220
  transition: { delay: i * 0.1 },
5176
- children: /* @__PURE__ */ jsx14(CardSkeleton, {})
5221
+ children: /* @__PURE__ */ jsx16(CardSkeleton, {})
5177
5222
  },
5178
5223
  key
5179
5224
  )) }),
5180
- /* @__PURE__ */ jsx14(
5225
+ /* @__PURE__ */ jsx16(
5181
5226
  motion3.p,
5182
5227
  {
5183
5228
  className: "text-slate-600 text-sm sm:text-base",
@@ -5203,17 +5248,17 @@ function GameSkeleton({
5203
5248
  "aria-live": "polite",
5204
5249
  "aria-label": message,
5205
5250
  children: [
5206
- /* @__PURE__ */ jsx14("div", { className: "w-full max-w-md space-y-4 mb-8", children: PLAYER_SKELETON_KEYS.map((key, i) => /* @__PURE__ */ jsx14(
5251
+ /* @__PURE__ */ jsx16("div", { className: "w-full max-w-md space-y-4 mb-8", children: PLAYER_SKELETON_KEYS.map((key, i) => /* @__PURE__ */ jsx16(
5207
5252
  motion3.div,
5208
5253
  {
5209
5254
  initial: { opacity: 0, x: -20 },
5210
5255
  animate: { opacity: 1, x: 0 },
5211
5256
  transition: { delay: i * 0.1 },
5212
- children: /* @__PURE__ */ jsx14(PlayerSkeleton, {})
5257
+ children: /* @__PURE__ */ jsx16(PlayerSkeleton, {})
5213
5258
  },
5214
5259
  key
5215
5260
  )) }),
5216
- /* @__PURE__ */ jsx14(
5261
+ /* @__PURE__ */ jsx16(
5217
5262
  motion3.p,
5218
5263
  {
5219
5264
  className: "text-slate-600 text-sm sm:text-base",
@@ -5239,27 +5284,27 @@ function GameSkeleton({
5239
5284
  "aria-label": message,
5240
5285
  children: [
5241
5286
  /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between mb-6 sm:mb-8", children: [
5242
- /* @__PURE__ */ jsx14(SkeletonBox, { className: "h-8 w-32 sm:w-48" }),
5243
- /* @__PURE__ */ jsx14(SkeletonBox, { className: "h-8 w-20 sm:w-32" })
5287
+ /* @__PURE__ */ jsx16(SkeletonBox, { className: "h-8 w-32 sm:w-48" }),
5288
+ /* @__PURE__ */ jsx16(SkeletonBox, { className: "h-8 w-20 sm:w-32" })
5244
5289
  ] }),
5245
- /* @__PURE__ */ jsx14("div", { className: "grid grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 mb-6 sm:mb-8", children: PLAYER_SKELETON_KEYS.map((key, i) => /* @__PURE__ */ jsx14(
5290
+ /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 mb-6 sm:mb-8", children: PLAYER_SKELETON_KEYS.map((key, i) => /* @__PURE__ */ jsx16(
5246
5291
  motion3.div,
5247
5292
  {
5248
5293
  initial: { opacity: 0, scale: 0.9 },
5249
5294
  animate: { opacity: 1, scale: 1 },
5250
5295
  transition: { delay: i * 0.1 },
5251
- children: /* @__PURE__ */ jsx14(PlayerSkeleton, {})
5296
+ children: /* @__PURE__ */ jsx16(PlayerSkeleton, {})
5252
5297
  },
5253
5298
  key
5254
5299
  )) }),
5255
- /* @__PURE__ */ jsx14("div", { className: "mb-6 sm:mb-8", children: /* @__PURE__ */ jsx14(SkeletonBox, { className: "w-full h-48 sm:h-64 rounded-2xl" }) }),
5256
- /* @__PURE__ */ jsx14("div", { className: "flex justify-center gap-2 sm:gap-4", children: HAND_SKELETON_KEYS.map((key, i) => /* @__PURE__ */ jsx14(
5300
+ /* @__PURE__ */ jsx16("div", { className: "mb-6 sm:mb-8", children: /* @__PURE__ */ jsx16(SkeletonBox, { className: "w-full h-48 sm:h-64 rounded-2xl" }) }),
5301
+ /* @__PURE__ */ jsx16("div", { className: "flex justify-center gap-2 sm:gap-4", children: HAND_SKELETON_KEYS.map((key, i) => /* @__PURE__ */ jsx16(
5257
5302
  motion3.div,
5258
5303
  {
5259
5304
  initial: { opacity: 0, y: 20 },
5260
5305
  animate: { opacity: 1, y: 0 },
5261
5306
  transition: { delay: 0.4 + i * 0.05 },
5262
- children: /* @__PURE__ */ jsx14(CardSkeleton, {})
5307
+ children: /* @__PURE__ */ jsx16(CardSkeleton, {})
5263
5308
  },
5264
5309
  key
5265
5310
  )) }),
@@ -5271,7 +5316,7 @@ function GameSkeleton({
5271
5316
  animate: { opacity: 1 },
5272
5317
  transition: { delay: 0.8 },
5273
5318
  children: [
5274
- /* @__PURE__ */ jsx14(
5319
+ /* @__PURE__ */ jsx16(
5275
5320
  Loader2,
5276
5321
  {
5277
5322
  size: 24,
@@ -5279,7 +5324,7 @@ function GameSkeleton({
5279
5324
  "aria-hidden": "true"
5280
5325
  }
5281
5326
  ),
5282
- /* @__PURE__ */ jsx14("p", { className: "text-slate-600 text-sm sm:text-base font-medium", children: message })
5327
+ /* @__PURE__ */ jsx16("p", { className: "text-slate-600 text-sm sm:text-base font-medium", children: message })
5283
5328
  ]
5284
5329
  }
5285
5330
  )
@@ -5293,13 +5338,13 @@ import { motion as motion4, AnimatePresence as AnimatePresence3 } from "framer-m
5293
5338
  import { X, CheckCircle, AlertCircle, Info, AlertTriangle } from "lucide-react";
5294
5339
 
5295
5340
  // src/ui/internal/ui/alert.tsx
5296
- import { jsx as jsx15 } from "react/jsx-runtime";
5341
+ import { jsx as jsx17 } from "react/jsx-runtime";
5297
5342
  function Alert({
5298
5343
  className,
5299
5344
  variant = "default",
5300
5345
  ...props
5301
5346
  }) {
5302
- return /* @__PURE__ */ jsx15(
5347
+ return /* @__PURE__ */ jsx17(
5303
5348
  "div",
5304
5349
  {
5305
5350
  "data-slot": "alert",
@@ -5317,7 +5362,7 @@ function AlertDescription({
5317
5362
  className,
5318
5363
  ...props
5319
5364
  }) {
5320
- return /* @__PURE__ */ jsx15(
5365
+ return /* @__PURE__ */ jsx17(
5321
5366
  "div",
5322
5367
  {
5323
5368
  "data-slot": "alert-description",
@@ -5332,13 +5377,13 @@ import {
5332
5377
  createContext as createContext5,
5333
5378
  useContext as useContext5,
5334
5379
  useState as useState12,
5335
- useCallback as useCallback9
5380
+ useCallback as useCallback11
5336
5381
  } from "react";
5337
- import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
5382
+ import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs8 } from "react/jsx-runtime";
5338
5383
  var ToastContext = createContext5(null);
5339
5384
  function ToastProvider({ children }) {
5340
5385
  const [toasts, setToasts] = useState12([]);
5341
- const show = useCallback9(
5386
+ const show = useCallback11(
5342
5387
  (message, type = "info", duration = 3e3) => {
5343
5388
  const id = `toast-${Date.now()}-${Math.random()}`;
5344
5389
  const toast = { id, type, message, duration };
@@ -5356,22 +5401,22 @@ function ToastProvider({ children }) {
5356
5401
  },
5357
5402
  []
5358
5403
  );
5359
- const dismiss = useCallback9((id) => {
5404
+ const dismiss = useCallback11((id) => {
5360
5405
  setToasts((prev) => prev.filter((t) => t.id !== id));
5361
5406
  }, []);
5362
- const success = useCallback9(
5407
+ const success = useCallback11(
5363
5408
  (message, duration) => show(message, "success", duration),
5364
5409
  [show]
5365
5410
  );
5366
- const error = useCallback9(
5411
+ const error = useCallback11(
5367
5412
  (message, duration) => show(message, "error", duration),
5368
5413
  [show]
5369
5414
  );
5370
- const info = useCallback9(
5415
+ const info = useCallback11(
5371
5416
  (message, duration) => show(message, "info", duration),
5372
5417
  [show]
5373
5418
  );
5374
- const warning = useCallback9(
5419
+ const warning = useCallback11(
5375
5420
  (message, duration) => show(message, "warning", duration),
5376
5421
  [show]
5377
5422
  );
@@ -5381,7 +5426,7 @@ function ToastProvider({ children }) {
5381
5426
  value: { toasts, show, dismiss, success, error, info, warning },
5382
5427
  children: [
5383
5428
  children,
5384
- /* @__PURE__ */ jsx16(ToastContainer, { toasts, onDismiss: dismiss })
5429
+ /* @__PURE__ */ jsx18(ToastContainer, { toasts, onDismiss: dismiss })
5385
5430
  ]
5386
5431
  }
5387
5432
  );
@@ -5394,7 +5439,7 @@ function useToast() {
5394
5439
  return context;
5395
5440
  }
5396
5441
  function ToastActions({ children }) {
5397
- return /* @__PURE__ */ jsx16(Fragment2, { children: children(useToast()) });
5442
+ return /* @__PURE__ */ jsx18(Fragment2, { children: children(useToast()) });
5398
5443
  }
5399
5444
  var Toast = {
5400
5445
  Actions: ToastActions
@@ -5403,14 +5448,14 @@ function ToastContainer({
5403
5448
  toasts,
5404
5449
  onDismiss
5405
5450
  }) {
5406
- return /* @__PURE__ */ jsx16(
5451
+ return /* @__PURE__ */ jsx18(
5407
5452
  "div",
5408
5453
  {
5409
5454
  className: "fixed bottom-4 right-4 z-50 flex flex-col gap-2 pointer-events-none",
5410
5455
  role: "region",
5411
5456
  "aria-live": "polite",
5412
5457
  "aria-label": "Notifications",
5413
- children: /* @__PURE__ */ jsx16(AnimatePresence3, { children: toasts.map((toast) => /* @__PURE__ */ jsx16(ToastItem, { toast, onDismiss }, toast.id)) })
5458
+ children: /* @__PURE__ */ jsx18(AnimatePresence3, { children: toasts.map((toast) => /* @__PURE__ */ jsx18(ToastItem, { toast, onDismiss }, toast.id)) })
5414
5459
  }
5415
5460
  );
5416
5461
  }
@@ -5454,7 +5499,7 @@ function ToastItem({
5454
5499
  const Icon2 = TOAST_ICONS[toast.type];
5455
5500
  const intent = intentForVariant(theme, TOAST_VARIANT[toast.type]);
5456
5501
  const surfaceStyle2 = toastSurfaceStyle(theme, toast.type);
5457
- return /* @__PURE__ */ jsx16(
5502
+ return /* @__PURE__ */ jsx18(
5458
5503
  motion4.div,
5459
5504
  {
5460
5505
  style: { pointerEvents: "auto" },
@@ -5468,7 +5513,7 @@ function ToastItem({
5468
5513
  variant: toast.type === "error" ? "destructive" : "default",
5469
5514
  style: surfaceStyle2,
5470
5515
  children: [
5471
- /* @__PURE__ */ jsx16(
5516
+ /* @__PURE__ */ jsx18(
5472
5517
  Icon2,
5473
5518
  {
5474
5519
  size: 20,
@@ -5480,7 +5525,7 @@ function ToastItem({
5480
5525
  "aria-hidden": "true"
5481
5526
  }
5482
5527
  ),
5483
- /* @__PURE__ */ jsx16(
5528
+ /* @__PURE__ */ jsx18(
5484
5529
  AlertDescription,
5485
5530
  {
5486
5531
  style: {
@@ -5493,7 +5538,7 @@ function ToastItem({
5493
5538
  children: toast.message
5494
5539
  }
5495
5540
  ),
5496
- /* @__PURE__ */ jsx16(
5541
+ /* @__PURE__ */ jsx18(
5497
5542
  ThemedButton,
5498
5543
  {
5499
5544
  type: "button",
@@ -5508,7 +5553,7 @@ function ToastItem({
5508
5553
  color: intent.onSoft
5509
5554
  },
5510
5555
  "aria-label": "Close notification",
5511
- children: /* @__PURE__ */ jsx16(X, { size: 16, "aria-hidden": "true" })
5556
+ children: /* @__PURE__ */ jsx18(X, { size: 16, "aria-hidden": "true" })
5512
5557
  }
5513
5558
  )
5514
5559
  ]
@@ -5523,7 +5568,7 @@ import {
5523
5568
  Component
5524
5569
  } from "react";
5525
5570
  import { AlertTriangle as AlertTriangle2, RefreshCw } from "lucide-react";
5526
- import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
5571
+ import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs9 } from "react/jsx-runtime";
5527
5572
  var ErrorBoundary = class extends Component {
5528
5573
  constructor(props) {
5529
5574
  super(props);
@@ -5544,7 +5589,7 @@ var ErrorBoundary = class extends Component {
5544
5589
  if (this.props.fallback) {
5545
5590
  return this.props.fallback(this.state.error, this.handleReset);
5546
5591
  }
5547
- return /* @__PURE__ */ jsx17(
5592
+ return /* @__PURE__ */ jsx19(
5548
5593
  DefaultErrorFallback,
5549
5594
  {
5550
5595
  error: this.state.error,
@@ -5698,7 +5743,7 @@ function DefaultErrorFallback({
5698
5743
  width: "100%"
5699
5744
  }
5700
5745
  };
5701
- return /* @__PURE__ */ jsx17(
5746
+ return /* @__PURE__ */ jsx19(
5702
5747
  "div",
5703
5748
  {
5704
5749
  "data-dreamboard-error-fallback": "",
@@ -5706,7 +5751,7 @@ function DefaultErrorFallback({
5706
5751
  role: "alert",
5707
5752
  "aria-live": "assertive",
5708
5753
  children: /* @__PURE__ */ jsxs9("div", { style: styles.panel, children: [
5709
- /* @__PURE__ */ jsx17("div", { style: styles.iconWrap, children: /* @__PURE__ */ jsx17(
5754
+ /* @__PURE__ */ jsx19("div", { style: styles.iconWrap, children: /* @__PURE__ */ jsx19(
5710
5755
  AlertTriangle2,
5711
5756
  {
5712
5757
  size: 28,
@@ -5715,11 +5760,11 @@ function DefaultErrorFallback({
5715
5760
  "aria-hidden": "true"
5716
5761
  }
5717
5762
  ) }),
5718
- /* @__PURE__ */ jsx17("p", { style: styles.eyebrow, children: "Runtime error" }),
5719
- /* @__PURE__ */ jsx17("h1", { style: styles.title, children: "Game failed to start" }),
5720
- /* @__PURE__ */ jsx17("p", { style: styles.body, children: "The game encountered an error and couldn't continue. You can try reloading to start fresh." }),
5763
+ /* @__PURE__ */ jsx19("p", { style: styles.eyebrow, children: "Runtime error" }),
5764
+ /* @__PURE__ */ jsx19("h1", { style: styles.title, children: "Game failed to start" }),
5765
+ /* @__PURE__ */ jsx19("p", { style: styles.body, children: "The game encountered an error and couldn't continue. You can try reloading to start fresh." }),
5721
5766
  /* @__PURE__ */ jsxs9("details", { style: styles.details, children: [
5722
- /* @__PURE__ */ jsx17("summary", { style: styles.summary, children: "Technical details" }),
5767
+ /* @__PURE__ */ jsx19("summary", { style: styles.summary, children: "Technical details" }),
5723
5768
  /* @__PURE__ */ jsxs9("pre", { style: styles.pre, children: [
5724
5769
  error.message,
5725
5770
  error.stack && /* @__PURE__ */ jsxs9(Fragment3, { children: [
@@ -5729,7 +5774,7 @@ function DefaultErrorFallback({
5729
5774
  ] })
5730
5775
  ] }),
5731
5776
  /* @__PURE__ */ jsxs9("button", { type: "button", onClick: onReset, style: styles.button, children: [
5732
- /* @__PURE__ */ jsx17(RefreshCw, { size: 18, "aria-hidden": "true" }),
5777
+ /* @__PURE__ */ jsx19(RefreshCw, { size: 18, "aria-hidden": "true" }),
5733
5778
  "Try again"
5734
5779
  ] })
5735
5780
  ] })
@@ -5740,24 +5785,24 @@ function DefaultErrorFallback({
5740
5785
  // src/ui/internal/ui/dialog.tsx
5741
5786
  import * as DialogPrimitive from "@radix-ui/react-dialog";
5742
5787
  import { XIcon } from "lucide-react";
5743
- import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
5788
+ import { jsx as jsx20, jsxs as jsxs10 } from "react/jsx-runtime";
5744
5789
  function Dialog(props) {
5745
- return /* @__PURE__ */ jsx18(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
5790
+ return /* @__PURE__ */ jsx20(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
5746
5791
  }
5747
5792
  function DialogTrigger(props) {
5748
- return /* @__PURE__ */ jsx18(DialogPrimitive.Trigger, { "data-slot": "dialog-trigger", ...props });
5793
+ return /* @__PURE__ */ jsx20(DialogPrimitive.Trigger, { "data-slot": "dialog-trigger", ...props });
5749
5794
  }
5750
5795
  function DialogPortal(props) {
5751
- return /* @__PURE__ */ jsx18(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
5796
+ return /* @__PURE__ */ jsx20(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
5752
5797
  }
5753
5798
  function DialogClose(props) {
5754
- return /* @__PURE__ */ jsx18(DialogPrimitive.Close, { "data-slot": "dialog-close", ...props });
5799
+ return /* @__PURE__ */ jsx20(DialogPrimitive.Close, { "data-slot": "dialog-close", ...props });
5755
5800
  }
5756
5801
  function DialogOverlay({
5757
5802
  className,
5758
5803
  ...props
5759
5804
  }) {
5760
- return /* @__PURE__ */ jsx18(
5805
+ return /* @__PURE__ */ jsx20(
5761
5806
  DialogPrimitive.Overlay,
5762
5807
  {
5763
5808
  "data-slot": "dialog-overlay",
@@ -5774,7 +5819,7 @@ function DialogContent({
5774
5819
  ...props
5775
5820
  }) {
5776
5821
  return /* @__PURE__ */ jsxs10(DialogPortal, { children: [
5777
- /* @__PURE__ */ jsx18(DialogOverlay, { className: overlayClassName }),
5822
+ /* @__PURE__ */ jsx20(DialogOverlay, { className: overlayClassName }),
5778
5823
  /* @__PURE__ */ jsxs10(
5779
5824
  DialogPrimitive.Content,
5780
5825
  {
@@ -5792,8 +5837,8 @@ function DialogContent({
5792
5837
  "data-slot": "dialog-close",
5793
5838
  className: "absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-slate-400",
5794
5839
  children: [
5795
- /* @__PURE__ */ jsx18(XIcon, { "aria-hidden": "true", className: "size-4" }),
5796
- /* @__PURE__ */ jsx18("span", { className: "sr-only", children: "Close" })
5840
+ /* @__PURE__ */ jsx20(XIcon, { "aria-hidden": "true", className: "size-4" }),
5841
+ /* @__PURE__ */ jsx20("span", { className: "sr-only", children: "Close" })
5797
5842
  ]
5798
5843
  }
5799
5844
  ) : null
@@ -5806,7 +5851,7 @@ function DialogHeader({
5806
5851
  className,
5807
5852
  ...props
5808
5853
  }) {
5809
- return /* @__PURE__ */ jsx18(
5854
+ return /* @__PURE__ */ jsx20(
5810
5855
  "div",
5811
5856
  {
5812
5857
  "data-slot": "dialog-header",
@@ -5819,7 +5864,7 @@ function DialogFooter({
5819
5864
  className,
5820
5865
  ...props
5821
5866
  }) {
5822
- return /* @__PURE__ */ jsx18(
5867
+ return /* @__PURE__ */ jsx20(
5823
5868
  "div",
5824
5869
  {
5825
5870
  "data-slot": "dialog-footer",
@@ -5835,7 +5880,7 @@ function DialogTitle({
5835
5880
  className,
5836
5881
  ...props
5837
5882
  }) {
5838
- return /* @__PURE__ */ jsx18(
5883
+ return /* @__PURE__ */ jsx20(
5839
5884
  DialogPrimitive.Title,
5840
5885
  {
5841
5886
  "data-slot": "dialog-title",
@@ -5848,7 +5893,7 @@ function DialogDescription({
5848
5893
  className,
5849
5894
  ...props
5850
5895
  }) {
5851
- return /* @__PURE__ */ jsx18(
5896
+ return /* @__PURE__ */ jsx20(
5852
5897
  DialogPrimitive.Description,
5853
5898
  {
5854
5899
  "data-slot": "dialog-description",
@@ -5859,13 +5904,13 @@ function DialogDescription({
5859
5904
  }
5860
5905
 
5861
5906
  // src/ui/internal/ui/input.tsx
5862
- import { jsx as jsx19 } from "react/jsx-runtime";
5907
+ import { jsx as jsx21 } from "react/jsx-runtime";
5863
5908
  function Input({
5864
5909
  className,
5865
5910
  type,
5866
5911
  ...props
5867
5912
  }) {
5868
- return /* @__PURE__ */ jsx19(
5913
+ return /* @__PURE__ */ jsx21(
5869
5914
  "input",
5870
5915
  {
5871
5916
  type,
@@ -5882,12 +5927,12 @@ function Input({
5882
5927
 
5883
5928
  // src/ui/internal/ui/label.tsx
5884
5929
  import * as LabelPrimitive from "@radix-ui/react-label";
5885
- import { jsx as jsx20 } from "react/jsx-runtime";
5930
+ import { jsx as jsx22 } from "react/jsx-runtime";
5886
5931
  function Label({
5887
5932
  className,
5888
5933
  ...props
5889
5934
  }) {
5890
- return /* @__PURE__ */ jsx20(
5935
+ return /* @__PURE__ */ jsx22(
5891
5936
  LabelPrimitive.Root,
5892
5937
  {
5893
5938
  "data-slot": "label",
@@ -5903,9 +5948,9 @@ function Label({
5903
5948
  // src/ui/internal/ui/select.tsx
5904
5949
  import * as SelectPrimitive from "@radix-ui/react-select";
5905
5950
  import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
5906
- import { jsx as jsx21, jsxs as jsxs11 } from "react/jsx-runtime";
5951
+ import { jsx as jsx23, jsxs as jsxs11 } from "react/jsx-runtime";
5907
5952
  function Select(props) {
5908
- return /* @__PURE__ */ jsx21(SelectPrimitive.Root, { "data-slot": "select", ...props });
5953
+ return /* @__PURE__ */ jsx23(SelectPrimitive.Root, { "data-slot": "select", ...props });
5909
5954
  }
5910
5955
  function SelectTrigger({
5911
5956
  className,
@@ -5927,7 +5972,7 @@ function SelectTrigger({
5927
5972
  ...props,
5928
5973
  children: [
5929
5974
  children,
5930
- /* @__PURE__ */ jsx21(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx21(ChevronDownIcon, { className: "size-4 opacity-50" }) })
5975
+ /* @__PURE__ */ jsx23(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx23(ChevronDownIcon, { className: "size-4 opacity-50" }) })
5931
5976
  ]
5932
5977
  }
5933
5978
  );
@@ -5939,7 +5984,7 @@ function SelectContent({
5939
5984
  align = "center",
5940
5985
  ...props
5941
5986
  }) {
5942
- return /* @__PURE__ */ jsx21(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs11(
5987
+ return /* @__PURE__ */ jsx23(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs11(
5943
5988
  SelectPrimitive.Content,
5944
5989
  {
5945
5990
  "data-slot": "select-content",
@@ -5951,9 +5996,9 @@ function SelectContent({
5951
5996
  align,
5952
5997
  ...props,
5953
5998
  children: [
5954
- /* @__PURE__ */ jsx21(SelectScrollUpButton, {}),
5955
- /* @__PURE__ */ jsx21(SelectPrimitive.Viewport, { className: "p-1", children }),
5956
- /* @__PURE__ */ jsx21(SelectScrollDownButton, {})
5999
+ /* @__PURE__ */ jsx23(SelectScrollUpButton, {}),
6000
+ /* @__PURE__ */ jsx23(SelectPrimitive.Viewport, { className: "p-1", children }),
6001
+ /* @__PURE__ */ jsx23(SelectScrollDownButton, {})
5957
6002
  ]
5958
6003
  }
5959
6004
  ) });
@@ -5973,8 +6018,8 @@ function SelectItem({
5973
6018
  ),
5974
6019
  ...props,
5975
6020
  children: [
5976
- /* @__PURE__ */ jsx21("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx21(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx21(CheckIcon, { className: "size-4" }) }) }),
5977
- /* @__PURE__ */ jsx21(SelectPrimitive.ItemText, { children })
6021
+ /* @__PURE__ */ jsx23("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx23(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx23(CheckIcon, { className: "size-4" }) }) }),
6022
+ /* @__PURE__ */ jsx23(SelectPrimitive.ItemText, { children })
5978
6023
  ]
5979
6024
  }
5980
6025
  );
@@ -5983,7 +6028,7 @@ function SelectScrollUpButton({
5983
6028
  className,
5984
6029
  ...props
5985
6030
  }) {
5986
- return /* @__PURE__ */ jsx21(
6031
+ return /* @__PURE__ */ jsx23(
5987
6032
  SelectPrimitive.ScrollUpButton,
5988
6033
  {
5989
6034
  "data-slot": "select-scroll-up-button",
@@ -5992,7 +6037,7 @@ function SelectScrollUpButton({
5992
6037
  className
5993
6038
  ),
5994
6039
  ...props,
5995
- children: /* @__PURE__ */ jsx21(ChevronUpIcon, { className: "size-4" })
6040
+ children: /* @__PURE__ */ jsx23(ChevronUpIcon, { className: "size-4" })
5996
6041
  }
5997
6042
  );
5998
6043
  }
@@ -6000,7 +6045,7 @@ function SelectScrollDownButton({
6000
6045
  className,
6001
6046
  ...props
6002
6047
  }) {
6003
- return /* @__PURE__ */ jsx21(
6048
+ return /* @__PURE__ */ jsx23(
6004
6049
  SelectPrimitive.ScrollDownButton,
6005
6050
  {
6006
6051
  "data-slot": "select-scroll-down-button",
@@ -6009,7 +6054,7 @@ function SelectScrollDownButton({
6009
6054
  className
6010
6055
  ),
6011
6056
  ...props,
6012
- children: /* @__PURE__ */ jsx21(ChevronDownIcon, { className: "size-4" })
6057
+ children: /* @__PURE__ */ jsx23(ChevronDownIcon, { className: "size-4" })
6013
6058
  }
6014
6059
  );
6015
6060
  }
@@ -6021,7 +6066,7 @@ import {
6021
6066
  useContext as useContext6,
6022
6067
  useMemo as useMemo10
6023
6068
  } from "react";
6024
- import { jsx as jsx22 } from "react/jsx-runtime";
6069
+ import { jsx as jsx24 } from "react/jsx-runtime";
6025
6070
  var ResourceCounterItemContext = createContext6(null);
6026
6071
  function useResourceCounterItemContext() {
6027
6072
  const value = useContext6(ResourceCounterItemContext);
@@ -6045,7 +6090,7 @@ function renderResourceIcon(icon, props = {}) {
6045
6090
  "aria-hidden": ariaHidden,
6046
6091
  ...spanProps
6047
6092
  } = props;
6048
- return /* @__PURE__ */ jsx22(
6093
+ return /* @__PURE__ */ jsx24(
6049
6094
  "span",
6050
6095
  {
6051
6096
  "aria-hidden": ariaHidden === void 0 ? true : ariaHidden !== "false",
@@ -6091,7 +6136,7 @@ function ResourceCounterRoot({
6091
6136
  "aria-label": ariaLabel ?? "Resource counts",
6092
6137
  "data-dreamboard-resource-counter": "",
6093
6138
  ...props,
6094
- children: items.map((resource) => /* @__PURE__ */ jsx22(ResourceCounterItemContext.Provider, { value: resource, children }, resource.type))
6139
+ children: items.map((resource) => /* @__PURE__ */ jsx24(ResourceCounterItemContext.Provider, { value: resource, children }, resource.type))
6095
6140
  });
6096
6141
  }
6097
6142
  function ResourceCounterItem({
@@ -6174,12 +6219,12 @@ import { clsx as clsx12 } from "clsx";
6174
6219
 
6175
6220
  // src/ui/internal/ui/tooltip.tsx
6176
6221
  import * as TooltipPrimitive from "@radix-ui/react-tooltip";
6177
- import { jsx as jsx23 } from "react/jsx-runtime";
6222
+ import { jsx as jsx25 } from "react/jsx-runtime";
6178
6223
  function TooltipProvider({
6179
6224
  delayDuration = 0,
6180
6225
  ...props
6181
6226
  }) {
6182
- return /* @__PURE__ */ jsx23(
6227
+ return /* @__PURE__ */ jsx25(
6183
6228
  TooltipPrimitive.Provider,
6184
6229
  {
6185
6230
  "data-slot": "tooltip-provider",
@@ -6189,17 +6234,17 @@ function TooltipProvider({
6189
6234
  );
6190
6235
  }
6191
6236
  function Tooltip(props) {
6192
- return /* @__PURE__ */ jsx23(TooltipProvider, { children: /* @__PURE__ */ jsx23(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
6237
+ return /* @__PURE__ */ jsx25(TooltipProvider, { children: /* @__PURE__ */ jsx25(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
6193
6238
  }
6194
6239
  function TooltipTrigger(props) {
6195
- return /* @__PURE__ */ jsx23(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
6240
+ return /* @__PURE__ */ jsx25(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
6196
6241
  }
6197
6242
  function TooltipContent({
6198
6243
  className,
6199
6244
  sideOffset = 0,
6200
6245
  ...props
6201
6246
  }) {
6202
- return /* @__PURE__ */ jsx23(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx23(
6247
+ return /* @__PURE__ */ jsx25(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx25(
6203
6248
  TooltipPrimitive.Content,
6204
6249
  {
6205
6250
  "data-slot": "tooltip-content",
@@ -6214,7 +6259,7 @@ function TooltipContent({
6214
6259
  }
6215
6260
 
6216
6261
  // src/ui/components/CostDisplay.tsx
6217
- import { jsx as jsx24, jsxs as jsxs12 } from "react/jsx-runtime";
6262
+ import { jsx as jsx26, jsxs as jsxs12 } from "react/jsx-runtime";
6218
6263
  function CostDisplay({
6219
6264
  cost,
6220
6265
  currentResources,
@@ -6238,7 +6283,7 @@ function CostDisplay({
6238
6283
  if (costEntries.length === 0) {
6239
6284
  return null;
6240
6285
  }
6241
- return /* @__PURE__ */ jsx24(
6286
+ return /* @__PURE__ */ jsx26(
6242
6287
  "div",
6243
6288
  {
6244
6289
  className: clsx12(
@@ -6250,14 +6295,14 @@ function CostDisplay({
6250
6295
  ),
6251
6296
  role: "list",
6252
6297
  "aria-label": `Cost: ${costEntries.map(([type, amount]) => `${amount} ${resourceMap[type]?.label || type}`).join(", ")}${currentResources ? canAffordAll ? " (affordable)" : " (cannot afford)" : ""}`,
6253
- children: /* @__PURE__ */ jsx24(TooltipProvider, { delayDuration: 200, children: costEntries.map(([type, amount]) => {
6298
+ children: /* @__PURE__ */ jsx26(TooltipProvider, { delayDuration: 200, children: costEntries.map(([type, amount]) => {
6254
6299
  const def = resourceMap[type];
6255
6300
  const have = currentResources?.[type] ?? Infinity;
6256
6301
  const canAfford = have >= amount;
6257
6302
  const Icon2 = def?.icon;
6258
6303
  const label = def?.label || type;
6259
6304
  return /* @__PURE__ */ jsxs12(Tooltip, { children: [
6260
- /* @__PURE__ */ jsx24(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12(
6305
+ /* @__PURE__ */ jsx26(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12(
6261
6306
  "div",
6262
6307
  {
6263
6308
  className: clsx12(
@@ -6271,9 +6316,9 @@ function CostDisplay({
6271
6316
  role: "listitem",
6272
6317
  tabIndex: 0,
6273
6318
  children: [
6274
- Icon2 && /* @__PURE__ */ jsx24(Icon2, { className: styles.icon, "aria-hidden": "true" }),
6275
- /* @__PURE__ */ jsx24("span", { className: "font-semibold", children: amount }),
6276
- !Icon2 && /* @__PURE__ */ jsx24("span", { className: "text-[10px] opacity-70", children: def?.label?.slice(0, 3) || type.slice(0, 3) })
6319
+ Icon2 && /* @__PURE__ */ jsx26(Icon2, { className: styles.icon, "aria-hidden": "true" }),
6320
+ /* @__PURE__ */ jsx26("span", { className: "font-semibold", children: amount }),
6321
+ !Icon2 && /* @__PURE__ */ jsx26("span", { className: "text-[10px] opacity-70", children: def?.label?.slice(0, 3) || type.slice(0, 3) })
6277
6322
  ]
6278
6323
  }
6279
6324
  ) }),
@@ -6284,8 +6329,8 @@ function CostDisplay({
6284
6329
  sideOffset: 6,
6285
6330
  className: "max-w-xs text-left",
6286
6331
  children: [
6287
- /* @__PURE__ */ jsx24("p", { className: "font-sans text-sm font-bold", children: label }),
6288
- /* @__PURE__ */ jsx24("p", { className: "font-sans mt-1 text-xs font-normal opacity-90", children: formatCostAvailability({
6332
+ /* @__PURE__ */ jsx26("p", { className: "font-sans text-sm font-bold", children: label }),
6333
+ /* @__PURE__ */ jsx26("p", { className: "font-sans mt-1 text-xs font-normal opacity-90", children: formatCostAvailability({
6289
6334
  amount,
6290
6335
  canAfford,
6291
6336
  have
@@ -6311,7 +6356,7 @@ function formatCostAvailability({
6311
6356
  }
6312
6357
 
6313
6358
  // src/ui/components/ActionButton.tsx
6314
- import { jsx as jsx25, jsxs as jsxs13 } from "react/jsx-runtime";
6359
+ import { jsx as jsx27, jsxs as jsxs13 } from "react/jsx-runtime";
6315
6360
  function ActionButton({
6316
6361
  label,
6317
6362
  description,
@@ -6361,11 +6406,11 @@ function ActionButton({
6361
6406
  onClick: handleClick,
6362
6407
  ...rest,
6363
6408
  children: [
6364
- Icon2 ? /* @__PURE__ */ jsx25(Icon2, { className: "h-4 w-4", "aria-hidden": "true" }) : null,
6409
+ Icon2 ? /* @__PURE__ */ jsx27(Icon2, { className: "h-4 w-4", "aria-hidden": "true" }) : null,
6365
6410
  /* @__PURE__ */ jsxs13("span", { className: "inline-flex min-w-0 flex-col items-start gap-0.5", children: [
6366
- /* @__PURE__ */ jsx25("span", { children: children ?? label ?? "Action" }),
6367
- description ? /* @__PURE__ */ jsx25("span", { className: "text-xs font-normal opacity-75", children: description }) : null,
6368
- cost && resourceDefs ? /* @__PURE__ */ jsx25(
6411
+ /* @__PURE__ */ jsx27("span", { children: children ?? label ?? "Action" }),
6412
+ description ? /* @__PURE__ */ jsx27("span", { className: "text-xs font-normal opacity-75", children: description }) : null,
6413
+ cost && resourceDefs ? /* @__PURE__ */ jsx27(
6369
6414
  CostDisplay,
6370
6415
  {
6371
6416
  cost,
@@ -6374,14 +6419,14 @@ function ActionButton({
6374
6419
  }
6375
6420
  ) : null
6376
6421
  ] }),
6377
- loading ? /* @__PURE__ */ jsx25("span", { "aria-hidden": "true", children: "..." }) : null
6422
+ loading ? /* @__PURE__ */ jsx27("span", { "aria-hidden": "true", children: "..." }) : null
6378
6423
  ]
6379
6424
  }
6380
6425
  );
6381
6426
  }
6382
6427
 
6383
6428
  // src/ui/components/PrimaryButton.tsx
6384
- import { jsx as jsx26 } from "react/jsx-runtime";
6429
+ import { jsx as jsx28 } from "react/jsx-runtime";
6385
6430
  function PrimaryButton({
6386
6431
  children,
6387
6432
  disabled,
@@ -6390,7 +6435,7 @@ function PrimaryButton({
6390
6435
  size = "md",
6391
6436
  ...rest
6392
6437
  }) {
6393
- return /* @__PURE__ */ jsx26(
6438
+ return /* @__PURE__ */ jsx28(
6394
6439
  ThemedButton,
6395
6440
  {
6396
6441
  type: "button",
@@ -6406,12 +6451,12 @@ function PrimaryButton({
6406
6451
 
6407
6452
  // src/ui/components/PrimaryActionButton.tsx
6408
6453
  import {
6409
- useEffect as useEffect10,
6410
- useRef as useRef6,
6454
+ useEffect as useEffect11,
6455
+ useRef as useRef8,
6411
6456
  useState as useState13
6412
6457
  } from "react";
6413
6458
  import { motion as motion5 } from "framer-motion";
6414
- import { Fragment as Fragment4, jsx as jsx27, jsxs as jsxs14 } from "react/jsx-runtime";
6459
+ import { Fragment as Fragment4, jsx as jsx29, jsxs as jsxs14 } from "react/jsx-runtime";
6415
6460
  function PrimaryActionButton({
6416
6461
  variant = "primary",
6417
6462
  size = "lg",
@@ -6437,9 +6482,9 @@ function PrimaryActionButton({
6437
6482
  const resolvedVariant = submitted ? whenSubmitted?.variant ?? "submitted" : variant;
6438
6483
  const disabled = !available;
6439
6484
  const intent = intentForVariant(theme, resolvedVariant);
6440
- const previouslyAvailableRef = useRef6(available);
6485
+ const previouslyAvailableRef = useRef8(available);
6441
6486
  const [pulseKey, setPulseKey] = useState13(0);
6442
- useEffect10(() => {
6487
+ useEffect11(() => {
6443
6488
  if (!previouslyAvailableRef.current && available) {
6444
6489
  setPulseKey((n) => n + 1);
6445
6490
  }
@@ -6448,7 +6493,7 @@ function PrimaryActionButton({
6448
6493
  const haloEnabled = !reducedMotion && available && attention !== "off" && !submitted;
6449
6494
  const tooltip = available ? void 0 : formatUnavailableReason(unavailableReason);
6450
6495
  const resolvedLabel = submitted ? whenSubmitted?.label ?? label : label;
6451
- const resolvedIcon = submitted && whenSubmitted?.icon ? /* @__PURE__ */ jsx27("span", { "aria-hidden": true, style: { fontSize: "1.15em" }, children: whenSubmitted.icon }) : icon ?? null;
6496
+ const resolvedIcon = submitted && whenSubmitted?.icon ? /* @__PURE__ */ jsx29("span", { "aria-hidden": true, style: { fontSize: "1.15em" }, children: whenSubmitted.icon }) : icon ?? null;
6452
6497
  return /* @__PURE__ */ jsxs14(
6453
6498
  "span",
6454
6499
  {
@@ -6468,7 +6513,7 @@ function PrimaryActionButton({
6468
6513
  },
6469
6514
  children: [
6470
6515
  haloEnabled ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
6471
- /* @__PURE__ */ jsx27(
6516
+ /* @__PURE__ */ jsx29(
6472
6517
  motion5.span,
6473
6518
  {
6474
6519
  "aria-hidden": true,
@@ -6491,7 +6536,7 @@ function PrimaryActionButton({
6491
6536
  }
6492
6537
  }
6493
6538
  ),
6494
- /* @__PURE__ */ jsx27(
6539
+ /* @__PURE__ */ jsx29(
6495
6540
  motion5.span,
6496
6541
  {
6497
6542
  "aria-hidden": true,
@@ -6548,7 +6593,7 @@ function PrimaryActionButton({
6548
6593
  },
6549
6594
  children: [
6550
6595
  resolvedIcon,
6551
- /* @__PURE__ */ jsx27("span", { children: resolvedLabel })
6596
+ /* @__PURE__ */ jsx29("span", { children: resolvedLabel })
6552
6597
  ]
6553
6598
  }
6554
6599
  )
@@ -6586,7 +6631,7 @@ function withAlpha(color, alpha) {
6586
6631
  import { useId as useId4, useState as useState14 } from "react";
6587
6632
  import { motion as motion6, AnimatePresence as AnimatePresence4 } from "framer-motion";
6588
6633
  import { ChevronUp } from "lucide-react";
6589
- import { jsx as jsx28, jsxs as jsxs15 } from "react/jsx-runtime";
6634
+ import { jsx as jsx30, jsxs as jsxs15 } from "react/jsx-runtime";
6590
6635
  function ActionPanel({
6591
6636
  title = "Actions",
6592
6637
  state,
@@ -6649,7 +6694,7 @@ function ActionPanel({
6649
6694
  },
6650
6695
  children: [
6651
6696
  /* @__PURE__ */ jsxs15("div", { children: [
6652
- /* @__PURE__ */ jsx28(
6697
+ /* @__PURE__ */ jsx30(
6653
6698
  "h2",
6654
6699
  {
6655
6700
  style: {
@@ -6677,7 +6722,7 @@ function ActionPanel({
6677
6722
  gap: theme.space[2]
6678
6723
  },
6679
6724
  children: [
6680
- /* @__PURE__ */ jsx28(
6725
+ /* @__PURE__ */ jsx30(
6681
6726
  "span",
6682
6727
  {
6683
6728
  style: {
@@ -6696,7 +6741,7 @@ function ActionPanel({
6696
6741
  }
6697
6742
  )
6698
6743
  ] }),
6699
- collapsible && /* @__PURE__ */ jsx28(
6744
+ collapsible && /* @__PURE__ */ jsx30(
6700
6745
  motion6.div,
6701
6746
  {
6702
6747
  animate: reducedMotion ? void 0 : { rotate: isExpanded ? 0 : 180 },
@@ -6709,7 +6754,7 @@ function ActionPanel({
6709
6754
  color: theme.semantic.text.primary,
6710
6755
  display: "inline-flex"
6711
6756
  },
6712
- children: /* @__PURE__ */ jsx28(
6757
+ children: /* @__PURE__ */ jsx30(
6713
6758
  ChevronUp,
6714
6759
  {
6715
6760
  size: 20,
@@ -6723,7 +6768,7 @@ function ActionPanel({
6723
6768
  ]
6724
6769
  }
6725
6770
  ),
6726
- /* @__PURE__ */ jsx28(AnimatePresence4, { initial: false, children: isExpanded && /* @__PURE__ */ jsx28(
6771
+ /* @__PURE__ */ jsx30(AnimatePresence4, { initial: false, children: isExpanded && /* @__PURE__ */ jsx30(
6727
6772
  motion6.div,
6728
6773
  {
6729
6774
  id: contentId,
@@ -6735,7 +6780,7 @@ function ActionPanel({
6735
6780
  overflow: "hidden",
6736
6781
  background: theme.semantic.surface.card
6737
6782
  },
6738
- children: /* @__PURE__ */ jsx28(
6783
+ children: /* @__PURE__ */ jsx30(
6739
6784
  "div",
6740
6785
  {
6741
6786
  style: {
@@ -6802,7 +6847,7 @@ function ActionGroup({
6802
6847
  role: "group",
6803
6848
  "aria-labelledby": `action-group-${title.toLowerCase().replace(/\s+/g, "-")}`,
6804
6849
  children: [
6805
- /* @__PURE__ */ jsx28(
6850
+ /* @__PURE__ */ jsx30(
6806
6851
  "span",
6807
6852
  {
6808
6853
  style: {
@@ -6815,7 +6860,7 @@ function ActionGroup({
6815
6860
  children: "Group"
6816
6861
  }
6817
6862
  ),
6818
- /* @__PURE__ */ jsx28(
6863
+ /* @__PURE__ */ jsx30(
6819
6864
  "h3",
6820
6865
  {
6821
6866
  id: `action-group-${title.toLowerCase().replace(/\s+/g, "-")}`,
@@ -6830,7 +6875,7 @@ function ActionGroup({
6830
6875
  children: title
6831
6876
  }
6832
6877
  ),
6833
- description && /* @__PURE__ */ jsx28(
6878
+ description && /* @__PURE__ */ jsx30(
6834
6879
  "p",
6835
6880
  {
6836
6881
  style: {
@@ -6844,7 +6889,7 @@ function ActionGroup({
6844
6889
  children: description
6845
6890
  }
6846
6891
  ),
6847
- /* @__PURE__ */ jsx28(
6892
+ /* @__PURE__ */ jsx30(
6848
6893
  "div",
6849
6894
  {
6850
6895
  style: {
@@ -6863,7 +6908,7 @@ function ActionGroup({
6863
6908
  // src/ui/components/MoreActions.tsx
6864
6909
  import { useId as useId5, useState as useState15 } from "react";
6865
6910
  import { ChevronDown, MoreHorizontal } from "lucide-react";
6866
- import { jsx as jsx29, jsxs as jsxs16 } from "react/jsx-runtime";
6911
+ import { jsx as jsx31, jsxs as jsxs16 } from "react/jsx-runtime";
6867
6912
  function MoreActions({
6868
6913
  children,
6869
6914
  label = "More",
@@ -6907,8 +6952,8 @@ function MoreActions({
6907
6952
  ...style
6908
6953
  },
6909
6954
  children: [
6910
- /* @__PURE__ */ jsx29(MoreHorizontal, { size: 16, "aria-hidden": true }),
6911
- /* @__PURE__ */ jsx29("span", { children: label }),
6955
+ /* @__PURE__ */ jsx31(MoreHorizontal, { size: 16, "aria-hidden": true }),
6956
+ /* @__PURE__ */ jsx31("span", { children: label }),
6912
6957
  showCount ? /* @__PURE__ */ jsxs16(
6913
6958
  "span",
6914
6959
  {
@@ -6924,7 +6969,7 @@ function MoreActions({
6924
6969
  ]
6925
6970
  }
6926
6971
  ) : null,
6927
- /* @__PURE__ */ jsx29(
6972
+ /* @__PURE__ */ jsx31(
6928
6973
  ChevronDown,
6929
6974
  {
6930
6975
  size: 14,
@@ -6938,7 +6983,7 @@ function MoreActions({
6938
6983
  ]
6939
6984
  }
6940
6985
  ),
6941
- open ? /* @__PURE__ */ jsx29(
6986
+ open ? /* @__PURE__ */ jsx31(
6942
6987
  "div",
6943
6988
  {
6944
6989
  id: regionId,
@@ -6968,15 +7013,15 @@ function MoreActions({
6968
7013
  import { clsx as clsx13 } from "clsx";
6969
7014
  import { motion as motion7 } from "framer-motion";
6970
7015
  import {
6971
- useCallback as useCallback10,
6972
- useEffect as useEffect11,
6973
- useRef as useRef7,
7016
+ useCallback as useCallback12,
7017
+ useEffect as useEffect12,
7018
+ useRef as useRef9,
6974
7019
  useState as useState16
6975
7020
  } from "react";
6976
7021
 
6977
7022
  // src/ui/primitives/dice.tsx
6978
7023
  import { createContext as createContext7, useContext as useContext7 } from "react";
6979
- import { jsx as jsx30 } from "react/jsx-runtime";
7024
+ import { jsx as jsx32 } from "react/jsx-runtime";
6980
7025
  var DiceContext = createContext7(null);
6981
7026
  function normalizeDiceState({
6982
7027
  values,
@@ -6997,7 +7042,7 @@ function normalizeDiceState({
6997
7042
  }
6998
7043
 
6999
7044
  // src/ui/components/DiceRoller.tsx
7000
- import { jsx as jsx31, jsxs as jsxs17 } from "react/jsx-runtime";
7045
+ import { jsx as jsx33, jsxs as jsxs17 } from "react/jsx-runtime";
7001
7046
  var DEFAULT_MIN_SPIN_MS = 1200;
7002
7047
  var DEFAULT_REVEAL_HOLD_MS = 1400;
7003
7048
  var FACE_SEQUENCE = [1, 2, 3, 4, 5, 6];
@@ -7016,8 +7061,8 @@ function DiceRoller({
7016
7061
  role: "region",
7017
7062
  "aria-label": "Dice roller",
7018
7063
  children: [
7019
- render ? render(renderProps) : /* @__PURE__ */ jsx31(DefaultDiceReadout, { ...renderProps }),
7020
- rollAction ? /* @__PURE__ */ jsx31(
7064
+ render ? render(renderProps) : /* @__PURE__ */ jsx33(DefaultDiceReadout, { ...renderProps }),
7065
+ rollAction ? /* @__PURE__ */ jsx33(
7021
7066
  DiceRollDialog,
7022
7067
  {
7023
7068
  action: rollAction,
@@ -7025,7 +7070,7 @@ function DiceRoller({
7025
7070
  diceCount: renderProps.diceCount
7026
7071
  }
7027
7072
  ) : null,
7028
- /* @__PURE__ */ jsx31("div", { className: "sr-only", "aria-live": "polite", children: renderProps.allRolled && renderProps.values ? `Rolled ${renderProps.values.join(", ")}. Total: ${renderProps.sum}` : "Dice not rolled yet" })
7073
+ /* @__PURE__ */ jsx33("div", { className: "sr-only", "aria-live": "polite", children: renderProps.allRolled && renderProps.values ? `Rolled ${renderProps.values.join(", ")}. Total: ${renderProps.sum}` : "Dice not rolled yet" })
7029
7074
  ]
7030
7075
  }
7031
7076
  );
@@ -7063,7 +7108,7 @@ function DefaultDiceReadout({
7063
7108
  ]
7064
7109
  }
7065
7110
  ) : null,
7066
- /* @__PURE__ */ jsx31(DiceRow, { values: dice, size: 44, rolling: false })
7111
+ /* @__PURE__ */ jsx33(DiceRow, { values: dice, size: 44, rolling: false })
7067
7112
  ]
7068
7113
  }
7069
7114
  );
@@ -7083,14 +7128,14 @@ function DiceRollDialog({
7083
7128
  () => nextAnimatedValues(diceCount)
7084
7129
  );
7085
7130
  const [revealedValues, setRevealedValues] = useState16(void 0);
7086
- const startedAtRef = useRef7(0);
7087
- const revealedRollKeyRef = useRef7(null);
7131
+ const startedAtRef = useRef9(0);
7132
+ const revealedRollKeyRef = useRef9(null);
7088
7133
  const shouldPresentDialog = Boolean(action.onRoll);
7089
7134
  const minSpinMs = reducedMotion ? 0 : action.minSpinMs ?? DEFAULT_MIN_SPIN_MS;
7090
7135
  const revealHoldMs = action.revealHoldMs ?? DEFAULT_REVEAL_HOLD_MS;
7091
7136
  const rolledValuesKey = values?.join(",") ?? "";
7092
7137
  const valuesAreReady = values !== void 0 && values.length > 0 && values.every((value) => typeof value === "number");
7093
- useEffect11(() => {
7138
+ useEffect12(() => {
7094
7139
  if (!shouldPresentDialog) {
7095
7140
  setOpen(false);
7096
7141
  return;
@@ -7118,7 +7163,7 @@ function DiceRollDialog({
7118
7163
  shouldPresentDialog,
7119
7164
  valuesAreReady
7120
7165
  ]);
7121
- useEffect11(() => {
7166
+ useEffect12(() => {
7122
7167
  if (phase !== "rolling") return;
7123
7168
  if (reducedMotion) return;
7124
7169
  const interval = setInterval(() => {
@@ -7126,7 +7171,7 @@ function DiceRollDialog({
7126
7171
  }, 120);
7127
7172
  return () => clearInterval(interval);
7128
7173
  }, [diceCount, phase, reducedMotion]);
7129
- useEffect11(() => {
7174
+ useEffect12(() => {
7130
7175
  if (phase !== "rolling" || !valuesAreReady || !values) return;
7131
7176
  const remaining = Math.max(
7132
7177
  0,
@@ -7139,7 +7184,7 @@ function DiceRollDialog({
7139
7184
  }, remaining);
7140
7185
  return () => clearTimeout(timeout);
7141
7186
  }, [minSpinMs, phase, rolledValuesKey, values, valuesAreReady]);
7142
- useEffect11(() => {
7187
+ useEffect12(() => {
7143
7188
  if (phase !== "revealed") return;
7144
7189
  const timeout = setTimeout(() => {
7145
7190
  setOpen(false);
@@ -7147,7 +7192,7 @@ function DiceRollDialog({
7147
7192
  }, revealHoldMs);
7148
7193
  return () => clearTimeout(timeout);
7149
7194
  }, [phase, revealHoldMs]);
7150
- const roll = useCallback10(async () => {
7195
+ const roll = useCallback12(async () => {
7151
7196
  if (!action.onRoll || action.available === false || phase === "rolling") {
7152
7197
  return;
7153
7198
  }
@@ -7174,7 +7219,7 @@ function DiceRollDialog({
7174
7219
  const rollLabel = action.rollLabel ?? "Roll dice";
7175
7220
  const disabled = action.available === false || phase === "rolling";
7176
7221
  const canClose = true;
7177
- return /* @__PURE__ */ jsx31(Dialog, { open, onOpenChange: canClose ? setOpen : void 0, children: /* @__PURE__ */ jsxs17(
7222
+ return /* @__PURE__ */ jsx33(Dialog, { open, onOpenChange: canClose ? setOpen : void 0, children: /* @__PURE__ */ jsxs17(
7178
7223
  DialogContent,
7179
7224
  {
7180
7225
  "data-dismiss-behavior": "dismiss",
@@ -7190,7 +7235,7 @@ function DiceRollDialog({
7190
7235
  onInteractOutside: canClose ? void 0 : (event) => event.preventDefault(),
7191
7236
  children: [
7192
7237
  /* @__PURE__ */ jsxs17(DialogHeader, { className: "text-center sm:text-center", children: [
7193
- /* @__PURE__ */ jsx31(
7238
+ /* @__PURE__ */ jsx33(
7194
7239
  DialogTitle,
7195
7240
  {
7196
7241
  style: {
@@ -7200,7 +7245,7 @@ function DiceRollDialog({
7200
7245
  children: title
7201
7246
  }
7202
7247
  ),
7203
- /* @__PURE__ */ jsx31(DialogDescription, { children: description })
7248
+ /* @__PURE__ */ jsx33(DialogDescription, { children: description })
7204
7249
  ] }),
7205
7250
  /* @__PURE__ */ jsxs17(
7206
7251
  "div",
@@ -7212,8 +7257,8 @@ function DiceRollDialog({
7212
7257
  gap: theme.space[4]
7213
7258
  },
7214
7259
  children: [
7215
- /* @__PURE__ */ jsx31(RollResult, { label: resultLabel, sum: displaySum, phase }),
7216
- /* @__PURE__ */ jsx31(
7260
+ /* @__PURE__ */ jsx33(RollResult, { label: resultLabel, sum: displaySum, phase }),
7261
+ /* @__PURE__ */ jsx33(
7217
7262
  DiceRow,
7218
7263
  {
7219
7264
  values: displayValues,
@@ -7221,7 +7266,7 @@ function DiceRollDialog({
7221
7266
  rolling: phase === "rolling"
7222
7267
  }
7223
7268
  ),
7224
- error ? /* @__PURE__ */ jsx31(
7269
+ error ? /* @__PURE__ */ jsx33(
7225
7270
  "span",
7226
7271
  {
7227
7272
  role: "alert",
@@ -7233,7 +7278,7 @@ function DiceRollDialog({
7233
7278
  children: error
7234
7279
  }
7235
7280
  ) : null,
7236
- /* @__PURE__ */ jsx31(
7281
+ /* @__PURE__ */ jsx33(
7237
7282
  ThemedButton,
7238
7283
  {
7239
7284
  type: "button",
@@ -7273,7 +7318,7 @@ function RollResult({
7273
7318
  textAlign: "center"
7274
7319
  },
7275
7320
  children: [
7276
- /* @__PURE__ */ jsx31(
7321
+ /* @__PURE__ */ jsx33(
7277
7322
  "div",
7278
7323
  {
7279
7324
  style: {
@@ -7286,7 +7331,7 @@ function RollResult({
7286
7331
  children: label
7287
7332
  }
7288
7333
  ),
7289
- /* @__PURE__ */ jsx31(
7334
+ /* @__PURE__ */ jsx33(
7290
7335
  "div",
7291
7336
  {
7292
7337
  style: {
@@ -7310,7 +7355,7 @@ function DiceRow({
7310
7355
  rolling
7311
7356
  }) {
7312
7357
  const gap = Math.max(8, Math.round(size * 0.18));
7313
- return /* @__PURE__ */ jsx31(
7358
+ return /* @__PURE__ */ jsx33(
7314
7359
  "div",
7315
7360
  {
7316
7361
  role: "list",
@@ -7321,7 +7366,7 @@ function DiceRow({
7321
7366
  gap,
7322
7367
  flexWrap: "wrap"
7323
7368
  },
7324
- children: values.map((value, index) => /* @__PURE__ */ jsx31(
7369
+ children: values.map((value, index) => /* @__PURE__ */ jsx33(
7325
7370
  DieFace,
7326
7371
  {
7327
7372
  value,
@@ -7357,7 +7402,7 @@ function DieFace({
7357
7402
  flex: "0 0 auto",
7358
7403
  overflow: "hidden"
7359
7404
  };
7360
- return /* @__PURE__ */ jsx31(
7405
+ return /* @__PURE__ */ jsx33(
7361
7406
  motion7.div,
7362
7407
  {
7363
7408
  role: "listitem",
@@ -7374,7 +7419,7 @@ function DieFace({
7374
7419
  delay: index * 0.06,
7375
7420
  ease: "easeInOut"
7376
7421
  } : { duration: 0.2 },
7377
- children: showPips ? /* @__PURE__ */ jsx31(PipFace, { value }) : /* @__PURE__ */ jsx31(
7422
+ children: showPips ? /* @__PURE__ */ jsx33(PipFace, { value }) : /* @__PURE__ */ jsx33(
7378
7423
  "span",
7379
7424
  {
7380
7425
  style: {
@@ -7392,7 +7437,7 @@ function DieFace({
7392
7437
  function PipFace({ value }) {
7393
7438
  const theme = useTheme();
7394
7439
  const pips = pipPositions(value);
7395
- return /* @__PURE__ */ jsx31(
7440
+ return /* @__PURE__ */ jsx33(
7396
7441
  "span",
7397
7442
  {
7398
7443
  "aria-hidden": true,
@@ -7400,7 +7445,7 @@ function PipFace({ value }) {
7400
7445
  position: "absolute",
7401
7446
  inset: "18%"
7402
7447
  },
7403
- children: pips.map(([left, top], index) => /* @__PURE__ */ jsx31(
7448
+ children: pips.map(([left, top], index) => /* @__PURE__ */ jsx33(
7404
7449
  "span",
7405
7450
  {
7406
7451
  style: {
@@ -7477,7 +7522,7 @@ function sumValues(values) {
7477
7522
  // src/ui/components/PhaseIndicator.tsx
7478
7523
  import { motion as motion8 } from "framer-motion";
7479
7524
  import { clsx as clsx14 } from "clsx";
7480
- import { jsx as jsx32, jsxs as jsxs18 } from "react/jsx-runtime";
7525
+ import { jsx as jsx34, jsxs as jsxs18 } from "react/jsx-runtime";
7481
7526
  function PhaseIndicator({
7482
7527
  currentPhase,
7483
7528
  phaseLabels,
@@ -7490,7 +7535,7 @@ function PhaseIndicator({
7490
7535
  const reducedMotion = theme.motion.reducedMotion === "true";
7491
7536
  const label = phaseLabels?.[currentPhase] ?? formatPhase(currentPhase);
7492
7537
  if (variant === "minimal") {
7493
- return /* @__PURE__ */ jsx32(
7538
+ return /* @__PURE__ */ jsx34(
7494
7539
  "span",
7495
7540
  {
7496
7541
  className,
@@ -7525,7 +7570,7 @@ function PhaseIndicator({
7525
7570
  reducedMotion
7526
7571
  });
7527
7572
  const ariaLabel = state === "your-turn" ? `Your turn \u2014 ${label}` : state === "waiting" ? `Waiting for ${formatPlayerList(activePlayerNames ?? [])} \u2014 ${label}` : label;
7528
- return /* @__PURE__ */ jsx32(
7573
+ return /* @__PURE__ */ jsx34(
7529
7574
  "div",
7530
7575
  {
7531
7576
  className: clsx14("flex items-center gap-3 flex-wrap", className),
@@ -7556,7 +7601,7 @@ function renderHeadline({
7556
7601
  reducedMotion
7557
7602
  }) {
7558
7603
  if (state === "phase-only") {
7559
- return /* @__PURE__ */ jsx32("div", { style: textBlockStyle(theme), children: /* @__PURE__ */ jsx32("span", { style: titleTextStyle(theme), children: label }) });
7604
+ return /* @__PURE__ */ jsx34("div", { style: textBlockStyle(theme), children: /* @__PURE__ */ jsx34("span", { style: titleTextStyle(theme), children: label }) });
7560
7605
  }
7561
7606
  const isYourTurn = state === "your-turn";
7562
7607
  const intent = isYourTurn ? theme.semantic.intent.success : theme.semantic.intent.info;
@@ -7572,7 +7617,7 @@ function renderHeadline({
7572
7617
  gap: theme.space[3]
7573
7618
  },
7574
7619
  children: [
7575
- /* @__PURE__ */ jsx32(
7620
+ /* @__PURE__ */ jsx34(
7576
7621
  StatusIndicator,
7577
7622
  {
7578
7623
  intent,
@@ -7581,8 +7626,8 @@ function renderHeadline({
7581
7626
  }
7582
7627
  ),
7583
7628
  /* @__PURE__ */ jsxs18("div", { style: textBlockStyle(theme), children: [
7584
- /* @__PURE__ */ jsx32("span", { style: titleTextStyle(theme), children: titleText }),
7585
- /* @__PURE__ */ jsx32("span", { style: subtitleTextStyle(theme), children: label })
7629
+ /* @__PURE__ */ jsx34("span", { style: titleTextStyle(theme), children: titleText }),
7630
+ /* @__PURE__ */ jsx34("span", { style: subtitleTextStyle(theme), children: label })
7586
7631
  ] })
7587
7632
  ]
7588
7633
  }
@@ -7638,7 +7683,7 @@ function StatusIndicator({
7638
7683
  flexShrink: 0
7639
7684
  },
7640
7685
  children: [
7641
- /* @__PURE__ */ jsx32(
7686
+ /* @__PURE__ */ jsx34(
7642
7687
  motion8.span,
7643
7688
  {
7644
7689
  style: {
@@ -7655,7 +7700,7 @@ function StatusIndicator({
7655
7700
  }
7656
7701
  }
7657
7702
  ),
7658
- /* @__PURE__ */ jsx32(
7703
+ /* @__PURE__ */ jsx34(
7659
7704
  "span",
7660
7705
  {
7661
7706
  style: {
@@ -7686,7 +7731,7 @@ function StatusIndicator({
7686
7731
  flexShrink: 0
7687
7732
  },
7688
7733
  children: [
7689
- /* @__PURE__ */ jsx32(
7734
+ /* @__PURE__ */ jsx34(
7690
7735
  "span",
7691
7736
  {
7692
7737
  style: {
@@ -7697,7 +7742,7 @@ function StatusIndicator({
7697
7742
  }
7698
7743
  }
7699
7744
  ),
7700
- /* @__PURE__ */ jsx32(
7745
+ /* @__PURE__ */ jsx34(
7701
7746
  motion8.span,
7702
7747
  {
7703
7748
  style: {
@@ -7724,8 +7769,8 @@ function StatusIndicator({
7724
7769
  // src/ui/components/GameEndDisplay.tsx
7725
7770
  import { motion as motion9 } from "framer-motion";
7726
7771
  import { Trophy, Home, Crown, Medal } from "lucide-react";
7727
- import { useEffect as useEffect12, useState as useState17 } from "react";
7728
- import { jsx as jsx33, jsxs as jsxs19 } from "react/jsx-runtime";
7772
+ import { useEffect as useEffect13, useState as useState17 } from "react";
7773
+ import { jsx as jsx35, jsxs as jsxs19 } from "react/jsx-runtime";
7729
7774
  function rankIntent(rank) {
7730
7775
  if (rank === 1) return "warning";
7731
7776
  if (rank === 2) return "secondary";
@@ -7735,7 +7780,7 @@ function rankIntent(rank) {
7735
7780
  function RankIcon({ rank, theme }) {
7736
7781
  const intent = intentForVariant(theme, rankIntent(rank));
7737
7782
  if (rank === 1) {
7738
- return /* @__PURE__ */ jsx33(
7783
+ return /* @__PURE__ */ jsx35(
7739
7784
  Trophy,
7740
7785
  {
7741
7786
  width: 20,
@@ -7747,7 +7792,7 @@ function RankIcon({ rank, theme }) {
7747
7792
  );
7748
7793
  }
7749
7794
  if (rank === 2 || rank === 3) {
7750
- return /* @__PURE__ */ jsx33(
7795
+ return /* @__PURE__ */ jsx35(
7751
7796
  Medal,
7752
7797
  {
7753
7798
  width: 20,
@@ -7786,7 +7831,7 @@ function GameEndDisplay({
7786
7831
  const theme = useTheme();
7787
7832
  const reducedMotion = theme.motion.reducedMotion === "true";
7788
7833
  const [isOpen, setIsOpen] = useState17(isGameOver);
7789
- useEffect12(() => {
7834
+ useEffect13(() => {
7790
7835
  setIsOpen(isGameOver);
7791
7836
  }, [isGameOver]);
7792
7837
  if (!isGameOver) return null;
@@ -7794,7 +7839,7 @@ function GameEndDisplay({
7794
7839
  const sortedScores = [...scores].sort((a, b) => b.score - a.score);
7795
7840
  const winningIntent = theme.semantic.intent.warning;
7796
7841
  const title = `${winner?.name ?? "Game"} Wins!`;
7797
- return /* @__PURE__ */ jsx33(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs19(
7842
+ return /* @__PURE__ */ jsx35(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs19(
7798
7843
  DialogContent,
7799
7844
  {
7800
7845
  className: `border-0 p-6 text-center shadow-none sm:max-w-lg ${className ?? ""}`,
@@ -7812,8 +7857,8 @@ function GameEndDisplay({
7812
7857
  fontFamily: theme.typography.fontFamily.body
7813
7858
  },
7814
7859
  children: [
7815
- /* @__PURE__ */ jsx33(DialogTitle, { className: "sr-only", children: title }),
7816
- /* @__PURE__ */ jsx33(
7860
+ /* @__PURE__ */ jsx35(DialogTitle, { className: "sr-only", children: title }),
7861
+ /* @__PURE__ */ jsx35(
7817
7862
  motion9.div,
7818
7863
  {
7819
7864
  initial: reducedMotion ? { scale: 1 } : { scale: 0.95, rotate: -180, opacity: 0 },
@@ -7836,7 +7881,7 @@ function GameEndDisplay({
7836
7881
  border: `3px solid ${winningIntent.border}`,
7837
7882
  boxShadow: theme.elevation.lifted
7838
7883
  },
7839
- children: /* @__PURE__ */ jsx33(
7884
+ children: /* @__PURE__ */ jsx35(
7840
7885
  Trophy,
7841
7886
  {
7842
7887
  width: 48,
@@ -7855,7 +7900,7 @@ function GameEndDisplay({
7855
7900
  animate: reducedMotion ? { opacity: 1 } : { opacity: 1, y: 0 },
7856
7901
  transition: { delay: reducedMotion ? 0 : 0.4 },
7857
7902
  children: [
7858
- /* @__PURE__ */ jsx33(
7903
+ /* @__PURE__ */ jsx35(
7859
7904
  "h2",
7860
7905
  {
7861
7906
  "aria-hidden": "true",
@@ -7871,7 +7916,7 @@ function GameEndDisplay({
7871
7916
  children: title
7872
7917
  }
7873
7918
  ),
7874
- winnerMessage && /* @__PURE__ */ jsx33(
7919
+ winnerMessage && /* @__PURE__ */ jsx35(
7875
7920
  "p",
7876
7921
  {
7877
7922
  style: {
@@ -7887,7 +7932,7 @@ function GameEndDisplay({
7887
7932
  ]
7888
7933
  }
7889
7934
  ),
7890
- /* @__PURE__ */ jsx33(
7935
+ /* @__PURE__ */ jsx35(
7891
7936
  motion9.div,
7892
7937
  {
7893
7938
  initial: { opacity: 0 },
@@ -7935,8 +7980,8 @@ function GameEndDisplay({
7935
7980
  gap: theme.space[3]
7936
7981
  },
7937
7982
  children: [
7938
- /* @__PURE__ */ jsx33(RankIcon, { rank, theme }),
7939
- /* @__PURE__ */ jsx33(
7983
+ /* @__PURE__ */ jsx35(RankIcon, { rank, theme }),
7984
+ /* @__PURE__ */ jsx35(
7940
7985
  "span",
7941
7986
  {
7942
7987
  style: {
@@ -7948,7 +7993,7 @@ function GameEndDisplay({
7948
7993
  children: player.name
7949
7994
  }
7950
7995
  ),
7951
- isWinner && /* @__PURE__ */ jsx33(
7996
+ isWinner && /* @__PURE__ */ jsx35(
7952
7997
  Crown,
7953
7998
  {
7954
7999
  width: 20,
@@ -7961,7 +8006,7 @@ function GameEndDisplay({
7961
8006
  ]
7962
8007
  }
7963
8008
  ),
7964
- /* @__PURE__ */ jsx33(
8009
+ /* @__PURE__ */ jsx35(
7965
8010
  "span",
7966
8011
  {
7967
8012
  style: {
@@ -8015,7 +8060,7 @@ function GameEndDisplay({
8015
8060
  gap: theme.space[2]
8016
8061
  },
8017
8062
  children: [
8018
- /* @__PURE__ */ jsx33(
8063
+ /* @__PURE__ */ jsx35(
8019
8064
  "span",
8020
8065
  {
8021
8066
  style: {
@@ -8031,7 +8076,7 @@ function GameEndDisplay({
8031
8076
  ]
8032
8077
  }
8033
8078
  ),
8034
- /* @__PURE__ */ jsx33(
8079
+ /* @__PURE__ */ jsx35(
8035
8080
  "div",
8036
8081
  {
8037
8082
  style: {
@@ -8049,8 +8094,8 @@ function GameEndDisplay({
8049
8094
  color: theme.semantic.text.primary
8050
8095
  },
8051
8096
  children: [
8052
- /* @__PURE__ */ jsx33("span", { style: { textTransform: "capitalize" }, children: key.replace(/([A-Z])/g, " $1") }),
8053
- /* @__PURE__ */ jsx33(
8097
+ /* @__PURE__ */ jsx35("span", { style: { textTransform: "capitalize" }, children: key.replace(/([A-Z])/g, " $1") }),
8098
+ /* @__PURE__ */ jsx35(
8054
8099
  "span",
8055
8100
  {
8056
8101
  style: {
@@ -8069,7 +8114,7 @@ function GameEndDisplay({
8069
8114
  ]
8070
8115
  }
8071
8116
  ),
8072
- onReturnToLobby && /* @__PURE__ */ jsx33(
8117
+ onReturnToLobby && /* @__PURE__ */ jsx35(
8073
8118
  motion9.div,
8074
8119
  {
8075
8120
  initial: reducedMotion ? { opacity: 0 } : { opacity: 0, y: 10 },
@@ -8087,7 +8132,7 @@ function GameEndDisplay({
8087
8132
  gap: theme.space[2]
8088
8133
  },
8089
8134
  children: [
8090
- /* @__PURE__ */ jsx33(Home, { size: 20, strokeWidth: 3, "aria-hidden": "true" }),
8135
+ /* @__PURE__ */ jsx35(Home, { size: 20, strokeWidth: 3, "aria-hidden": "true" }),
8091
8136
  "Return to Lobby"
8092
8137
  ]
8093
8138
  }
@@ -8119,7 +8164,7 @@ function handleKeyboardActivation(event, onActivate, options) {
8119
8164
  }
8120
8165
 
8121
8166
  // src/ui/components/board/NetworkGraph.tsx
8122
- import { Fragment as Fragment5, jsx as jsx34, jsxs as jsxs20 } from "react/jsx-runtime";
8167
+ import { Fragment as Fragment5, jsx as jsx36, jsxs as jsxs20 } from "react/jsx-runtime";
8123
8168
  var EMPTY_NETWORK_EDGES = [];
8124
8169
  var EMPTY_NETWORK_PIECES = [];
8125
8170
  function DefaultNetworkNode({
@@ -8156,7 +8201,7 @@ function DefaultNetworkNode({
8156
8201
  tabIndex: onClick ? 0 : void 0,
8157
8202
  "aria-label": onClick ? label ?? "Network node" : void 0,
8158
8203
  children: [
8159
- /* @__PURE__ */ jsx34(
8204
+ /* @__PURE__ */ jsx36(
8160
8205
  "circle",
8161
8206
  {
8162
8207
  r: radius,
@@ -8165,7 +8210,7 @@ function DefaultNetworkNode({
8165
8210
  strokeWidth: effectiveStrokeWidth
8166
8211
  }
8167
8212
  ),
8168
- displayLabel && /* @__PURE__ */ jsx34(
8213
+ displayLabel && /* @__PURE__ */ jsx36(
8169
8214
  "text",
8170
8215
  {
8171
8216
  textAnchor: "middle",
@@ -8213,7 +8258,7 @@ function DefaultNetworkEdge({
8213
8258
  tabIndex: onClick ? 0 : void 0,
8214
8259
  "aria-label": onClick ? label !== void 0 ? `Network edge ${label}` : "Network edge" : void 0,
8215
8260
  children: [
8216
- /* @__PURE__ */ jsx34(
8261
+ /* @__PURE__ */ jsx36(
8217
8262
  "line",
8218
8263
  {
8219
8264
  x1: from.x,
@@ -8226,7 +8271,7 @@ function DefaultNetworkEdge({
8226
8271
  }
8227
8272
  ),
8228
8273
  label !== void 0 && /* @__PURE__ */ jsxs20(Fragment5, { children: [
8229
- /* @__PURE__ */ jsx34(
8274
+ /* @__PURE__ */ jsx36(
8230
8275
  "circle",
8231
8276
  {
8232
8277
  cx: midX,
@@ -8237,7 +8282,7 @@ function DefaultNetworkEdge({
8237
8282
  strokeWidth: 1
8238
8283
  }
8239
8284
  ),
8240
- /* @__PURE__ */ jsx34(
8285
+ /* @__PURE__ */ jsx36(
8241
8286
  "text",
8242
8287
  {
8243
8288
  x: midX,
@@ -8262,7 +8307,7 @@ function DefaultNetworkPiece({
8262
8307
  onClick,
8263
8308
  className
8264
8309
  }) {
8265
- return /* @__PURE__ */ jsx34(
8310
+ return /* @__PURE__ */ jsx36(
8266
8311
  "g",
8267
8312
  {
8268
8313
  onClick,
@@ -8271,7 +8316,7 @@ function DefaultNetworkPiece({
8271
8316
  role: onClick ? "button" : void 0,
8272
8317
  tabIndex: onClick ? 0 : void 0,
8273
8318
  "aria-label": onClick ? "Network piece" : void 0,
8274
- children: shape === "square" ? /* @__PURE__ */ jsx34(
8319
+ children: shape === "square" ? /* @__PURE__ */ jsx36(
8275
8320
  "rect",
8276
8321
  {
8277
8322
  x: -radius,
@@ -8282,7 +8327,7 @@ function DefaultNetworkPiece({
8282
8327
  stroke: "white",
8283
8328
  strokeWidth: 1.5
8284
8329
  }
8285
- ) : /* @__PURE__ */ jsx34("circle", { r: radius, fill: color, stroke: "white", strokeWidth: 1.5 })
8330
+ ) : /* @__PURE__ */ jsx36("circle", { r: radius, fill: color, stroke: "white", strokeWidth: 1.5 })
8286
8331
  }
8287
8332
  );
8288
8333
  }
@@ -8366,11 +8411,11 @@ function NetworkGraph({
8366
8411
  role: "img",
8367
8412
  "aria-label": "Network graph",
8368
8413
  children: [
8369
- /* @__PURE__ */ jsx34("g", { className: "network-edges", role: "list", "aria-label": "Network connections", children: edges.map((edge) => {
8414
+ /* @__PURE__ */ jsx36("g", { className: "network-edges", role: "list", "aria-label": "Network connections", children: edges.map((edge) => {
8370
8415
  const fromNode = nodeMap[edge.from];
8371
8416
  const toNode = nodeMap[edge.to];
8372
8417
  if (!fromNode || !toNode) return null;
8373
- return /* @__PURE__ */ jsx34(
8418
+ return /* @__PURE__ */ jsx36(
8374
8419
  "g",
8375
8420
  {
8376
8421
  role: "listitem",
@@ -8380,7 +8425,7 @@ function NetworkGraph({
8380
8425
  edge.id
8381
8426
  );
8382
8427
  }) }),
8383
- /* @__PURE__ */ jsx34("g", { className: "network-nodes", role: "list", "aria-label": "Network nodes", children: nodes.map((node) => {
8428
+ /* @__PURE__ */ jsx36("g", { className: "network-nodes", role: "list", "aria-label": "Network nodes", children: nodes.map((node) => {
8384
8429
  const nodePieces = piecesByNode[node.id] ?? [];
8385
8430
  return /* @__PURE__ */ jsxs20(
8386
8431
  "g",
@@ -8390,11 +8435,11 @@ function NetworkGraph({
8390
8435
  "aria-label": node.label ?? node.id,
8391
8436
  children: [
8392
8437
  renderNode(node, nodePieces),
8393
- nodePieces.length > 0 && /* @__PURE__ */ jsx34("g", { className: "node-pieces", children: nodePieces.map((piece, i) => {
8438
+ nodePieces.length > 0 && /* @__PURE__ */ jsx36("g", { className: "node-pieces", children: nodePieces.map((piece, i) => {
8394
8439
  const angle = i / nodePieces.length * 2 * Math.PI - Math.PI / 2;
8395
8440
  const pieceX = Math.cos(angle) * (nodeRadius + 8);
8396
8441
  const pieceY = Math.sin(angle) * (nodeRadius + 8);
8397
- return /* @__PURE__ */ jsx34(
8442
+ return /* @__PURE__ */ jsx36(
8398
8443
  "g",
8399
8444
  {
8400
8445
  transform: `translate(${pieceX}, ${pieceY})`,
@@ -8413,7 +8458,7 @@ function NetworkGraph({
8413
8458
  {
8414
8459
  transform: `translate(${viewBoxX + 10}, ${viewBoxY + viewBoxHeight - 30})`,
8415
8460
  children: [
8416
- /* @__PURE__ */ jsx34(
8461
+ /* @__PURE__ */ jsx36(
8417
8462
  "rect",
8418
8463
  {
8419
8464
  x: 0,
@@ -8439,7 +8484,7 @@ function NetworkGraph({
8439
8484
  // src/ui/components/board/ZoneMap.tsx
8440
8485
  import { useMemo as useMemo12 } from "react";
8441
8486
  import { clsx as clsx16 } from "clsx";
8442
- import { jsx as jsx35, jsxs as jsxs21 } from "react/jsx-runtime";
8487
+ import { jsx as jsx37, jsxs as jsxs21 } from "react/jsx-runtime";
8443
8488
  var HIGHLIGHT_COLORS = {
8444
8489
  valid: "rgba(34, 197, 94, 0.4)",
8445
8490
  // Green
@@ -8492,7 +8537,7 @@ function DefaultZone({
8492
8537
  switch (zone.shape.type) {
8493
8538
  case "polygon":
8494
8539
  if (!zone.shape.points) return null;
8495
- return /* @__PURE__ */ jsx35(
8540
+ return /* @__PURE__ */ jsx37(
8496
8541
  "polygon",
8497
8542
  {
8498
8543
  points: zone.shape.points.map((p) => `${p.x},${p.y}`).join(" "),
@@ -8503,7 +8548,7 @@ function DefaultZone({
8503
8548
  );
8504
8549
  case "path":
8505
8550
  if (!zone.shape.path) return null;
8506
- return /* @__PURE__ */ jsx35(
8551
+ return /* @__PURE__ */ jsx37(
8507
8552
  "path",
8508
8553
  {
8509
8554
  d: zone.shape.path,
@@ -8514,7 +8559,7 @@ function DefaultZone({
8514
8559
  );
8515
8560
  case "circle":
8516
8561
  if (!zone.shape.center) return null;
8517
- return /* @__PURE__ */ jsx35(
8562
+ return /* @__PURE__ */ jsx37(
8518
8563
  "circle",
8519
8564
  {
8520
8565
  cx: zone.shape.center.x,
@@ -8542,7 +8587,7 @@ function DefaultZone({
8542
8587
  tabIndex: onClick ? 0 : void 0,
8543
8588
  children: [
8544
8589
  renderShape(),
8545
- showLabel && zone.shape?.center && /* @__PURE__ */ jsx35(
8590
+ showLabel && zone.shape?.center && /* @__PURE__ */ jsx37(
8546
8591
  "text",
8547
8592
  {
8548
8593
  x: zone.shape.center.x,
@@ -8602,7 +8647,7 @@ function DefaultZonePieces({
8602
8647
  });
8603
8648
  const owners = Object.keys(piecesByOwner);
8604
8649
  const startOffset = -((owners.length - 1) * spacing) / 2;
8605
- return /* @__PURE__ */ jsx35("g", { className: clsx16("zone-pieces", className), children: owners.map((owner, i) => {
8650
+ return /* @__PURE__ */ jsx37("g", { className: clsx16("zone-pieces", className), children: owners.map((owner, i) => {
8606
8651
  const ownerPieces = piecesByOwner[owner] || [];
8607
8652
  const totalCount = ownerPieces.reduce(
8608
8653
  (sum, p) => sum + (p.count || 1),
@@ -8614,7 +8659,7 @@ function DefaultZonePieces({
8614
8659
  {
8615
8660
  transform: `translate(${centerX + offsetX}, ${centerY + yOffset})`,
8616
8661
  children: [
8617
- /* @__PURE__ */ jsx35(
8662
+ /* @__PURE__ */ jsx37(
8618
8663
  "circle",
8619
8664
  {
8620
8665
  r: radius,
@@ -8623,7 +8668,7 @@ function DefaultZonePieces({
8623
8668
  strokeWidth: 2
8624
8669
  }
8625
8670
  ),
8626
- /* @__PURE__ */ jsx35(
8671
+ /* @__PURE__ */ jsx37(
8627
8672
  "text",
8628
8673
  {
8629
8674
  textAnchor: "middle",
@@ -8664,8 +8709,8 @@ function DefaultZonePiece({
8664
8709
  tabIndex: onClick ? 0 : void 0,
8665
8710
  "aria-label": `Piece ${piece.id}`,
8666
8711
  children: [
8667
- /* @__PURE__ */ jsx35("circle", { r: radius, fill: color, stroke: "white", strokeWidth: 2 }),
8668
- /* @__PURE__ */ jsx35(
8712
+ /* @__PURE__ */ jsx37("circle", { r: radius, fill: color, stroke: "white", strokeWidth: 2 }),
8713
+ /* @__PURE__ */ jsx37(
8669
8714
  "text",
8670
8715
  {
8671
8716
  textAnchor: "middle",
@@ -8735,17 +8780,17 @@ function ZoneMap({
8735
8780
  role: "img",
8736
8781
  "aria-label": "Zone map",
8737
8782
  children: [
8738
- backgroundImage && /* @__PURE__ */ jsx35("image", { href: backgroundImage, width, height }),
8739
- /* @__PURE__ */ jsx35("g", { className: "zones", role: "list", "aria-label": "Map zones", children: zones.map((zone) => {
8783
+ backgroundImage && /* @__PURE__ */ jsx37("image", { href: backgroundImage, width, height }),
8784
+ /* @__PURE__ */ jsx37("g", { className: "zones", role: "list", "aria-label": "Map zones", children: zones.map((zone) => {
8740
8785
  const zonePieces = piecesByZone[zone.id] || [];
8741
- return /* @__PURE__ */ jsx35("g", { children: renderZone(zone, zonePieces) }, zone.id);
8786
+ return /* @__PURE__ */ jsx37("g", { children: renderZone(zone, zonePieces) }, zone.id);
8742
8787
  }) }),
8743
8788
  enablePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsxs21(
8744
8789
  "g",
8745
8790
  {
8746
8791
  transform: `translate(${viewBoxX + 10}, ${viewBoxY + viewBoxHeight - 30})`,
8747
8792
  children: [
8748
- /* @__PURE__ */ jsx35(
8793
+ /* @__PURE__ */ jsx37(
8749
8794
  "rect",
8750
8795
  {
8751
8796
  x: 0,
@@ -8771,7 +8816,7 @@ function ZoneMap({
8771
8816
  // src/ui/components/board/TrackBoard.tsx
8772
8817
  import { useMemo as useMemo13 } from "react";
8773
8818
  import { clsx as clsx17 } from "clsx";
8774
- import { jsx as jsx36, jsxs as jsxs22 } from "react/jsx-runtime";
8819
+ import { jsx as jsx38, jsxs as jsxs22 } from "react/jsx-runtime";
8775
8820
  function DefaultTrackSpace({
8776
8821
  space,
8777
8822
  size = 50,
@@ -8802,7 +8847,7 @@ function DefaultTrackSpace({
8802
8847
  "aria-label": space.name || `Space ${space.index}`,
8803
8848
  tabIndex: onClick ? 0 : void 0,
8804
8849
  children: [
8805
- /* @__PURE__ */ jsx36(
8850
+ /* @__PURE__ */ jsx38(
8806
8851
  "rect",
8807
8852
  {
8808
8853
  x: -halfSize,
@@ -8815,7 +8860,7 @@ function DefaultTrackSpace({
8815
8860
  strokeWidth: computedStrokeWidth
8816
8861
  }
8817
8862
  ),
8818
- space.name ? /* @__PURE__ */ jsx36(
8863
+ space.name ? /* @__PURE__ */ jsx38(
8819
8864
  "text",
8820
8865
  {
8821
8866
  textAnchor: "middle",
@@ -8825,7 +8870,7 @@ function DefaultTrackSpace({
8825
8870
  fontWeight: "bold",
8826
8871
  children: space.name.length > 8 ? space.name.slice(0, 7) + "\u2026" : space.name
8827
8872
  }
8828
- ) : /* @__PURE__ */ jsx36(
8873
+ ) : /* @__PURE__ */ jsx38(
8829
8874
  "text",
8830
8875
  {
8831
8876
  textAnchor: "middle",
@@ -8837,8 +8882,8 @@ function DefaultTrackSpace({
8837
8882
  }
8838
8883
  ),
8839
8884
  showJumpIndicator && space.jumpTo && /* @__PURE__ */ jsxs22("g", { transform: `translate(${halfSize - 6}, ${-halfSize + 6})`, children: [
8840
- /* @__PURE__ */ jsx36("circle", { r: 6, fill: "#fbbf24" }),
8841
- /* @__PURE__ */ jsx36(
8885
+ /* @__PURE__ */ jsx38("circle", { r: 6, fill: "#fbbf24" }),
8886
+ /* @__PURE__ */ jsx38(
8842
8887
  "text",
8843
8888
  {
8844
8889
  textAnchor: "middle",
@@ -8869,7 +8914,7 @@ function DefaultTrackPiece({
8869
8914
  const offset = total > 1 ? spacing : 0;
8870
8915
  const px = Math.cos(angle) * offset;
8871
8916
  const py = Math.sin(angle) * offset;
8872
- return /* @__PURE__ */ jsx36(
8917
+ return /* @__PURE__ */ jsx38(
8873
8918
  "circle",
8874
8919
  {
8875
8920
  cx: px,
@@ -8897,7 +8942,7 @@ function DefaultTrackConnection({
8897
8942
  strokeWidth = 2,
8898
8943
  className
8899
8944
  }) {
8900
- return /* @__PURE__ */ jsx36(
8945
+ return /* @__PURE__ */ jsx38(
8901
8946
  "line",
8902
8947
  {
8903
8948
  x1: from.x,
@@ -8933,7 +8978,7 @@ function DefaultTrackJump({
8933
8978
  const endY = to.y - unitY * (spaceSize / 2 + 5);
8934
8979
  const markerId = `arrow-${isUp ? "up" : "down"}-${from.x}-${from.y}`;
8935
8980
  return /* @__PURE__ */ jsxs22("g", { className, children: [
8936
- /* @__PURE__ */ jsx36("defs", { children: /* @__PURE__ */ jsx36(
8981
+ /* @__PURE__ */ jsx38("defs", { children: /* @__PURE__ */ jsx38(
8937
8982
  "marker",
8938
8983
  {
8939
8984
  id: markerId,
@@ -8942,10 +8987,10 @@ function DefaultTrackJump({
8942
8987
  refX: "9",
8943
8988
  refY: "3.5",
8944
8989
  orient: "auto",
8945
- children: /* @__PURE__ */ jsx36("polygon", { points: "0 0, 10 3.5, 0 7", fill: color })
8990
+ children: /* @__PURE__ */ jsx38("polygon", { points: "0 0, 10 3.5, 0 7", fill: color })
8946
8991
  }
8947
8992
  ) }),
8948
- /* @__PURE__ */ jsx36(
8993
+ /* @__PURE__ */ jsx38(
8949
8994
  "line",
8950
8995
  {
8951
8996
  x1: startX,
@@ -9009,7 +9054,7 @@ function TrackBoard({
9009
9054
  return nextSpaceIds.map((nextId) => {
9010
9055
  const targetSpace = spaceMap.get(nextId);
9011
9056
  if (!targetSpace) return null;
9012
- return /* @__PURE__ */ jsx36("g", { children: renderConnection(
9057
+ return /* @__PURE__ */ jsx38("g", { children: renderConnection(
9013
9058
  space.position,
9014
9059
  targetSpace.position,
9015
9060
  space,
@@ -9026,7 +9071,7 @@ function TrackBoard({
9026
9071
  if (!targetSpace) return [];
9027
9072
  const isUp = targetSpace.index > space.index;
9028
9073
  return [
9029
- /* @__PURE__ */ jsx36("g", { children: renderJump(
9074
+ /* @__PURE__ */ jsx38("g", { children: renderJump(
9030
9075
  space.position,
9031
9076
  targetSpace.position,
9032
9077
  space,
@@ -9059,11 +9104,11 @@ function TrackBoard({
9059
9104
  role: "img",
9060
9105
  "aria-label": "Track board",
9061
9106
  children: [
9062
- /* @__PURE__ */ jsx36("g", { className: "track-connections", children: renderConnections() }),
9063
- /* @__PURE__ */ jsx36("g", { className: "track-jumps", children: renderJumps() }),
9064
- /* @__PURE__ */ jsx36("g", { className: "track-spaces", role: "list", "aria-label": "Track spaces", children: spaces.map((space) => {
9107
+ /* @__PURE__ */ jsx38("g", { className: "track-connections", children: renderConnections() }),
9108
+ /* @__PURE__ */ jsx38("g", { className: "track-jumps", children: renderJumps() }),
9109
+ /* @__PURE__ */ jsx38("g", { className: "track-spaces", role: "list", "aria-label": "Track spaces", children: spaces.map((space) => {
9065
9110
  const spacePieces = piecesBySpace[space.id] || [];
9066
- return /* @__PURE__ */ jsx36(
9111
+ return /* @__PURE__ */ jsx38(
9067
9112
  "g",
9068
9113
  {
9069
9114
  transform: `translate(${space.position.x}, ${space.position.y})`,
@@ -9077,7 +9122,7 @@ function TrackBoard({
9077
9122
  {
9078
9123
  transform: `translate(${viewBoxX + 10}, ${viewBoxY + viewBoxHeight - 30})`,
9079
9124
  children: [
9080
- /* @__PURE__ */ jsx36(
9125
+ /* @__PURE__ */ jsx38(
9081
9126
  "rect",
9082
9127
  {
9083
9128
  x: 0,
@@ -9104,7 +9149,7 @@ function TrackBoard({
9104
9149
  import { useMemo as useMemo14 } from "react";
9105
9150
  import { clsx as clsx18 } from "clsx";
9106
9151
  import { Users, Lock, Gift, Coins } from "lucide-react";
9107
- import { jsx as jsx37, jsxs as jsxs23 } from "react/jsx-runtime";
9152
+ import { jsx as jsx39, jsxs as jsxs23 } from "react/jsx-runtime";
9108
9153
  var EMPTY_SLOT_OCCUPANTS = [];
9109
9154
  function DefaultSlotItem({
9110
9155
  name,
@@ -9152,7 +9197,7 @@ function DefaultSlotItem({
9152
9197
  children: [
9153
9198
  /* @__PURE__ */ jsxs23("div", { className: "flex items-start justify-between gap-2", children: [
9154
9199
  /* @__PURE__ */ jsxs23("div", { children: [
9155
- /* @__PURE__ */ jsx37(
9200
+ /* @__PURE__ */ jsx39(
9156
9201
  "h3",
9157
9202
  {
9158
9203
  className: "font-bold",
@@ -9160,7 +9205,7 @@ function DefaultSlotItem({
9160
9205
  children: name
9161
9206
  }
9162
9207
  ),
9163
- description && /* @__PURE__ */ jsx37(
9208
+ description && /* @__PURE__ */ jsx39(
9164
9209
  "p",
9165
9210
  {
9166
9211
  className: "text-xs mt-0.5",
@@ -9170,7 +9215,7 @@ function DefaultSlotItem({
9170
9215
  )
9171
9216
  ] }),
9172
9217
  /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-1", children: [
9173
- isExclusive && /* @__PURE__ */ jsx37(
9218
+ isExclusive && /* @__PURE__ */ jsx39(
9174
9219
  Lock,
9175
9220
  {
9176
9221
  className: "w-4 h-4",
@@ -9185,8 +9230,8 @@ function DefaultSlotItem({
9185
9230
  style: { color: theme.semantic.text.muted },
9186
9231
  title: `Capacity: ${capacity}`,
9187
9232
  children: [
9188
- /* @__PURE__ */ jsx37(Users, { className: "w-3 h-3" }),
9189
- /* @__PURE__ */ jsx37("span", { children: capacity })
9233
+ /* @__PURE__ */ jsx39(Users, { className: "w-3 h-3" }),
9234
+ /* @__PURE__ */ jsx39("span", { children: capacity })
9190
9235
  ]
9191
9236
  }
9192
9237
  )
@@ -9199,8 +9244,8 @@ function DefaultSlotItem({
9199
9244
  className: "flex items-center gap-1",
9200
9245
  style: { color: theme.semantic.intent.danger.solid },
9201
9246
  children: [
9202
- /* @__PURE__ */ jsx37(Coins, { className: "w-3 h-3", "aria-hidden": "true" }),
9203
- /* @__PURE__ */ jsx37("span", { children: costLabel })
9247
+ /* @__PURE__ */ jsx39(Coins, { className: "w-3 h-3", "aria-hidden": "true" }),
9248
+ /* @__PURE__ */ jsx39("span", { children: costLabel })
9204
9249
  ]
9205
9250
  }
9206
9251
  ),
@@ -9210,14 +9255,14 @@ function DefaultSlotItem({
9210
9255
  className: "flex items-center gap-1",
9211
9256
  style: { color: theme.semantic.intent.success.solid },
9212
9257
  children: [
9213
- /* @__PURE__ */ jsx37(Gift, { className: "w-3 h-3", "aria-hidden": "true" }),
9214
- /* @__PURE__ */ jsx37("span", { children: rewardLabel })
9258
+ /* @__PURE__ */ jsx39(Gift, { className: "w-3 h-3", "aria-hidden": "true" }),
9259
+ /* @__PURE__ */ jsx39("span", { children: rewardLabel })
9215
9260
  ]
9216
9261
  }
9217
9262
  )
9218
9263
  ] }),
9219
- renderOccupants && /* @__PURE__ */ jsx37("div", { className: "mt-2", children: renderOccupants() }),
9220
- !isAvailable && !isFull && /* @__PURE__ */ jsx37(
9264
+ renderOccupants && /* @__PURE__ */ jsx39("div", { className: "mt-2", children: renderOccupants() }),
9265
+ !isAvailable && !isFull && /* @__PURE__ */ jsx39(
9221
9266
  "div",
9222
9267
  {
9223
9268
  className: "mt-2 text-xs",
@@ -9237,7 +9282,7 @@ function DefaultSlotOccupant({
9237
9282
  onClick,
9238
9283
  className
9239
9284
  }) {
9240
- return /* @__PURE__ */ jsx37(
9285
+ return /* @__PURE__ */ jsx39(
9241
9286
  "div",
9242
9287
  {
9243
9288
  onClick,
@@ -9265,7 +9310,7 @@ function DefaultEmptySlot({
9265
9310
  className
9266
9311
  }) {
9267
9312
  const theme = useTheme();
9268
- return /* @__PURE__ */ jsx37(
9313
+ return /* @__PURE__ */ jsx39(
9269
9314
  "div",
9270
9315
  {
9271
9316
  className: clsx18("rounded-full border-2 border-dashed", className),
@@ -9320,18 +9365,18 @@ function SlotSystem({
9320
9365
  }, [slots, layout]);
9321
9366
  const renderSlotItem = (slot) => {
9322
9367
  const slotOccupants = occupantsBySlot[slot.id] ?? [];
9323
- return /* @__PURE__ */ jsx37("div", { role: "listitem", "aria-label": slot.name, children: renderSlot(slot, slotOccupants) }, slot.id);
9368
+ return /* @__PURE__ */ jsx39("div", { role: "listitem", "aria-label": slot.name, children: renderSlot(slot, slotOccupants) }, slot.id);
9324
9369
  };
9325
9370
  const responsiveGridStyle = {
9326
9371
  display: "grid",
9327
9372
  gridTemplateColumns: `repeat(auto-fit, minmax(${minSlotWidth}px, 1fr))`,
9328
9373
  gap: "1rem"
9329
9374
  };
9330
- const wrapContent = (content) => /* @__PURE__ */ jsx37("div", { style: { width, height }, className: clsx18("slot-system", className), children: content });
9375
+ const wrapContent = (content) => /* @__PURE__ */ jsx39("div", { style: { width, height }, className: clsx18("slot-system", className), children: content });
9331
9376
  if (layout === "grouped" && slotGroups) {
9332
9377
  return wrapContent(
9333
- /* @__PURE__ */ jsx37("div", { className: "space-y-6", role: "list", children: Object.entries(slotGroups).map(([groupName, groupSlots]) => /* @__PURE__ */ jsxs23("div", { children: [
9334
- /* @__PURE__ */ jsx37(
9378
+ /* @__PURE__ */ jsx39("div", { className: "space-y-6", role: "list", children: Object.entries(slotGroups).map(([groupName, groupSlots]) => /* @__PURE__ */ jsxs23("div", { children: [
9379
+ /* @__PURE__ */ jsx39(
9335
9380
  "h3",
9336
9381
  {
9337
9382
  className: "text-lg font-semibold mb-3",
@@ -9339,22 +9384,111 @@ function SlotSystem({
9339
9384
  children: groupName
9340
9385
  }
9341
9386
  ),
9342
- /* @__PURE__ */ jsx37("div", { style: responsiveGridStyle, children: groupSlots.map(renderSlotItem) })
9387
+ /* @__PURE__ */ jsx39("div", { style: responsiveGridStyle, children: groupSlots.map(renderSlotItem) })
9343
9388
  ] }, groupName)) })
9344
9389
  );
9345
9390
  }
9346
9391
  if (layout === "list") {
9347
9392
  return wrapContent(
9348
- /* @__PURE__ */ jsx37("div", { className: "flex flex-col gap-2", role: "list", children: slots.map(renderSlotItem) })
9393
+ /* @__PURE__ */ jsx39("div", { className: "flex flex-col gap-2", role: "list", children: slots.map(renderSlotItem) })
9349
9394
  );
9350
9395
  }
9351
9396
  return wrapContent(
9352
- /* @__PURE__ */ jsx37("div", { style: responsiveGridStyle, role: "list", children: slots.map(renderSlotItem) })
9397
+ /* @__PURE__ */ jsx39("div", { style: responsiveGridStyle, role: "list", children: slots.map(renderSlotItem) })
9353
9398
  );
9354
9399
  }
9355
9400
 
9356
9401
  // src/ui/components/board/SquareGrid.tsx
9357
- import { useMemo as useMemo15, useState as useState18 } from "react";
9402
+ import { useMemo as useMemo15 } from "react";
9403
+ import { clsx as clsx20 } from "clsx";
9404
+
9405
+ // src/ui/components/board/tiled-grid/use-grid-svg-frame.ts
9406
+ import {
9407
+ createElement as createElement2,
9408
+ useState as useState18
9409
+ } from "react";
9410
+ function useGridSvgFrame(options) {
9411
+ const { panZoomEnabled, initialZoom, minZoom, maxZoom, bounds, viewBoxMode } = options;
9412
+ const [hoveredSpaceId, setHoveredSpaceId] = useState18(null);
9413
+ const [hoveredEdgeId, setHoveredEdgeId] = useState18(null);
9414
+ const [hoveredVertexId, setHoveredVertexId] = useState18(null);
9415
+ const { transform, bind, isDragging } = usePanZoom({
9416
+ enabled: panZoomEnabled,
9417
+ initialZoom,
9418
+ minZoom,
9419
+ maxZoom,
9420
+ mode: "viewbox"
9421
+ });
9422
+ let viewBox;
9423
+ let viewBoxX;
9424
+ let viewBoxY;
9425
+ let viewBoxHeight;
9426
+ if (viewBoxMode === "transformed") {
9427
+ viewBox = calculateViewBox(bounds, transform);
9428
+ const viewBoxParts = viewBox.split(" ").map(Number);
9429
+ viewBoxX = viewBoxParts[0] ?? 0;
9430
+ viewBoxY = viewBoxParts[1] ?? 0;
9431
+ viewBoxHeight = viewBoxParts[3] ?? 0;
9432
+ } else {
9433
+ const totalWidth = bounds.width;
9434
+ const totalHeight = bounds.height;
9435
+ const viewBoxWidth = totalWidth / transform.zoom;
9436
+ viewBoxHeight = totalHeight / transform.zoom;
9437
+ viewBoxX = (totalWidth - viewBoxWidth) / 2 - transform.pan.x;
9438
+ viewBoxY = (totalHeight - viewBoxHeight) / 2 - transform.pan.y;
9439
+ viewBox = panZoomEnabled ? `${viewBoxX} ${viewBoxY} ${viewBoxWidth} ${viewBoxHeight}` : `0 0 ${totalWidth} ${totalHeight}`;
9440
+ }
9441
+ return {
9442
+ transform,
9443
+ bind,
9444
+ isDragging,
9445
+ viewBox,
9446
+ viewBoxX,
9447
+ viewBoxY,
9448
+ viewBoxHeight,
9449
+ spaceHover: {
9450
+ hoveredTargetId: hoveredSpaceId,
9451
+ setHoveredTargetId: setHoveredSpaceId
9452
+ },
9453
+ edgeHover: {
9454
+ hoveredTargetId: hoveredEdgeId,
9455
+ setHoveredTargetId: setHoveredEdgeId
9456
+ },
9457
+ vertexHover: {
9458
+ hoveredTargetId: hoveredVertexId,
9459
+ setHoveredTargetId: setHoveredVertexId
9460
+ }
9461
+ };
9462
+ }
9463
+ function GridZoomIndicator({
9464
+ viewBoxX,
9465
+ viewBoxY,
9466
+ viewBoxHeight,
9467
+ zoom
9468
+ }) {
9469
+ return createElement2(
9470
+ "g",
9471
+ {
9472
+ transform: `translate(${viewBoxX + 10}, ${viewBoxY + viewBoxHeight - 30})`
9473
+ },
9474
+ createElement2("rect", {
9475
+ x: 0,
9476
+ y: 0,
9477
+ width: 60,
9478
+ height: 20,
9479
+ rx: 4,
9480
+ fill: "rgba(0,0,0,0.6)"
9481
+ }),
9482
+ createElement2(
9483
+ "text",
9484
+ { x: 30, y: 14, textAnchor: "middle", fill: "white", fontSize: 12 },
9485
+ Math.round(zoom * 100),
9486
+ "%"
9487
+ )
9488
+ );
9489
+ }
9490
+
9491
+ // src/ui/components/board/tiled-grid/interactive-layer.tsx
9358
9492
  import { clsx as clsx19 } from "clsx";
9359
9493
 
9360
9494
  // src/ui/components/board/target-layer.ts
@@ -9377,12 +9511,102 @@ function interactiveTargetRenderState(layer, targetId, isHovered) {
9377
9511
  isHovered
9378
9512
  };
9379
9513
  }
9380
- function isInteractiveTargetSelectable(layer, state) {
9381
- return state.isEnabled && state.selectable && !!(state.select ?? layer.selectTargetId);
9514
+ function isInteractiveTargetSelectable(layer, state) {
9515
+ return state.isEnabled && state.selectable && !!(state.select ?? layer.selectTargetId);
9516
+ }
9517
+
9518
+ // src/ui/components/board/tiled-grid/interactive-layer.tsx
9519
+ import { jsx as jsx40 } from "react/jsx-runtime";
9520
+ function InteractiveTargetLayerGroup({
9521
+ layer,
9522
+ targets,
9523
+ getTargetId,
9524
+ targetKind,
9525
+ groupClassName,
9526
+ groupAriaLabel,
9527
+ groupRole,
9528
+ spreadBrowserAttributes,
9529
+ selectMode,
9530
+ hover,
9531
+ getTargetTransform,
9532
+ renderTargetContent
9533
+ }) {
9534
+ const { hoveredTargetId, setHoveredTargetId } = hover;
9535
+ return /* @__PURE__ */ jsx40("g", { className: groupClassName, role: groupRole, "aria-label": groupAriaLabel, children: targets.map((target) => {
9536
+ const targetId = getTargetId(target);
9537
+ const state = interactiveTargetRenderState(
9538
+ layer,
9539
+ targetId,
9540
+ hoveredTargetId === targetId
9541
+ );
9542
+ const isSelectable = isInteractiveTargetSelectable(layer, state);
9543
+ const activate = selectMode === "render-state" ? () => {
9544
+ void state.select?.();
9545
+ } : () => {
9546
+ void layer.selectTargetId?.(targetId);
9547
+ };
9548
+ return spreadBrowserAttributes ? (
9549
+ // HexGrid markup variant: browserAttributes spread first, then
9550
+ // transform, role, className (preserves HexGrid's rendered
9551
+ // attribute order).
9552
+ /* @__PURE__ */ jsx40(
9553
+ "g",
9554
+ {
9555
+ ...state.browserAttributes,
9556
+ ...getTargetTransform ? { transform: getTargetTransform(target) } : {},
9557
+ role: isSelectable ? "button" : void 0,
9558
+ className: clsx19(isSelectable && "cursor-pointer"),
9559
+ onPointerEnter: () => setHoveredTargetId(targetId),
9560
+ onPointerLeave: () => setHoveredTargetId(
9561
+ (currentId) => currentId === targetId ? null : currentId
9562
+ ),
9563
+ onClick: isSelectable ? activate : void 0,
9564
+ onKeyDown: (event) => handleKeyboardActivation(
9565
+ event,
9566
+ isSelectable ? activate : void 0
9567
+ ),
9568
+ tabIndex: isSelectable ? 0 : void 0,
9569
+ "aria-label": isSelectable ? `Select ${targetKind} ${targetId}` : void 0,
9570
+ children: renderTargetContent(target, state, isSelectable)
9571
+ },
9572
+ targetId
9573
+ )
9574
+ ) : (
9575
+ // SquareGrid markup variant: no browserAttributes spread;
9576
+ // transform, className, role (preserves SquareGrid's rendered
9577
+ // attribute order).
9578
+ /* @__PURE__ */ jsx40(
9579
+ "g",
9580
+ {
9581
+ ...getTargetTransform ? { transform: getTargetTransform(target) } : {},
9582
+ onClick: isSelectable ? activate : void 0,
9583
+ onKeyDown: (event) => handleKeyboardActivation(
9584
+ event,
9585
+ isSelectable ? activate : void 0
9586
+ ),
9587
+ onPointerEnter: () => setHoveredTargetId(targetId),
9588
+ onPointerLeave: () => setHoveredTargetId(
9589
+ (currentId) => currentId === targetId ? null : currentId
9590
+ ),
9591
+ className: clsx19(isSelectable && "cursor-pointer"),
9592
+ role: isSelectable ? "button" : void 0,
9593
+ tabIndex: isSelectable ? 0 : void 0,
9594
+ "aria-label": isSelectable ? `Select ${targetKind} ${targetId}` : void 0,
9595
+ children: renderTargetContent(target, state, isSelectable)
9596
+ },
9597
+ targetId
9598
+ )
9599
+ );
9600
+ }) });
9601
+ }
9602
+
9603
+ // src/ui/components/board/tiled-grid/resolve-board-prop.ts
9604
+ function resolveBoardProp(props, buildInlineBoard) {
9605
+ return "board" in props ? props.board : buildInlineBoard(props);
9382
9606
  }
9383
9607
 
9384
9608
  // src/ui/components/board/SquareGrid.tsx
9385
- import { jsx as jsx38, jsxs as jsxs24 } from "react/jsx-runtime";
9609
+ import { Fragment as Fragment6, jsx as jsx41, jsxs as jsxs24 } from "react/jsx-runtime";
9386
9610
  function DefaultGridCell({
9387
9611
  size,
9388
9612
  isLight = true,
@@ -9407,7 +9631,7 @@ function DefaultGridCell({
9407
9631
  onPointerEnter,
9408
9632
  onPointerLeave,
9409
9633
  onKeyDown: (event) => handleKeyboardActivation(event, onClick),
9410
- className: clsx19(
9634
+ className: clsx20(
9411
9635
  "transition-colors duration-100",
9412
9636
  onClick && "cursor-pointer",
9413
9637
  className
@@ -9416,8 +9640,8 @@ function DefaultGridCell({
9416
9640
  tabIndex: onClick ? 0 : void 0,
9417
9641
  "aria-label": onClick ? "Grid cell" : void 0,
9418
9642
  children: [
9419
- /* @__PURE__ */ jsx38("rect", { width: size, height: size, fill: baseColor }),
9420
- isSelected && /* @__PURE__ */ jsx38(
9643
+ /* @__PURE__ */ jsx41("rect", { width: size, height: size, fill: baseColor }),
9644
+ isSelected && /* @__PURE__ */ jsx41(
9421
9645
  "rect",
9422
9646
  {
9423
9647
  width: size,
@@ -9426,7 +9650,7 @@ function DefaultGridCell({
9426
9650
  pointerEvents: "none"
9427
9651
  }
9428
9652
  ),
9429
- isHighlighted && !isSelected && /* @__PURE__ */ jsx38(
9653
+ isHighlighted && !isSelected && /* @__PURE__ */ jsx41(
9430
9654
  "rect",
9431
9655
  {
9432
9656
  width: size,
@@ -9435,7 +9659,7 @@ function DefaultGridCell({
9435
9659
  pointerEvents: "none"
9436
9660
  }
9437
9661
  ),
9438
- isValidMove && !isCapture && /* @__PURE__ */ jsx38(
9662
+ isValidMove && !isCapture && /* @__PURE__ */ jsx41(
9439
9663
  "circle",
9440
9664
  {
9441
9665
  cx: size / 2,
@@ -9445,7 +9669,7 @@ function DefaultGridCell({
9445
9669
  pointerEvents: "none"
9446
9670
  }
9447
9671
  ),
9448
- isCapture && /* @__PURE__ */ jsx38(
9672
+ isCapture && /* @__PURE__ */ jsx41(
9449
9673
  "circle",
9450
9674
  {
9451
9675
  cx: size / 2,
@@ -9479,7 +9703,7 @@ function DefaultGridPiece({
9479
9703
  onClick,
9480
9704
  onPointerDown,
9481
9705
  onKeyDown: (event) => handleKeyboardActivation(event, onClick),
9482
- className: clsx19(
9706
+ className: clsx20(
9483
9707
  "transition-transform duration-150",
9484
9708
  (onClick || onPointerDown) && "cursor-pointer hover:scale-105",
9485
9709
  className
@@ -9489,7 +9713,7 @@ function DefaultGridPiece({
9489
9713
  tabIndex: onClick ? 0 : void 0,
9490
9714
  "aria-label": onClick ? label ?? "Grid piece" : void 0,
9491
9715
  children: [
9492
- /* @__PURE__ */ jsx38(
9716
+ /* @__PURE__ */ jsx41(
9493
9717
  "circle",
9494
9718
  {
9495
9719
  r: isDragging ? radius * 1.1 : radius,
@@ -9499,7 +9723,7 @@ function DefaultGridPiece({
9499
9723
  style: { filter: "drop-shadow(1px 2px 2px rgba(0,0,0,0.4))" }
9500
9724
  }
9501
9725
  ),
9502
- label && /* @__PURE__ */ jsx38(
9726
+ label && /* @__PURE__ */ jsx41(
9503
9727
  "text",
9504
9728
  {
9505
9729
  y: 4,
@@ -9544,20 +9768,20 @@ function DefaultChessPiece({
9544
9768
  const symbol = CHESS_SYMBOLS[owner]?.[type] ?? "?";
9545
9769
  const textColor = owner === "white" ? "#f8fafc" : "#1e293b";
9546
9770
  const shadowFilter = owner === "white" ? "drop-shadow(1px 1px 1px rgba(0,0,0,0.5))" : "drop-shadow(1px 1px 1px rgba(255,255,255,0.3))";
9547
- return /* @__PURE__ */ jsx38(
9771
+ return /* @__PURE__ */ jsx41(
9548
9772
  "g",
9549
9773
  {
9550
9774
  onClick,
9551
9775
  onPointerDown,
9552
9776
  onKeyDown: (event) => handleKeyboardActivation(event, onClick),
9553
- className: clsx19(
9777
+ className: clsx20(
9554
9778
  (onClick || onPointerDown) && "cursor-pointer",
9555
9779
  className
9556
9780
  ),
9557
9781
  role: onClick ? "button" : void 0,
9558
9782
  tabIndex: onClick ? 0 : void 0,
9559
9783
  "aria-label": onClick ? `${owner} ${type}` : void 0,
9560
- children: /* @__PURE__ */ jsx38(
9784
+ children: /* @__PURE__ */ jsx41(
9561
9785
  "text",
9562
9786
  {
9563
9787
  textAnchor: "middle",
@@ -9684,35 +9908,24 @@ function SquareGridImpl(props) {
9684
9908
  renderInteractiveEdge,
9685
9909
  renderInteractiveVertex
9686
9910
  } = props;
9687
- const board = "board" in props ? props.board : "spaces" in props ? {
9688
- id: "__square-grid__",
9689
- spaces: props.spaces,
9690
- pieces: props.pieces ?? [],
9691
- edges: props.edges ?? [],
9692
- vertices: props.vertices ?? []
9693
- } : {
9694
- id: "__square-grid__",
9695
- rows: props.rows ?? 0,
9696
- cols: props.cols ?? 0,
9697
- cells: props.cells,
9698
- pieces: props.pieces ?? [],
9699
- edges: props.edges ?? [],
9700
- vertices: props.vertices ?? []
9701
- };
9702
- const [hoveredInteractiveSpaceId, setHoveredInteractiveSpaceId] = useState18(null);
9703
- const [hoveredInteractiveEdgeId, setHoveredInteractiveEdgeId] = useState18(null);
9704
- const [hoveredInteractiveVertexId, setHoveredInteractiveVertexId] = useState18(null);
9705
- const {
9706
- transform,
9707
- bind,
9708
- isDragging: isPanning
9709
- } = usePanZoom({
9710
- enabled: enablePanZoom,
9711
- initialZoom,
9712
- minZoom,
9713
- maxZoom,
9714
- mode: "viewbox"
9715
- });
9911
+ const board = resolveBoardProp(
9912
+ props,
9913
+ (inlineProps) => "spaces" in inlineProps ? {
9914
+ id: "__square-grid__",
9915
+ spaces: inlineProps.spaces,
9916
+ pieces: inlineProps.pieces ?? [],
9917
+ edges: inlineProps.edges ?? [],
9918
+ vertices: inlineProps.vertices ?? []
9919
+ } : {
9920
+ id: "__square-grid__",
9921
+ rows: inlineProps.rows ?? 0,
9922
+ cols: inlineProps.cols ?? 0,
9923
+ cells: inlineProps.cells,
9924
+ pieces: inlineProps.pieces ?? [],
9925
+ edges: inlineProps.edges ?? [],
9926
+ vertices: inlineProps.vertices ?? []
9927
+ }
9928
+ );
9716
9929
  const labelMargin = showCoordinates && coordinateStyle !== "none" ? 24 : 0;
9717
9930
  const normalizedBoard = useMemo15(
9718
9931
  () => normalizeSquareBoardInput(board),
@@ -9804,19 +10017,34 @@ function SquareGridImpl(props) {
9804
10017
  }),
9805
10018
  [cellSize, cellsById, labelMargin, resolvedVertices]
9806
10019
  );
9807
- const viewBoxWidth = totalWidth / transform.zoom;
9808
- const viewBoxHeight = totalHeight / transform.zoom;
9809
- const viewBoxX = (totalWidth - viewBoxWidth) / 2 - transform.pan.x;
9810
- const viewBoxY = (totalHeight - viewBoxHeight) / 2 - transform.pan.y;
9811
10020
  const svgWidth = width ?? totalWidth;
9812
10021
  const svgHeight = height ?? totalHeight;
10022
+ const {
10023
+ transform,
10024
+ bind,
10025
+ isDragging: isPanning,
10026
+ viewBox,
10027
+ viewBoxX,
10028
+ viewBoxY,
10029
+ viewBoxHeight,
10030
+ spaceHover,
10031
+ edgeHover,
10032
+ vertexHover
10033
+ } = useGridSvgFrame({
10034
+ panZoomEnabled: enablePanZoom,
10035
+ initialZoom,
10036
+ minZoom,
10037
+ maxZoom,
10038
+ bounds: { minX: 0, minY: 0, width: totalWidth, height: totalHeight },
10039
+ viewBoxMode: "static-when-disabled"
10040
+ });
9813
10041
  return /* @__PURE__ */ jsxs24(
9814
10042
  "svg",
9815
10043
  {
9816
10044
  width: svgWidth,
9817
10045
  height: svgHeight,
9818
- viewBox: enablePanZoom ? `${viewBoxX} ${viewBoxY} ${viewBoxWidth} ${viewBoxHeight}` : `0 0 ${totalWidth} ${totalHeight}`,
9819
- className: clsx19(
10046
+ viewBox,
10047
+ className: clsx20(
9820
10048
  "square-grid",
9821
10049
  enablePanZoom && "touch-none",
9822
10050
  isPanning && "cursor-grabbing",
@@ -9827,11 +10055,11 @@ function SquareGridImpl(props) {
9827
10055
  role: "img",
9828
10056
  "aria-label": `${rows}x${cols} game grid`,
9829
10057
  children: [
9830
- /* @__PURE__ */ jsx38("defs", { children: /* @__PURE__ */ jsx38("filter", { id: "pieceShadow", x: "-20%", y: "-20%", width: "140%", height: "140%", children: /* @__PURE__ */ jsx38("feDropShadow", { dx: "1", dy: "2", stdDeviation: "2", floodOpacity: "0.4" }) }) }),
9831
- /* @__PURE__ */ jsx38("g", { className: "cells", role: "list", "aria-label": "Grid cells", children: renderableCells.map(({ row, col }) => {
10058
+ /* @__PURE__ */ jsx41("defs", { children: /* @__PURE__ */ jsx41("filter", { id: "pieceShadow", x: "-20%", y: "-20%", width: "140%", height: "140%", children: /* @__PURE__ */ jsx41("feDropShadow", { dx: "1", dy: "2", stdDeviation: "2", floodOpacity: "0.4" }) }) }),
10059
+ /* @__PURE__ */ jsx41("g", { className: "cells", role: "list", "aria-label": "Grid cells", children: renderableCells.map(({ row, col }) => {
9832
10060
  const x = labelMargin + col * cellSize;
9833
10061
  const y = row * cellSize;
9834
- return /* @__PURE__ */ jsx38(
10062
+ return /* @__PURE__ */ jsx41(
9835
10063
  "g",
9836
10064
  {
9837
10065
  transform: `translate(${x}, ${y})`,
@@ -9842,153 +10070,91 @@ function SquareGridImpl(props) {
9842
10070
  `${row}-${col}`
9843
10071
  );
9844
10072
  }) }),
9845
- interactiveSpaces && /* @__PURE__ */ jsx38("g", { className: "interactive-spaces", "aria-label": "Interactive spaces", children: resolvedCells.map((space) => {
9846
- const state = interactiveTargetRenderState(
9847
- interactiveSpaces,
9848
- space.id,
9849
- hoveredInteractiveSpaceId === space.id
9850
- );
9851
- const isSelectable = isInteractiveTargetSelectable(
9852
- interactiveSpaces,
9853
- state
9854
- );
9855
- const x = labelMargin + space.col * cellSize;
9856
- const y = space.row * cellSize;
9857
- return /* @__PURE__ */ jsxs24(
9858
- "g",
9859
- {
9860
- transform: `translate(${x}, ${y})`,
9861
- onClick: isSelectable ? () => {
9862
- void interactiveSpaces.selectTargetId?.(space.id);
9863
- } : void 0,
9864
- onKeyDown: (event) => handleKeyboardActivation(
9865
- event,
9866
- isSelectable ? () => {
9867
- void interactiveSpaces.selectTargetId?.(space.id);
9868
- } : void 0
9869
- ),
9870
- onPointerEnter: () => setHoveredInteractiveSpaceId(space.id),
9871
- onPointerLeave: () => setHoveredInteractiveSpaceId(
9872
- (currentId) => currentId === space.id ? null : currentId
9873
- ),
9874
- className: clsx19(isSelectable && "cursor-pointer"),
9875
- role: isSelectable ? "button" : void 0,
9876
- tabIndex: isSelectable ? 0 : void 0,
9877
- "aria-label": isSelectable ? `Select space ${space.id}` : void 0,
9878
- children: [
9879
- isSelectable && /* @__PURE__ */ jsx38(
9880
- "rect",
9881
- {
9882
- x: 0,
9883
- y: 0,
9884
- width: cellSize,
9885
- height: cellSize,
9886
- fill: "rgba(255,255,255,0.001)",
9887
- pointerEvents: "all"
9888
- }
9889
- ),
9890
- renderInteractiveSpace ? renderInteractiveSpace(space, state) : null
9891
- ]
9892
- },
9893
- space.id
9894
- );
9895
- }) }),
9896
- renderEdge && resolvedEdgePositions.length > 0 && /* @__PURE__ */ jsx38("g", { className: "edges", "aria-label": "Board edges", children: resolvedEdgePositions.map(({ edge, interactiveEdge }) => /* @__PURE__ */ jsx38("g", { children: renderEdge(edge, interactiveEdge.position) }, edge.id)) }),
9897
- interactiveEdges && /* @__PURE__ */ jsx38("g", { className: "interactive-edges", "aria-label": "Interactive edges", children: resolvedEdgePositions.map(({ interactiveEdge: edge }) => {
9898
- const state = interactiveTargetRenderState(
9899
- interactiveEdges,
9900
- edge.id,
9901
- hoveredInteractiveEdgeId === edge.id
9902
- );
9903
- const isSelectable = isInteractiveTargetSelectable(
9904
- interactiveEdges,
9905
- state
9906
- );
9907
- return /* @__PURE__ */ jsx38(
9908
- "g",
9909
- {
9910
- onClick: isSelectable ? () => {
9911
- void interactiveEdges.selectTargetId?.(edge.id);
9912
- } : void 0,
9913
- onKeyDown: (event) => handleKeyboardActivation(
9914
- event,
9915
- isSelectable ? () => {
9916
- void interactiveEdges.selectTargetId?.(edge.id);
9917
- } : void 0
9918
- ),
9919
- onPointerEnter: () => setHoveredInteractiveEdgeId(edge.id),
9920
- onPointerLeave: () => setHoveredInteractiveEdgeId(
9921
- (currentId) => currentId === edge.id ? null : currentId
9922
- ),
9923
- className: clsx19(isSelectable && "cursor-pointer"),
9924
- role: isSelectable ? "button" : void 0,
9925
- tabIndex: isSelectable ? 0 : void 0,
9926
- "aria-label": isSelectable ? `Select edge ${edge.id}` : void 0,
9927
- children: renderInteractiveEdge ? renderInteractiveEdge(edge, edge.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx38(
9928
- "line",
9929
- {
9930
- x1: edge.position.x1,
9931
- y1: edge.position.y1,
9932
- x2: edge.position.x2,
9933
- y2: edge.position.y2,
9934
- stroke: "rgba(255,255,255,0.001)",
9935
- strokeWidth: Math.max(12, cellSize * 0.18),
9936
- pointerEvents: "stroke"
9937
- }
9938
- ) : null
9939
- },
9940
- edge.id
9941
- );
9942
- }) }),
9943
- renderVertex && resolvedVertexPositions.length > 0 && /* @__PURE__ */ jsx38("g", { className: "vertices", "aria-label": "Board vertices", children: resolvedVertexPositions.map(({ vertex, interactiveVertex }) => /* @__PURE__ */ jsx38("g", { children: renderVertex(vertex, interactiveVertex.position) }, vertex.id)) }),
9944
- interactiveVertices && /* @__PURE__ */ jsx38("g", { className: "interactive-vertices", "aria-label": "Interactive vertices", children: resolvedVertexPositions.map(({ interactiveVertex: vertex }) => {
9945
- const state = interactiveTargetRenderState(
9946
- interactiveVertices,
9947
- vertex.id,
9948
- hoveredInteractiveVertexId === vertex.id
9949
- );
9950
- const isSelectable = isInteractiveTargetSelectable(
9951
- interactiveVertices,
9952
- state
9953
- );
9954
- return /* @__PURE__ */ jsx38(
9955
- "g",
9956
- {
9957
- onClick: isSelectable ? () => {
9958
- void interactiveVertices.selectTargetId?.(vertex.id);
9959
- } : void 0,
9960
- onKeyDown: (event) => handleKeyboardActivation(
9961
- event,
9962
- isSelectable ? () => {
9963
- void interactiveVertices.selectTargetId?.(vertex.id);
9964
- } : void 0
9965
- ),
9966
- onPointerEnter: () => setHoveredInteractiveVertexId(vertex.id),
9967
- onPointerLeave: () => setHoveredInteractiveVertexId(
9968
- (currentId) => currentId === vertex.id ? null : currentId
9969
- ),
9970
- className: clsx19(isSelectable && "cursor-pointer"),
9971
- role: isSelectable ? "button" : void 0,
9972
- tabIndex: isSelectable ? 0 : void 0,
9973
- "aria-label": isSelectable ? `Select vertex ${vertex.id}` : void 0,
9974
- children: renderInteractiveVertex ? renderInteractiveVertex(vertex, vertex.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx38(
9975
- "circle",
10073
+ interactiveSpaces && /* @__PURE__ */ jsx41(
10074
+ InteractiveTargetLayerGroup,
10075
+ {
10076
+ layer: interactiveSpaces,
10077
+ targets: resolvedCells,
10078
+ getTargetId: (space) => space.id,
10079
+ targetKind: "space",
10080
+ groupClassName: "interactive-spaces",
10081
+ groupAriaLabel: "Interactive spaces",
10082
+ spreadBrowserAttributes: false,
10083
+ selectMode: "layer-direct",
10084
+ hover: spaceHover,
10085
+ getTargetTransform: (space) => `translate(${labelMargin + space.col * cellSize}, ${space.row * cellSize})`,
10086
+ renderTargetContent: (space, state, isSelectable) => /* @__PURE__ */ jsxs24(Fragment6, { children: [
10087
+ isSelectable && /* @__PURE__ */ jsx41(
10088
+ "rect",
9976
10089
  {
9977
- cx: vertex.position.x,
9978
- cy: vertex.position.y,
9979
- r: Math.max(8, cellSize * 0.12),
10090
+ x: 0,
10091
+ y: 0,
10092
+ width: cellSize,
10093
+ height: cellSize,
9980
10094
  fill: "rgba(255,255,255,0.001)",
9981
10095
  pointerEvents: "all"
9982
10096
  }
9983
- ) : null
9984
- },
9985
- vertex.id
9986
- );
9987
- }) }),
10097
+ ),
10098
+ renderInteractiveSpace ? renderInteractiveSpace(space, state) : null
10099
+ ] })
10100
+ }
10101
+ ),
10102
+ renderEdge && resolvedEdgePositions.length > 0 && /* @__PURE__ */ jsx41("g", { className: "edges", "aria-label": "Board edges", children: resolvedEdgePositions.map(({ edge, interactiveEdge }) => /* @__PURE__ */ jsx41("g", { children: renderEdge(edge, interactiveEdge.position) }, edge.id)) }),
10103
+ interactiveEdges && /* @__PURE__ */ jsx41(
10104
+ InteractiveTargetLayerGroup,
10105
+ {
10106
+ layer: interactiveEdges,
10107
+ targets: resolvedEdgePositions,
10108
+ getTargetId: ({ interactiveEdge }) => interactiveEdge.id,
10109
+ targetKind: "edge",
10110
+ groupClassName: "interactive-edges",
10111
+ groupAriaLabel: "Interactive edges",
10112
+ spreadBrowserAttributes: false,
10113
+ selectMode: "layer-direct",
10114
+ hover: edgeHover,
10115
+ renderTargetContent: ({ interactiveEdge: edge }, state) => renderInteractiveEdge ? renderInteractiveEdge(edge, edge.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx41(
10116
+ "line",
10117
+ {
10118
+ x1: edge.position.x1,
10119
+ y1: edge.position.y1,
10120
+ x2: edge.position.x2,
10121
+ y2: edge.position.y2,
10122
+ stroke: "rgba(255,255,255,0.001)",
10123
+ strokeWidth: Math.max(12, cellSize * 0.18),
10124
+ pointerEvents: "stroke"
10125
+ }
10126
+ ) : null
10127
+ }
10128
+ ),
10129
+ renderVertex && resolvedVertexPositions.length > 0 && /* @__PURE__ */ jsx41("g", { className: "vertices", "aria-label": "Board vertices", children: resolvedVertexPositions.map(({ vertex, interactiveVertex }) => /* @__PURE__ */ jsx41("g", { children: renderVertex(vertex, interactiveVertex.position) }, vertex.id)) }),
10130
+ interactiveVertices && /* @__PURE__ */ jsx41(
10131
+ InteractiveTargetLayerGroup,
10132
+ {
10133
+ layer: interactiveVertices,
10134
+ targets: resolvedVertexPositions,
10135
+ getTargetId: ({ interactiveVertex }) => interactiveVertex.id,
10136
+ targetKind: "vertex",
10137
+ groupClassName: "interactive-vertices",
10138
+ groupAriaLabel: "Interactive vertices",
10139
+ spreadBrowserAttributes: false,
10140
+ selectMode: "layer-direct",
10141
+ hover: vertexHover,
10142
+ renderTargetContent: ({ interactiveVertex: vertex }, state) => renderInteractiveVertex ? renderInteractiveVertex(vertex, vertex.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx41(
10143
+ "circle",
10144
+ {
10145
+ cx: vertex.position.x,
10146
+ cy: vertex.position.y,
10147
+ r: Math.max(8, cellSize * 0.12),
10148
+ fill: "rgba(255,255,255,0.001)",
10149
+ pointerEvents: "all"
10150
+ }
10151
+ ) : null
10152
+ }
10153
+ ),
9988
10154
  showCoordinates && coordinateStyle !== "none" && /* @__PURE__ */ jsxs24("g", { className: "coordinates", "aria-hidden": "true", children: [
9989
10155
  Array.from({ length: cols }).map((_, col) => {
9990
10156
  const label = coordinateStyle === "algebraic" ? String.fromCharCode(97 + col) : String(col + 1);
9991
- return /* @__PURE__ */ jsx38(
10157
+ return /* @__PURE__ */ jsx41(
9992
10158
  "text",
9993
10159
  {
9994
10160
  x: labelMargin + col * cellSize + cellSize / 2,
@@ -10004,7 +10170,7 @@ function SquareGridImpl(props) {
10004
10170
  }),
10005
10171
  Array.from({ length: rows }).map((_, row) => {
10006
10172
  const label = coordinateStyle === "algebraic" ? String(rows - row) : String(row + 1);
10007
- return /* @__PURE__ */ jsx38(
10173
+ return /* @__PURE__ */ jsx41(
10008
10174
  "text",
10009
10175
  {
10010
10176
  x: 10,
@@ -10019,10 +10185,10 @@ function SquareGridImpl(props) {
10019
10185
  );
10020
10186
  })
10021
10187
  ] }),
10022
- /* @__PURE__ */ jsx38("g", { className: "pieces", role: "list", "aria-label": "Game pieces", children: resolvedPieces.map((piece) => {
10188
+ /* @__PURE__ */ jsx41("g", { className: "pieces", role: "list", "aria-label": "Game pieces", children: resolvedPieces.map((piece) => {
10023
10189
  const x = labelMargin + piece.col * cellSize + cellSize / 2;
10024
10190
  const y = piece.row * cellSize + cellSize / 2;
10025
- return /* @__PURE__ */ jsx38(
10191
+ return /* @__PURE__ */ jsx41(
10026
10192
  "g",
10027
10193
  {
10028
10194
  transform: `translate(${x}, ${y})`,
@@ -10033,27 +10199,13 @@ function SquareGridImpl(props) {
10033
10199
  piece.id
10034
10200
  );
10035
10201
  }) }),
10036
- enablePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsxs24(
10037
- "g",
10202
+ enablePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsx41(
10203
+ GridZoomIndicator,
10038
10204
  {
10039
- transform: `translate(${viewBoxX + 10}, ${viewBoxY + viewBoxHeight - 30})`,
10040
- children: [
10041
- /* @__PURE__ */ jsx38(
10042
- "rect",
10043
- {
10044
- x: 0,
10045
- y: 0,
10046
- width: 60,
10047
- height: 20,
10048
- rx: 4,
10049
- fill: "rgba(0,0,0,0.6)"
10050
- }
10051
- ),
10052
- /* @__PURE__ */ jsxs24("text", { x: 30, y: 14, textAnchor: "middle", fill: "white", fontSize: 12, children: [
10053
- Math.round(transform.zoom * 100),
10054
- "%"
10055
- ] })
10056
- ]
10205
+ viewBoxX,
10206
+ viewBoxY,
10207
+ viewBoxHeight,
10208
+ zoom: transform.zoom
10057
10209
  }
10058
10210
  )
10059
10211
  ]
@@ -10063,9 +10215,9 @@ function SquareGridImpl(props) {
10063
10215
  var SquareGrid = SquareGridImpl;
10064
10216
 
10065
10217
  // src/ui/components/board/HexGrid.tsx
10066
- import { useMemo as useMemo16, useState as useState19 } from "react";
10067
- import { clsx as clsx20 } from "clsx";
10068
- import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
10218
+ import { useMemo as useMemo16 } from "react";
10219
+ import { clsx as clsx21 } from "clsx";
10220
+ import { Fragment as Fragment7, jsx as jsx42, jsxs as jsxs25 } from "react/jsx-runtime";
10069
10221
  function DefaultHexTile({
10070
10222
  size,
10071
10223
  fill,
@@ -10093,7 +10245,7 @@ function DefaultHexTile({
10093
10245
  onPointerEnter,
10094
10246
  onPointerLeave,
10095
10247
  onKeyDown: (event) => handleKeyboardActivation(event, onClick),
10096
- className: clsx20(
10248
+ className: clsx21(
10097
10249
  "transition-all duration-150",
10098
10250
  onClick && "cursor-pointer hover:brightness-110",
10099
10251
  className
@@ -10102,7 +10254,7 @@ function DefaultHexTile({
10102
10254
  tabIndex: onClick ? 0 : void 0,
10103
10255
  "aria-label": onClick ? label ?? "Hex tile" : void 0,
10104
10256
  children: [
10105
- /* @__PURE__ */ jsx39(
10257
+ /* @__PURE__ */ jsx42(
10106
10258
  "polygon",
10107
10259
  {
10108
10260
  points,
@@ -10112,7 +10264,7 @@ function DefaultHexTile({
10112
10264
  filter: "url(#hexShadow)"
10113
10265
  }
10114
10266
  ),
10115
- label && /* @__PURE__ */ jsx39(
10267
+ label && /* @__PURE__ */ jsx42(
10116
10268
  "text",
10117
10269
  {
10118
10270
  x: 0,
@@ -10166,7 +10318,7 @@ function DefaultHexEdge({
10166
10318
  {
10167
10319
  onClick,
10168
10320
  onKeyDown: (event) => handleKeyboardActivation(event, onClick),
10169
- className: clsx20(
10321
+ className: clsx21(
10170
10322
  "transition-all duration-150",
10171
10323
  onClick && "cursor-pointer",
10172
10324
  className
@@ -10175,7 +10327,7 @@ function DefaultHexEdge({
10175
10327
  tabIndex: onClick ? 0 : void 0,
10176
10328
  "aria-label": onClick ? "Hex edge" : void 0,
10177
10329
  children: [
10178
- /* @__PURE__ */ jsx39(
10330
+ /* @__PURE__ */ jsx42(
10179
10331
  "rect",
10180
10332
  {
10181
10333
  x: position.midX - touchTargetLength / 2,
@@ -10188,7 +10340,7 @@ function DefaultHexEdge({
10188
10340
  pointerEvents: "all"
10189
10341
  }
10190
10342
  ),
10191
- /* @__PURE__ */ jsx39(
10343
+ /* @__PURE__ */ jsx42(
10192
10344
  "line",
10193
10345
  {
10194
10346
  x1: position.x1,
@@ -10231,7 +10383,7 @@ function DefaultHexVertex({
10231
10383
  onPointerEnter,
10232
10384
  onPointerLeave,
10233
10385
  onKeyDown: (event) => handleKeyboardActivation(event, onClick),
10234
- className: clsx20(
10386
+ className: clsx21(
10235
10387
  "transition-all duration-150",
10236
10388
  onClick && "cursor-pointer hover:scale-110",
10237
10389
  className
@@ -10241,7 +10393,7 @@ function DefaultHexVertex({
10241
10393
  tabIndex: onClick ? 0 : void 0,
10242
10394
  "aria-label": onClick ? "Hex vertex" : void 0,
10243
10395
  children: [
10244
- /* @__PURE__ */ jsx39(
10396
+ /* @__PURE__ */ jsx42(
10245
10397
  "circle",
10246
10398
  {
10247
10399
  cx: position.x,
@@ -10251,7 +10403,7 @@ function DefaultHexVertex({
10251
10403
  pointerEvents: "all"
10252
10404
  }
10253
10405
  ),
10254
- shape === "square" ? /* @__PURE__ */ jsx39(
10406
+ shape === "square" ? /* @__PURE__ */ jsx42(
10255
10407
  "rect",
10256
10408
  {
10257
10409
  x: position.x - size,
@@ -10263,7 +10415,7 @@ function DefaultHexVertex({
10263
10415
  strokeWidth: effectiveStrokeWidth,
10264
10416
  className: hasOwner ? "" : "opacity-30"
10265
10417
  }
10266
- ) : /* @__PURE__ */ jsx39(
10418
+ ) : /* @__PURE__ */ jsx42(
10267
10419
  "circle",
10268
10420
  {
10269
10421
  cx: position.x,
@@ -10287,7 +10439,7 @@ function DefaultInteractiveVertex({
10287
10439
  hoverColor = "rgba(34, 197, 94, 0.8)",
10288
10440
  className
10289
10441
  }) {
10290
- return /* @__PURE__ */ jsx39(
10442
+ return /* @__PURE__ */ jsx42(
10291
10443
  "circle",
10292
10444
  {
10293
10445
  cx: position.x,
@@ -10296,7 +10448,7 @@ function DefaultInteractiveVertex({
10296
10448
  fill: isHovered ? hoverColor : color,
10297
10449
  stroke: isHovered ? "#22c55e" : "rgba(255,255,255,0.4)",
10298
10450
  strokeWidth: isHovered ? 2 : 1,
10299
- className: clsx20("transition-all duration-150", className)
10451
+ className: clsx21("transition-all duration-150", className)
10300
10452
  }
10301
10453
  );
10302
10454
  }
@@ -10308,7 +10460,7 @@ function DefaultInteractiveEdge({
10308
10460
  hoverColor = "rgba(251, 146, 60, 0.8)",
10309
10461
  className
10310
10462
  }) {
10311
- return /* @__PURE__ */ jsx39(
10463
+ return /* @__PURE__ */ jsx42(
10312
10464
  "line",
10313
10465
  {
10314
10466
  x1: position.x1,
@@ -10318,7 +10470,7 @@ function DefaultInteractiveEdge({
10318
10470
  stroke: isHovered ? hoverColor : color,
10319
10471
  strokeWidth: isHovered ? strokeWidth * 1.5 : strokeWidth,
10320
10472
  strokeLinecap: "round",
10321
- className: clsx20("transition-all duration-150", className)
10473
+ className: clsx21("transition-all duration-150", className)
10322
10474
  }
10323
10475
  );
10324
10476
  }
@@ -10417,19 +10569,22 @@ function HexGridImpl(props) {
10417
10569
  interactiveVertexSize = 12,
10418
10570
  interactiveEdgeSize = 10
10419
10571
  } = props;
10420
- const board = "board" in props ? props.board : "spaces" in props ? {
10421
- id: "__hex-grid__",
10422
- orientation,
10423
- spaces: props.spaces,
10424
- edges: props.edges ?? [],
10425
- vertices: props.vertices ?? []
10426
- } : {
10427
- id: "__hex-grid__",
10428
- orientation,
10429
- tiles: props.tiles,
10430
- edges: props.edges ?? [],
10431
- vertices: props.vertices ?? []
10432
- };
10572
+ const board = resolveBoardProp(
10573
+ props,
10574
+ (inlineProps) => "spaces" in inlineProps ? {
10575
+ id: "__hex-grid__",
10576
+ orientation,
10577
+ spaces: inlineProps.spaces,
10578
+ edges: inlineProps.edges ?? [],
10579
+ vertices: inlineProps.vertices ?? []
10580
+ } : {
10581
+ id: "__hex-grid__",
10582
+ orientation,
10583
+ tiles: inlineProps.tiles,
10584
+ edges: inlineProps.edges ?? [],
10585
+ vertices: inlineProps.vertices ?? []
10586
+ }
10587
+ );
10433
10588
  const isMobile = useIsMobile();
10434
10589
  const effectivePanZoom = enablePanZoom && isMobile;
10435
10590
  const normalizedBoard = useMemo16(
@@ -10440,16 +10595,6 @@ function HexGridImpl(props) {
10440
10595
  const resolvedEdges = normalizedBoard.edges;
10441
10596
  const resolvedVertices = normalizedBoard.vertices;
10442
10597
  const resolvedOrientation = normalizedBoard.orientation ?? orientation;
10443
- const [hoveredSpaceId, setHoveredSpaceId] = useState19(null);
10444
- const [hoveredVertexId, setHoveredVertexId] = useState19(null);
10445
- const [hoveredEdgeId, setHoveredEdgeId] = useState19(null);
10446
- const { transform, bind, isDragging } = usePanZoom({
10447
- enabled: effectivePanZoom,
10448
- initialZoom,
10449
- minZoom,
10450
- maxZoom,
10451
- mode: "viewbox"
10452
- });
10453
10598
  const tilePositions = useMemo16(() => {
10454
10599
  const positions = /* @__PURE__ */ new Map();
10455
10600
  resolvedTiles.forEach((tile) => {
@@ -10561,18 +10706,39 @@ function HexGridImpl(props) {
10561
10706
  height: maxY - minY + padding * 2
10562
10707
  };
10563
10708
  }, [resolvedTiles, tilePositions, hexSize]);
10564
- const viewBox = calculateViewBox(bounds, transform);
10565
- const viewBoxParts = viewBox.split(" ").map(Number);
10566
- const viewBoxX = viewBoxParts[0] ?? 0;
10567
- const viewBoxY = viewBoxParts[1] ?? 0;
10568
- const viewBoxHeight = viewBoxParts[3] ?? 0;
10709
+ const interactiveSpaceTargets = useMemo16(
10710
+ () => resolvedTiles.flatMap((space) => {
10711
+ const pos = tilePositions.get(space.id);
10712
+ return pos ? [{ space, pos }] : [];
10713
+ }),
10714
+ [resolvedTiles, tilePositions]
10715
+ );
10716
+ const {
10717
+ transform,
10718
+ bind,
10719
+ isDragging,
10720
+ viewBox,
10721
+ viewBoxX,
10722
+ viewBoxY,
10723
+ viewBoxHeight,
10724
+ spaceHover,
10725
+ edgeHover,
10726
+ vertexHover
10727
+ } = useGridSvgFrame({
10728
+ panZoomEnabled: effectivePanZoom,
10729
+ initialZoom,
10730
+ minZoom,
10731
+ maxZoom,
10732
+ bounds,
10733
+ viewBoxMode: "transformed"
10734
+ });
10569
10735
  return /* @__PURE__ */ jsxs25(
10570
10736
  "svg",
10571
10737
  {
10572
10738
  width,
10573
10739
  height,
10574
10740
  viewBox,
10575
- className: clsx20(
10741
+ className: clsx21(
10576
10742
  "hex-grid",
10577
10743
  effectivePanZoom && "touch-none",
10578
10744
  isDragging && "cursor-grabbing",
@@ -10585,16 +10751,16 @@ function HexGridImpl(props) {
10585
10751
  children: [
10586
10752
  /* @__PURE__ */ jsxs25("defs", { children: [
10587
10753
  /* @__PURE__ */ jsxs25("linearGradient", { id: "oceanGradient", x1: "0%", y1: "0%", x2: "100%", y2: "100%", children: [
10588
- /* @__PURE__ */ jsx39("stop", { offset: "0%", stopColor: "#0ea5e9" }),
10589
- /* @__PURE__ */ jsx39("stop", { offset: "100%", stopColor: "#0284c7" })
10754
+ /* @__PURE__ */ jsx42("stop", { offset: "0%", stopColor: "#0ea5e9" }),
10755
+ /* @__PURE__ */ jsx42("stop", { offset: "100%", stopColor: "#0284c7" })
10590
10756
  ] }),
10591
- /* @__PURE__ */ jsx39("filter", { id: "hexShadow", x: "-20%", y: "-20%", width: "140%", height: "140%", children: /* @__PURE__ */ jsx39("feDropShadow", { dx: "1", dy: "1", stdDeviation: "2", floodOpacity: "0.3" }) })
10757
+ /* @__PURE__ */ jsx42("filter", { id: "hexShadow", x: "-20%", y: "-20%", width: "140%", height: "140%", children: /* @__PURE__ */ jsx42("feDropShadow", { dx: "1", dy: "1", stdDeviation: "2", floodOpacity: "0.3" }) })
10592
10758
  ] }),
10593
- /* @__PURE__ */ jsx39("g", { className: "tiles", role: "list", "aria-label": "Hex tiles", children: resolvedTiles.map((tile) => {
10759
+ /* @__PURE__ */ jsx42("g", { className: "tiles", role: "list", "aria-label": "Hex tiles", children: resolvedTiles.map((tile) => {
10594
10760
  const pos = tilePositions.get(tile.id);
10595
10761
  if (!pos) return null;
10596
10762
  const geometry = buildTileGeometry(pos);
10597
- return /* @__PURE__ */ jsx39(
10763
+ return /* @__PURE__ */ jsx42(
10598
10764
  "g",
10599
10765
  {
10600
10766
  transform: `translate(${pos.x}, ${pos.y})`,
@@ -10605,222 +10771,127 @@ function HexGridImpl(props) {
10605
10771
  tile.id
10606
10772
  );
10607
10773
  }) }),
10608
- interactiveSpaces && resolvedTiles.length > 0 && /* @__PURE__ */ jsx39(
10609
- "g",
10774
+ interactiveSpaces && resolvedTiles.length > 0 && /* @__PURE__ */ jsx42(
10775
+ InteractiveTargetLayerGroup,
10610
10776
  {
10611
- className: "interactive-spaces",
10612
- role: "list",
10613
- "aria-label": "Interactive spaces",
10614
- children: resolvedTiles.map((space) => {
10615
- const pos = tilePositions.get(space.id);
10616
- if (!pos) return null;
10617
- const state = interactiveTargetRenderState(
10618
- interactiveSpaces,
10619
- space.id,
10620
- hoveredSpaceId === space.id
10621
- );
10622
- const isSelectable = isInteractiveTargetSelectable(
10623
- interactiveSpaces,
10624
- state
10625
- );
10626
- return /* @__PURE__ */ jsxs25(
10627
- "g",
10777
+ layer: interactiveSpaces,
10778
+ targets: interactiveSpaceTargets,
10779
+ getTargetId: ({ space }) => space.id,
10780
+ targetKind: "space",
10781
+ groupClassName: "interactive-spaces",
10782
+ groupAriaLabel: "Interactive spaces",
10783
+ groupRole: "list",
10784
+ spreadBrowserAttributes: true,
10785
+ selectMode: "render-state",
10786
+ hover: spaceHover,
10787
+ getTargetTransform: ({ pos }) => `translate(${pos.x}, ${pos.y})`,
10788
+ renderTargetContent: ({ space, pos }, state, isSelectable) => /* @__PURE__ */ jsxs25(Fragment7, { children: [
10789
+ isSelectable && /* @__PURE__ */ jsx42(
10790
+ "polygon",
10628
10791
  {
10629
- transform: `translate(${pos.x}, ${pos.y})`,
10630
- role: isSelectable ? "button" : void 0,
10631
- className: clsx20(isSelectable && "cursor-pointer"),
10632
- onPointerEnter: () => setHoveredSpaceId(space.id),
10633
- onPointerLeave: () => setHoveredSpaceId(
10634
- (currentId) => currentId === space.id ? null : currentId
10635
- ),
10636
- onClick: isSelectable ? () => {
10637
- void state.select?.();
10638
- } : void 0,
10639
- onKeyDown: (event) => handleKeyboardActivation(
10640
- event,
10641
- isSelectable ? () => {
10642
- void state.select?.();
10643
- } : void 0
10644
- ),
10645
- tabIndex: isSelectable ? 0 : void 0,
10646
- "aria-label": isSelectable ? `Select space ${space.id}` : void 0,
10647
- children: [
10648
- isSelectable && /* @__PURE__ */ jsx39(
10649
- "polygon",
10650
- {
10651
- points: buildTileGeometry(pos).points({
10652
- inset: hexSize * 0.05
10653
- }),
10654
- fill: "rgba(255,255,255,0.001)",
10655
- pointerEvents: "all"
10656
- }
10657
- ),
10658
- renderInteractiveSpace ? renderInteractiveSpace(space, state) : null
10659
- ]
10660
- },
10661
- space.id
10662
- );
10663
- })
10792
+ points: buildTileGeometry(pos).points({
10793
+ inset: hexSize * 0.05
10794
+ }),
10795
+ fill: "rgba(255,255,255,0.001)",
10796
+ pointerEvents: "all"
10797
+ }
10798
+ ),
10799
+ renderInteractiveSpace ? renderInteractiveSpace(space, state) : null
10800
+ ] })
10664
10801
  }
10665
10802
  ),
10666
- resolvedEdges.length > 0 && /* @__PURE__ */ jsx39("g", { className: "edges", role: "list", "aria-label": "Hex edges", children: resolvedEdgePositions.map(({ edge, interactiveEdge }) => {
10667
- return /* @__PURE__ */ jsx39("g", { role: "listitem", children: renderEdge(edge, interactiveEdge.position) }, edge.id);
10803
+ resolvedEdges.length > 0 && /* @__PURE__ */ jsx42("g", { className: "edges", role: "list", "aria-label": "Hex edges", children: resolvedEdgePositions.map(({ edge, interactiveEdge }) => {
10804
+ return /* @__PURE__ */ jsx42("g", { role: "listitem", children: renderEdge(edge, interactiveEdge.position) }, edge.id);
10668
10805
  }) }),
10669
- resolvedVertices.length > 0 && /* @__PURE__ */ jsx39("g", { className: "vertices", role: "list", "aria-label": "Hex vertices", children: resolvedVertexPositions.map(({ vertex, interactiveVertex }) => {
10670
- return /* @__PURE__ */ jsx39("g", { role: "listitem", children: renderVertex(vertex, interactiveVertex.position) }, vertex.id);
10806
+ resolvedVertices.length > 0 && /* @__PURE__ */ jsx42("g", { className: "vertices", role: "list", "aria-label": "Hex vertices", children: resolvedVertexPositions.map(({ vertex, interactiveVertex }) => {
10807
+ return /* @__PURE__ */ jsx42("g", { role: "listitem", children: renderVertex(vertex, interactiveVertex.position) }, vertex.id);
10671
10808
  }) }),
10672
- interactiveEdges && resolvedEdgePositions.length > 0 && /* @__PURE__ */ jsx39(
10673
- "g",
10809
+ interactiveEdges && resolvedEdgePositions.length > 0 && /* @__PURE__ */ jsx42(
10810
+ InteractiveTargetLayerGroup,
10674
10811
  {
10675
- className: "interactive-edges",
10676
- role: "list",
10677
- "aria-label": "Interactive edges for placement",
10678
- children: resolvedEdgePositions.map(({ interactiveEdge: edge }) => {
10679
- const state = interactiveTargetRenderState(
10680
- interactiveEdges,
10681
- edge.id,
10682
- hoveredEdgeId === edge.id
10683
- );
10684
- const isSelectable = isInteractiveTargetSelectable(
10685
- interactiveEdges,
10686
- state
10687
- );
10812
+ layer: interactiveEdges,
10813
+ targets: resolvedEdgePositions,
10814
+ getTargetId: ({ interactiveEdge }) => interactiveEdge.id,
10815
+ targetKind: "edge",
10816
+ groupClassName: "interactive-edges",
10817
+ groupAriaLabel: "Interactive edges for placement",
10818
+ groupRole: "list",
10819
+ spreadBrowserAttributes: true,
10820
+ selectMode: "render-state",
10821
+ hover: edgeHover,
10822
+ renderTargetContent: ({ interactiveEdge: edge }, state, isSelectable) => {
10688
10823
  const touchTargetLength = Math.hypot(
10689
10824
  edge.position.x2 - edge.position.x1,
10690
10825
  edge.position.y2 - edge.position.y1
10691
10826
  );
10692
- return /* @__PURE__ */ jsxs25(
10693
- "g",
10694
- {
10695
- role: isSelectable ? "button" : void 0,
10696
- className: clsx20(isSelectable && "cursor-pointer"),
10697
- onPointerEnter: () => setHoveredEdgeId(edge.id),
10698
- onPointerLeave: () => setHoveredEdgeId(
10699
- (currentId) => currentId === edge.id ? null : currentId
10700
- ),
10701
- onClick: isSelectable ? () => {
10702
- void state.select?.();
10703
- } : void 0,
10704
- onKeyDown: (event) => handleKeyboardActivation(
10705
- event,
10706
- isSelectable ? () => {
10707
- void state.select?.();
10708
- } : void 0
10709
- ),
10710
- tabIndex: isSelectable ? 0 : void 0,
10711
- "aria-label": isSelectable ? `Select edge ${edge.id}` : void 0,
10712
- children: [
10713
- isSelectable && /* @__PURE__ */ jsx39(
10714
- "rect",
10715
- {
10716
- x: edge.position.midX - touchTargetLength / 2,
10717
- y: edge.position.midY - interactiveEdgeSize,
10718
- width: touchTargetLength,
10719
- height: interactiveEdgeSize * 2,
10720
- rx: interactiveEdgeSize,
10721
- fill: "rgba(255,255,255,0.001)",
10722
- transform: `rotate(${edge.position.edgeAngle} ${edge.position.midX} ${edge.position.midY})`,
10723
- pointerEvents: "all"
10724
- }
10725
- ),
10726
- renderInteractiveEdge ? renderInteractiveEdge(edge, edge.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx39(
10727
- DefaultInteractiveEdge,
10728
- {
10729
- position: edge.position,
10730
- isHovered: state.isHovered,
10731
- strokeWidth: interactiveEdgeSize * 0.6
10732
- }
10733
- ) : null
10734
- ]
10735
- },
10736
- edge.id
10737
- );
10738
- })
10827
+ return /* @__PURE__ */ jsxs25(Fragment7, { children: [
10828
+ isSelectable && /* @__PURE__ */ jsx42(
10829
+ "rect",
10830
+ {
10831
+ x: edge.position.midX - touchTargetLength / 2,
10832
+ y: edge.position.midY - interactiveEdgeSize,
10833
+ width: touchTargetLength,
10834
+ height: interactiveEdgeSize * 2,
10835
+ rx: interactiveEdgeSize,
10836
+ fill: "rgba(255,255,255,0.001)",
10837
+ transform: `rotate(${edge.position.edgeAngle} ${edge.position.midX} ${edge.position.midY})`,
10838
+ pointerEvents: "all"
10839
+ }
10840
+ ),
10841
+ renderInteractiveEdge ? renderInteractiveEdge(edge, edge.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx42(
10842
+ DefaultInteractiveEdge,
10843
+ {
10844
+ position: edge.position,
10845
+ isHovered: state.isHovered,
10846
+ strokeWidth: interactiveEdgeSize * 0.6
10847
+ }
10848
+ ) : null
10849
+ ] });
10850
+ }
10739
10851
  }
10740
10852
  ),
10741
- interactiveVertices && resolvedVertexPositions.length > 0 && /* @__PURE__ */ jsx39(
10742
- "g",
10853
+ interactiveVertices && resolvedVertexPositions.length > 0 && /* @__PURE__ */ jsx42(
10854
+ InteractiveTargetLayerGroup,
10743
10855
  {
10744
- className: "interactive-vertices",
10745
- role: "list",
10746
- "aria-label": "Interactive vertices for placement",
10747
- children: resolvedVertexPositions.map(({ interactiveVertex: vertex }) => {
10748
- const state = interactiveTargetRenderState(
10749
- interactiveVertices,
10750
- vertex.id,
10751
- hoveredVertexId === vertex.id
10752
- );
10753
- const isSelectable = isInteractiveTargetSelectable(
10754
- interactiveVertices,
10755
- state
10756
- );
10757
- return /* @__PURE__ */ jsxs25(
10758
- "g",
10856
+ layer: interactiveVertices,
10857
+ targets: resolvedVertexPositions,
10858
+ getTargetId: ({ interactiveVertex }) => interactiveVertex.id,
10859
+ targetKind: "vertex",
10860
+ groupClassName: "interactive-vertices",
10861
+ groupAriaLabel: "Interactive vertices for placement",
10862
+ groupRole: "list",
10863
+ spreadBrowserAttributes: true,
10864
+ selectMode: "render-state",
10865
+ hover: vertexHover,
10866
+ renderTargetContent: ({ interactiveVertex: vertex }, state, isSelectable) => /* @__PURE__ */ jsxs25(Fragment7, { children: [
10867
+ isSelectable && /* @__PURE__ */ jsx42(
10868
+ "circle",
10759
10869
  {
10760
- role: isSelectable ? "button" : void 0,
10761
- className: clsx20(isSelectable && "cursor-pointer"),
10762
- onPointerEnter: () => setHoveredVertexId(vertex.id),
10763
- onPointerLeave: () => setHoveredVertexId(
10764
- (currentId) => currentId === vertex.id ? null : currentId
10765
- ),
10766
- onClick: isSelectable ? () => {
10767
- void state.select?.();
10768
- } : void 0,
10769
- onKeyDown: (event) => handleKeyboardActivation(
10770
- event,
10771
- isSelectable ? () => {
10772
- void state.select?.();
10773
- } : void 0
10774
- ),
10775
- tabIndex: isSelectable ? 0 : void 0,
10776
- "aria-label": isSelectable ? `Select vertex ${vertex.id}` : void 0,
10777
- children: [
10778
- isSelectable && /* @__PURE__ */ jsx39(
10779
- "circle",
10780
- {
10781
- cx: vertex.position.x,
10782
- cy: vertex.position.y,
10783
- r: interactiveVertexSize * 1.5,
10784
- fill: "rgba(255,255,255,0.001)",
10785
- pointerEvents: "all"
10786
- }
10787
- ),
10788
- renderInteractiveVertex ? renderInteractiveVertex(vertex, vertex.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx39(
10789
- DefaultInteractiveVertex,
10790
- {
10791
- position: vertex.position,
10792
- isHovered: state.isHovered,
10793
- size: interactiveVertexSize * 0.6
10794
- }
10795
- ) : null
10796
- ]
10797
- },
10798
- vertex.id
10799
- );
10800
- })
10870
+ cx: vertex.position.x,
10871
+ cy: vertex.position.y,
10872
+ r: interactiveVertexSize * 1.5,
10873
+ fill: "rgba(255,255,255,0.001)",
10874
+ pointerEvents: "all"
10875
+ }
10876
+ ),
10877
+ renderInteractiveVertex ? renderInteractiveVertex(vertex, vertex.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx42(
10878
+ DefaultInteractiveVertex,
10879
+ {
10880
+ position: vertex.position,
10881
+ isHovered: state.isHovered,
10882
+ size: interactiveVertexSize * 0.6
10883
+ }
10884
+ ) : null
10885
+ ] })
10801
10886
  }
10802
10887
  ),
10803
- effectivePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsxs25(
10804
- "g",
10888
+ effectivePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsx42(
10889
+ GridZoomIndicator,
10805
10890
  {
10806
- transform: `translate(${viewBoxX + 10}, ${viewBoxY + viewBoxHeight - 30})`,
10807
- children: [
10808
- /* @__PURE__ */ jsx39(
10809
- "rect",
10810
- {
10811
- x: 0,
10812
- y: 0,
10813
- width: 60,
10814
- height: 20,
10815
- rx: 4,
10816
- fill: "rgba(0,0,0,0.6)"
10817
- }
10818
- ),
10819
- /* @__PURE__ */ jsxs25("text", { x: 30, y: 14, textAnchor: "middle", fill: "white", fontSize: 12, children: [
10820
- Math.round(transform.zoom * 100),
10821
- "%"
10822
- ] })
10823
- ]
10891
+ viewBoxX,
10892
+ viewBoxY,
10893
+ viewBoxHeight,
10894
+ zoom: transform.zoom
10824
10895
  }
10825
10896
  )
10826
10897
  ]
@@ -10987,4 +11058,4 @@ export {
10987
11058
  HexGrid,
10988
11059
  createHexBoardView
10989
11060
  };
10990
- //# sourceMappingURL=chunk-WYPQ3GG5.js.map
11061
+ //# sourceMappingURL=chunk-QZ6X4B5P.js.map