@dreamboard-games/sdk 0.4.0-alpha.4 → 0.4.0-alpha.6

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 (79) hide show
  1. package/REFERENCE.md +1089 -123
  2. package/dist/{HandView-x8MhbhFl.d.ts → HandView-Bi2lxzQP.d.ts} +3 -3
  3. package/dist/{ThemeProvider-DRalAWzY.d.ts → ThemeProvider-CElaL2ik.d.ts} +1 -1
  4. package/dist/authoring/index.js +2 -2
  5. package/dist/browser-interaction.js +1 -1
  6. package/dist/{chunk-E3X552YM.js → chunk-2TRZSZGD.js} +1061 -425
  7. package/dist/chunk-2TRZSZGD.js.map +1 -0
  8. package/dist/{chunk-CP35NPPY.js → chunk-52DH7VQF.js} +61 -7
  9. package/dist/chunk-52DH7VQF.js.map +1 -0
  10. package/dist/{chunk-N6ZDIMRB.js → chunk-B2YBS3SG.js} +1 -1
  11. package/dist/chunk-B2YBS3SG.js.map +1 -0
  12. package/dist/{chunk-LKJLAGND.js → chunk-DDST4U2P.js} +2 -2
  13. package/dist/{chunk-SUMZ5OEH.js → chunk-HK3WN4U7.js} +2 -2
  14. package/dist/{chunk-SUMZ5OEH.js.map → chunk-HK3WN4U7.js.map} +1 -1
  15. package/dist/{chunk-QOFFRHZR.js → chunk-OV6JC2BM.js} +64 -28
  16. package/dist/chunk-OV6JC2BM.js.map +1 -0
  17. package/dist/{chunk-K5ZRJTZZ.js → chunk-PAPIAMYX.js} +6 -3
  18. package/dist/chunk-PAPIAMYX.js.map +1 -0
  19. package/dist/{chunk-TTISZQNI.js → chunk-SOBNI363.js} +39 -28
  20. package/dist/chunk-SOBNI363.js.map +1 -0
  21. package/dist/{chunk-Y6Y2YABD.js → chunk-TGMXBRKY.js} +22 -6
  22. package/dist/chunk-TGMXBRKY.js.map +1 -0
  23. package/dist/{chunk-XZ667T4K.js → chunk-UC2UXAC6.js} +2 -2
  24. package/dist/{chunk-O6M6PN4E.js → chunk-UUQNOGZV.js} +94 -53
  25. package/dist/chunk-UUQNOGZV.js.map +1 -0
  26. package/dist/{chunk-WUIVY2KE.js → chunk-WHR5UW3F.js} +1 -1
  27. package/dist/chunk-WHR5UW3F.js.map +1 -0
  28. package/dist/codegen.d.ts +13 -0
  29. package/dist/codegen.js +1 -1
  30. package/dist/{components-B7hFaEn_.d.ts → components-BTwSIjXj.d.ts} +77 -206
  31. package/dist/{hex-board-view-BFlWDb9k.d.ts → hex-board-view-aKkblDp6.d.ts} +180 -1
  32. package/dist/{index-gjxQichK.d.ts → index-CFTjJIXd.d.ts} +5 -4
  33. package/dist/{index.d-BL3bT5lt.d.ts → index.d-DMASeF6M.d.ts} +294 -27
  34. package/dist/index.js +2 -2
  35. package/dist/package-set.d.ts +2 -2
  36. package/dist/package-set.js +2 -2
  37. package/dist/{runtime-api-BJharVaj.d.ts → plugin-state-BRH3UiUp.d.ts} +19 -3
  38. package/dist/{protocol-BP193lva.d.ts → protocol-835hEGne.d.ts} +42 -1
  39. package/dist/reducer/advanced.d.ts +4 -2
  40. package/dist/reducer/advanced.js +1 -1
  41. package/dist/reducer-contract.d.ts +1 -1
  42. package/dist/reducer-contract.js +2 -2
  43. package/dist/reducer.d.ts +10 -4
  44. package/dist/reducer.js +317 -15
  45. package/dist/reducer.js.map +1 -1
  46. package/dist/runtime/primitives.d.ts +32 -7
  47. package/dist/runtime/primitives.js +9 -5
  48. package/dist/runtime/runtime-api.d.ts +1 -1
  49. package/dist/runtime/workspace-contract.d.ts +7 -7
  50. package/dist/runtime/workspace-contract.js +6 -6
  51. package/dist/runtime-Dkfm1x2r.d.ts +1670 -0
  52. package/dist/runtime.d.ts +10 -9
  53. package/dist/runtime.js +240 -16
  54. package/dist/runtime.js.map +1 -1
  55. package/dist/testing.d.ts +78 -15
  56. package/dist/testing.js +69 -8
  57. package/dist/testing.js.map +1 -1
  58. package/dist/{types-CYeN0wLK.d.ts → types-aI4V9CWe.d.ts} +5 -5
  59. package/dist/types.d.ts +13 -0
  60. package/dist/ui/components.d.ts +6 -3
  61. package/dist/ui/components.js +15 -3
  62. package/dist/ui/plugin-styles.css +2 -2
  63. package/dist/{ui-contract-B4NjRlvC.d.ts → ui-contract-Ue6SywvO.d.ts} +24 -10
  64. package/dist/ui.d.ts +9 -6
  65. package/dist/ui.js +16 -4
  66. package/dist/views-32rSsfeU.d.ts +1559 -0
  67. package/package.json +21 -20
  68. package/dist/chunk-CP35NPPY.js.map +0 -1
  69. package/dist/chunk-E3X552YM.js.map +0 -1
  70. package/dist/chunk-K5ZRJTZZ.js.map +0 -1
  71. package/dist/chunk-N6ZDIMRB.js.map +0 -1
  72. package/dist/chunk-O6M6PN4E.js.map +0 -1
  73. package/dist/chunk-QOFFRHZR.js.map +0 -1
  74. package/dist/chunk-TTISZQNI.js.map +0 -1
  75. package/dist/chunk-WUIVY2KE.js.map +0 -1
  76. package/dist/chunk-Y6Y2YABD.js.map +0 -1
  77. package/dist/views-fn2RuXOx.d.ts +0 -3168
  78. /package/dist/{chunk-LKJLAGND.js.map → chunk-DDST4U2P.js.map} +0 -0
  79. /package/dist/{chunk-XZ667T4K.js.map → chunk-UC2UXAC6.js.map} +0 -0
@@ -6,13 +6,14 @@ import {
6
6
  // src/ui/hooks/usePanZoom.ts
7
7
  import { useState, useCallback, useEffect, useMemo } from "react";
8
8
  import { useGesture } from "@use-gesture/react";
9
+ var DEFAULT_INITIAL_PAN = { x: 0, y: 0 };
9
10
  function usePanZoom(options = {}) {
10
11
  const {
11
12
  enabled = true,
12
13
  initialZoom = 1,
13
14
  minZoom = 0.5,
14
15
  maxZoom = 3,
15
- initialPan = { x: 0, y: 0 },
16
+ initialPan = DEFAULT_INITIAL_PAN,
16
17
  mode = "viewbox",
17
18
  wheelSensitivity = 2e-3,
18
19
  onTransformChange
@@ -29,7 +30,9 @@ function usePanZoom(options = {}) {
29
30
  (newZoom, newPan) => {
30
31
  const clampedZoom = clampZoom(newZoom);
31
32
  setZoomState(clampedZoom);
32
- setPanState(newPan);
33
+ setPanState(
34
+ (current) => current.x === newPan.x && current.y === newPan.y ? current : newPan
35
+ );
33
36
  onTransformChange?.({ zoom: clampedZoom, pan: newPan });
34
37
  },
35
38
  [clampZoom, onTransformChange]
@@ -89,10 +92,10 @@ function usePanZoom(options = {}) {
89
92
  );
90
93
  const resetTransform = useCallback(() => {
91
94
  updateTransform(initialZoom, initialPan);
92
- }, [initialZoom, initialPan, updateTransform]);
95
+ }, [initialZoom, initialPan.x, initialPan.y, updateTransform]);
93
96
  useEffect(() => {
94
97
  updateTransform(initialZoom, initialPan);
95
- }, [initialZoom, initialPan, updateTransform]);
98
+ }, [initialZoom, initialPan.x, initialPan.y, updateTransform]);
96
99
  const setZoom = useCallback(
97
100
  (newZoom) => {
98
101
  updateTransform(clampZoom(newZoom), pan);
@@ -7446,7 +7449,7 @@ function DiceRollDialog({
7446
7449
  const displaySum = sumValues(displayValues);
7447
7450
  const title = action.title ?? "Roll dice";
7448
7451
  const description = action.description ?? "Roll to resolve the current turn.";
7449
- const resultLabel = action.resultLabel ?? "Roll result";
7452
+ const resultLabel2 = action.resultLabel ?? "Roll result";
7450
7453
  const rollLabel = action.rollLabel ?? "Roll dice";
7451
7454
  const disabled = action.available === false || phase === "rolling";
7452
7455
  const canClose = true;
@@ -7488,7 +7491,7 @@ function DiceRollDialog({
7488
7491
  gap: theme.space[4]
7489
7492
  },
7490
7493
  children: [
7491
- /* @__PURE__ */ jsx34(RollResult, { label: resultLabel, sum: displaySum, phase }),
7494
+ /* @__PURE__ */ jsx34(RollResult, { label: resultLabel2, sum: displaySum, phase }),
7492
7495
  /* @__PURE__ */ jsx34(
7493
7496
  DiceRow,
7494
7497
  {
@@ -7997,21 +8000,351 @@ function StatusIndicator({
7997
8000
  );
7998
8001
  }
7999
8002
 
8000
- // src/ui/components/GameEndDisplay.tsx
8003
+ // src/ui/components/Guidance.tsx
8004
+ import {
8005
+ AlertCircle as AlertCircle2,
8006
+ CheckCircle2,
8007
+ Circle,
8008
+ HelpCircle,
8009
+ Info as Info2
8010
+ } from "lucide-react";
8011
+ import { useId as useId6 } from "react";
8012
+ import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
8013
+ function GuidancePanel({
8014
+ phase,
8015
+ actions = [],
8016
+ className,
8017
+ style
8018
+ }) {
8019
+ const theme = useTheme();
8020
+ const titleId = useId6();
8021
+ const summaryId = useId6();
8022
+ const hasSummary = phase.summary !== void 0 && phase.summary !== null;
8023
+ const hasObjective = phase.objective !== void 0 && phase.objective !== null;
8024
+ const describedBy = [
8025
+ hasSummary || hasObjective ? summaryId : void 0
8026
+ ].filter(Boolean);
8027
+ return /* @__PURE__ */ jsxs19(
8028
+ "section",
8029
+ {
8030
+ className,
8031
+ "aria-labelledby": titleId,
8032
+ "aria-describedby": describedBy.join(" ") || void 0,
8033
+ style: {
8034
+ ...guidanceContainerStyle(theme),
8035
+ ...style
8036
+ },
8037
+ children: [
8038
+ /* @__PURE__ */ jsxs19("header", { style: headerStyle(theme), children: [
8039
+ /* @__PURE__ */ jsx36(
8040
+ Info2,
8041
+ {
8042
+ size: 20,
8043
+ strokeWidth: 2.5,
8044
+ "aria-hidden": "true",
8045
+ style: { color: theme.semantic.intent.info.solid, flex: "0 0 auto" }
8046
+ }
8047
+ ),
8048
+ /* @__PURE__ */ jsxs19("div", { style: { minWidth: 0 }, children: [
8049
+ /* @__PURE__ */ jsx36("h2", { id: titleId, style: titleStyle(theme), children: phase.label }),
8050
+ /* @__PURE__ */ jsxs19("div", { id: summaryId, style: bodyStackStyle(theme), children: [
8051
+ hasSummary ? /* @__PURE__ */ jsx36("p", { style: bodyTextStyle(theme), children: phase.summary }) : null,
8052
+ hasObjective ? /* @__PURE__ */ jsx36("p", { style: objectiveTextStyle(theme), children: phase.objective }) : null
8053
+ ] })
8054
+ ] })
8055
+ ] }),
8056
+ actions.length > 0 ? /* @__PURE__ */ jsx36(
8057
+ "div",
8058
+ {
8059
+ "aria-label": "Available action guidance",
8060
+ style: {
8061
+ display: "grid",
8062
+ gap: theme.space[2]
8063
+ },
8064
+ children: actions.map((action, index) => /* @__PURE__ */ jsx36(
8065
+ ActionHelp,
8066
+ {
8067
+ label: action.label,
8068
+ help: action.help,
8069
+ unavailableReason: action.unavailableReason
8070
+ },
8071
+ `${String(action.label)}:${index}`
8072
+ ))
8073
+ }
8074
+ ) : null
8075
+ ]
8076
+ }
8077
+ );
8078
+ }
8079
+ function SetupChecklist({
8080
+ guidance,
8081
+ completedStepIds = [],
8082
+ className,
8083
+ style
8084
+ }) {
8085
+ const theme = useTheme();
8086
+ const titleId = useId6();
8087
+ const completed = new Set(completedStepIds);
8088
+ if (!guidance) return null;
8089
+ return /* @__PURE__ */ jsxs19(
8090
+ "section",
8091
+ {
8092
+ className,
8093
+ "aria-labelledby": titleId,
8094
+ style: {
8095
+ ...guidanceContainerStyle(theme),
8096
+ ...style
8097
+ },
8098
+ children: [
8099
+ /* @__PURE__ */ jsxs19("header", { style: headerStyle(theme), children: [
8100
+ /* @__PURE__ */ jsx36(
8101
+ CheckCircle2,
8102
+ {
8103
+ size: 20,
8104
+ strokeWidth: 2.5,
8105
+ "aria-hidden": "true",
8106
+ style: {
8107
+ color: theme.semantic.intent.success.solid,
8108
+ flex: "0 0 auto"
8109
+ }
8110
+ }
8111
+ ),
8112
+ /* @__PURE__ */ jsxs19("div", { style: { minWidth: 0 }, children: [
8113
+ /* @__PURE__ */ jsx36("h2", { id: titleId, style: titleStyle(theme), children: guidance.name }),
8114
+ guidance.summary ? /* @__PURE__ */ jsx36("p", { style: bodyTextStyle(theme), children: guidance.summary }) : null
8115
+ ] })
8116
+ ] }),
8117
+ guidance.steps.length > 0 ? /* @__PURE__ */ jsx36(
8118
+ "ol",
8119
+ {
8120
+ style: {
8121
+ display: "grid",
8122
+ gap: theme.space[2],
8123
+ margin: 0,
8124
+ padding: 0,
8125
+ listStyle: "none"
8126
+ },
8127
+ children: guidance.steps.map((step) => {
8128
+ const isComplete = completed.has(step.id);
8129
+ return /* @__PURE__ */ jsxs19(
8130
+ "li",
8131
+ {
8132
+ "aria-current": isComplete ? void 0 : "step",
8133
+ style: {
8134
+ display: "grid",
8135
+ gridTemplateColumns: "24px minmax(0, 1fr)",
8136
+ gap: theme.space[3],
8137
+ alignItems: "start",
8138
+ minWidth: 0
8139
+ },
8140
+ children: [
8141
+ isComplete ? /* @__PURE__ */ jsx36(
8142
+ CheckCircle2,
8143
+ {
8144
+ size: 20,
8145
+ strokeWidth: 2.5,
8146
+ "aria-label": "Complete",
8147
+ style: { color: theme.semantic.intent.success.solid }
8148
+ }
8149
+ ) : /* @__PURE__ */ jsx36(
8150
+ Circle,
8151
+ {
8152
+ size: 20,
8153
+ strokeWidth: 2.5,
8154
+ "aria-label": "Not complete",
8155
+ style: { color: theme.semantic.text.muted }
8156
+ }
8157
+ ),
8158
+ /* @__PURE__ */ jsxs19("div", { style: bodyStackStyle(theme), children: [
8159
+ /* @__PURE__ */ jsx36("span", { style: stepTitleStyle(theme), children: step.label }),
8160
+ step.description ? /* @__PURE__ */ jsx36("span", { style: bodyTextStyle(theme), children: step.description }) : null
8161
+ ] })
8162
+ ]
8163
+ },
8164
+ step.id
8165
+ );
8166
+ })
8167
+ }
8168
+ ) : null
8169
+ ]
8170
+ }
8171
+ );
8172
+ }
8173
+ function ActionHelp({
8174
+ label,
8175
+ help,
8176
+ unavailableReason,
8177
+ className,
8178
+ style
8179
+ }) {
8180
+ const theme = useTheme();
8181
+ const helpId = useId6();
8182
+ const reasonId = useId6();
8183
+ const hasHelp = help !== void 0 && help !== null;
8184
+ const hasReason = unavailableReason !== void 0 && unavailableReason !== null;
8185
+ const describedBy = [
8186
+ hasHelp ? helpId : void 0,
8187
+ hasReason ? reasonId : void 0
8188
+ ].filter(Boolean);
8189
+ return /* @__PURE__ */ jsxs19(
8190
+ "article",
8191
+ {
8192
+ className,
8193
+ "aria-describedby": describedBy.join(" ") || void 0,
8194
+ style: {
8195
+ display: "grid",
8196
+ gap: theme.space[2],
8197
+ minWidth: 0,
8198
+ padding: theme.space[3],
8199
+ borderRadius: theme.radius.md,
8200
+ border: `1px solid ${theme.semantic.border.subtle}`,
8201
+ background: theme.semantic.surface.inset,
8202
+ ...style
8203
+ },
8204
+ children: [
8205
+ /* @__PURE__ */ jsxs19(
8206
+ "div",
8207
+ {
8208
+ style: {
8209
+ display: "flex",
8210
+ alignItems: "center",
8211
+ gap: theme.space[2],
8212
+ minWidth: 0
8213
+ },
8214
+ children: [
8215
+ /* @__PURE__ */ jsx36(
8216
+ HelpCircle,
8217
+ {
8218
+ size: 18,
8219
+ strokeWidth: 2.5,
8220
+ "aria-hidden": "true",
8221
+ style: {
8222
+ color: theme.semantic.intent.info.solid,
8223
+ flex: "0 0 auto"
8224
+ }
8225
+ }
8226
+ ),
8227
+ /* @__PURE__ */ jsx36("h3", { style: actionTitleStyle(theme), children: label })
8228
+ ]
8229
+ }
8230
+ ),
8231
+ hasHelp ? /* @__PURE__ */ jsx36("p", { id: helpId, style: bodyTextStyle(theme), children: help }) : null,
8232
+ hasReason ? /* @__PURE__ */ jsxs19(
8233
+ "div",
8234
+ {
8235
+ id: reasonId,
8236
+ role: "status",
8237
+ style: {
8238
+ ...chipStyle(theme, { variant: "warning" }),
8239
+ justifySelf: "start",
8240
+ display: "inline-flex",
8241
+ alignItems: "center",
8242
+ gap: theme.space[1],
8243
+ maxWidth: "100%",
8244
+ whiteSpace: "normal"
8245
+ },
8246
+ children: [
8247
+ /* @__PURE__ */ jsx36(AlertCircle2, { size: 14, strokeWidth: 2.5, "aria-hidden": "true" }),
8248
+ /* @__PURE__ */ jsx36("span", { children: unavailableReason })
8249
+ ]
8250
+ }
8251
+ ) : null
8252
+ ]
8253
+ }
8254
+ );
8255
+ }
8256
+ function guidanceContainerStyle(theme) {
8257
+ return {
8258
+ display: "grid",
8259
+ gap: theme.space[4],
8260
+ minWidth: 0,
8261
+ color: theme.semantic.text.primary,
8262
+ fontFamily: theme.typography.fontFamily.body
8263
+ };
8264
+ }
8265
+ function headerStyle(theme) {
8266
+ return {
8267
+ display: "grid",
8268
+ gridTemplateColumns: "24px minmax(0, 1fr)",
8269
+ gap: theme.space[3],
8270
+ alignItems: "start",
8271
+ minWidth: 0
8272
+ };
8273
+ }
8274
+ function bodyStackStyle(theme) {
8275
+ return {
8276
+ display: "grid",
8277
+ gap: theme.space[1],
8278
+ minWidth: 0
8279
+ };
8280
+ }
8281
+ function titleStyle(theme) {
8282
+ return {
8283
+ margin: 0,
8284
+ fontFamily: theme.typography.fontFamily.display,
8285
+ fontSize: theme.typography.fontSize.lg,
8286
+ fontWeight: theme.typography.fontWeight.bold,
8287
+ lineHeight: theme.typography.lineHeight.tight,
8288
+ color: theme.semantic.text.primary
8289
+ };
8290
+ }
8291
+ function actionTitleStyle(theme) {
8292
+ return {
8293
+ margin: 0,
8294
+ minWidth: 0,
8295
+ overflowWrap: "anywhere",
8296
+ fontFamily: theme.typography.fontFamily.body,
8297
+ fontSize: theme.typography.fontSize.md,
8298
+ fontWeight: theme.typography.fontWeight.bold,
8299
+ lineHeight: theme.typography.lineHeight.tight,
8300
+ color: theme.semantic.text.primary
8301
+ };
8302
+ }
8303
+ function stepTitleStyle(theme) {
8304
+ return {
8305
+ minWidth: 0,
8306
+ overflowWrap: "anywhere",
8307
+ fontFamily: theme.typography.fontFamily.body,
8308
+ fontSize: theme.typography.fontSize.sm,
8309
+ fontWeight: theme.typography.fontWeight.bold,
8310
+ lineHeight: theme.typography.lineHeight.tight,
8311
+ color: theme.semantic.text.primary
8312
+ };
8313
+ }
8314
+ function bodyTextStyle(theme) {
8315
+ return {
8316
+ margin: 0,
8317
+ minWidth: 0,
8318
+ overflowWrap: "anywhere",
8319
+ color: theme.semantic.text.muted,
8320
+ fontSize: theme.typography.fontSize.sm,
8321
+ lineHeight: theme.typography.lineHeight.normal
8322
+ };
8323
+ }
8324
+ function objectiveTextStyle(theme) {
8325
+ return {
8326
+ ...bodyTextStyle(theme),
8327
+ color: theme.semantic.text.primary,
8328
+ fontWeight: theme.typography.fontWeight.medium
8329
+ };
8330
+ }
8331
+
8332
+ // src/ui/components/OutcomeDialog.tsx
8001
8333
  import { motion as motion9 } from "framer-motion";
8002
- import { Trophy, Home, Crown, Medal } from "lucide-react";
8334
+ import { Home, Medal, Trophy } from "lucide-react";
8003
8335
  import { useEffect as useEffect13, useState as useState17 } from "react";
8004
- import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
8005
- function rankIntent(rank) {
8006
- if (rank === 1) return "warning";
8007
- if (rank === 2) return "secondary";
8008
- if (rank === 3) return "info";
8336
+ import { jsx as jsx37, jsxs as jsxs20 } from "react/jsx-runtime";
8337
+ function rankIntent(row) {
8338
+ if (row.result === "win") return "warning";
8339
+ if (row.result === "draw") return "info";
8340
+ if (row.result === "eliminated") return "danger";
8341
+ if (row.rank === 1) return "secondary";
8009
8342
  return "secondary";
8010
8343
  }
8011
- function RankIcon({ rank, theme }) {
8012
- const intent = intentForVariant(theme, rankIntent(rank));
8013
- if (rank === 1) {
8014
- return /* @__PURE__ */ jsx36(
8344
+ function RankIcon({ row, theme }) {
8345
+ const intent = intentForVariant(theme, rankIntent(row));
8346
+ if (row.result === "win") {
8347
+ return /* @__PURE__ */ jsx37(
8015
8348
  Trophy,
8016
8349
  {
8017
8350
  width: 20,
@@ -8022,8 +8355,8 @@ function RankIcon({ rank, theme }) {
8022
8355
  }
8023
8356
  );
8024
8357
  }
8025
- if (rank === 2 || rank === 3) {
8026
- return /* @__PURE__ */ jsx36(
8358
+ if (row.rank <= 3) {
8359
+ return /* @__PURE__ */ jsx37(
8027
8360
  Medal,
8028
8361
  {
8029
8362
  width: 20,
@@ -8034,7 +8367,7 @@ function RankIcon({ rank, theme }) {
8034
8367
  }
8035
8368
  );
8036
8369
  }
8037
- return /* @__PURE__ */ jsxs19(
8370
+ return /* @__PURE__ */ jsxs20(
8038
8371
  "span",
8039
8372
  {
8040
8373
  style: {
@@ -8046,313 +8379,375 @@ function RankIcon({ rank, theme }) {
8046
8379
  },
8047
8380
  children: [
8048
8381
  "#",
8049
- rank
8382
+ row.rank
8050
8383
  ]
8051
8384
  }
8052
8385
  );
8053
8386
  }
8054
- function GameEndDisplay({
8055
- isGameOver,
8056
- scores,
8057
- winnerMessage,
8058
- showDetails = false,
8059
- onReturnToLobby,
8060
- className
8387
+ function resultLabel(result) {
8388
+ if (result === "win") return "Win";
8389
+ if (result === "draw") return "Draw";
8390
+ if (result === "loss") return "Loss";
8391
+ return "Eliminated";
8392
+ }
8393
+ function outcomeTitle(outcome) {
8394
+ const rows = outcome.standings;
8395
+ const rankOneRows = rows.filter((row) => row.rank === 1);
8396
+ if (rankOneRows.length > 1 && rankOneRows.every((row) => row.result === "draw")) {
8397
+ return "Draw";
8398
+ }
8399
+ if (rows.length > 0 && rows.every((row) => row.result === "win")) {
8400
+ return "Team Victory";
8401
+ }
8402
+ if (rankOneRows.length === 1 && rankOneRows[0]?.result === "win") {
8403
+ return "Game Complete";
8404
+ }
8405
+ return "Game Complete";
8406
+ }
8407
+ function DetailsList({
8408
+ label,
8409
+ entries
8061
8410
  }) {
8062
8411
  const theme = useTheme();
8063
- const reducedMotion = theme.motion.reducedMotion === "true";
8064
- const [isOpen, setIsOpen] = useState17(isGameOver);
8065
- useEffect13(() => {
8066
- setIsOpen(isGameOver);
8067
- }, [isGameOver]);
8068
- if (!isGameOver) return null;
8069
- const winner = scores.find((s) => s.isWinner) || scores[0];
8070
- const sortedScores = [...scores].sort((a, b) => b.score - a.score);
8071
- const winningIntent = theme.semantic.intent.warning;
8072
- const title = `${winner?.name ?? "Game"} Wins!`;
8073
- return /* @__PURE__ */ jsx36(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs19(
8074
- DialogContent,
8075
- {
8076
- className: `border-0 p-6 text-center shadow-none sm:max-w-lg ${className ?? ""}`,
8077
- overlayClassName: "bg-black/50 backdrop-blur-md",
8078
- "aria-describedby": void 0,
8079
- style: {
8080
- ...surfaceStyle(theme, { tone: "sheet", radius: "hud" }),
8081
- width: "100%",
8082
- maxWidth: 480,
8083
- padding: `${theme.space[8]} ${theme.space[6]}`,
8084
- textAlign: "center",
8085
- boxShadow: theme.elevation.overlay,
8086
- overflow: "hidden",
8087
- backgroundImage: `radial-gradient(circle at top, ${winningIntent.soft} 0%, ${theme.semantic.surface.sheet} 60%)`,
8088
- fontFamily: theme.typography.fontFamily.body
8089
- },
8090
- children: [
8091
- /* @__PURE__ */ jsx36(DialogTitle, { className: "sr-only", children: title }),
8092
- /* @__PURE__ */ jsx36(
8093
- motion9.div,
8412
+ if (entries.length === 0) return null;
8413
+ return /* @__PURE__ */ jsxs20("div", { children: [
8414
+ /* @__PURE__ */ jsx37(
8415
+ "div",
8416
+ {
8417
+ style: {
8418
+ marginBottom: theme.space[1],
8419
+ color: theme.semantic.text.muted,
8420
+ fontSize: theme.typography.fontSize.xs,
8421
+ fontWeight: theme.typography.fontWeight.bold,
8422
+ textTransform: "uppercase"
8423
+ },
8424
+ children: label
8425
+ }
8426
+ ),
8427
+ /* @__PURE__ */ jsx37(
8428
+ "dl",
8429
+ {
8430
+ style: {
8431
+ display: "grid",
8432
+ gap: theme.space[1],
8433
+ margin: 0
8434
+ },
8435
+ children: entries.map((entry) => /* @__PURE__ */ jsxs20(
8436
+ "div",
8094
8437
  {
8095
- initial: reducedMotion ? { scale: 1 } : { scale: 0.95, rotate: -180, opacity: 0 },
8096
- animate: reducedMotion ? { scale: 1 } : { scale: 1, rotate: 0, opacity: 1 },
8097
- transition: {
8098
- type: "spring",
8099
- stiffness: 200,
8100
- damping: 15,
8101
- delay: reducedMotion ? 0 : 0.2
8102
- },
8103
8438
  style: {
8104
- marginBottom: theme.space[6],
8105
- display: "inline-flex",
8106
- alignItems: "center",
8107
- justifyContent: "center",
8108
- width: 96,
8109
- height: 96,
8110
- borderRadius: theme.radius.pill,
8111
- background: winningIntent.soft,
8112
- border: `3px solid ${winningIntent.border}`,
8113
- boxShadow: theme.elevation.lifted
8439
+ display: "flex",
8440
+ justifyContent: "space-between",
8441
+ gap: theme.space[3],
8442
+ color: theme.semantic.text.muted,
8443
+ fontSize: theme.typography.fontSize.sm
8114
8444
  },
8115
- children: /* @__PURE__ */ jsx36(
8116
- Trophy,
8117
- {
8118
- width: 48,
8119
- height: 48,
8120
- strokeWidth: 2.5,
8121
- "aria-hidden": "true",
8122
- style: { color: winningIntent.solid }
8123
- }
8124
- )
8125
- }
8126
- ),
8127
- /* @__PURE__ */ jsxs19(
8128
- motion9.div,
8129
- {
8130
- initial: reducedMotion ? { opacity: 0 } : { opacity: 0, y: 10 },
8131
- animate: reducedMotion ? { opacity: 1 } : { opacity: 1, y: 0 },
8132
- transition: { delay: reducedMotion ? 0 : 0.4 },
8133
8445
  children: [
8134
- /* @__PURE__ */ jsx36(
8135
- "h2",
8446
+ /* @__PURE__ */ jsx37("dt", { children: entry.label }),
8447
+ /* @__PURE__ */ jsx37(
8448
+ "dd",
8136
8449
  {
8137
- "aria-hidden": "true",
8138
8450
  style: {
8139
8451
  margin: 0,
8140
- fontFamily: theme.typography.fontFamily.display,
8141
- fontSize: theme.typography.fontSize["3xl"],
8142
- fontWeight: theme.typography.fontWeight.bold,
8143
- color: theme.semantic.text.primary,
8144
- marginBottom: theme.space[2],
8145
- lineHeight: theme.typography.lineHeight.tight
8146
- },
8147
- children: title
8148
- }
8149
- ),
8150
- winnerMessage && /* @__PURE__ */ jsx36(
8151
- "p",
8152
- {
8153
- style: {
8154
- margin: 0,
8155
- marginBottom: theme.space[6],
8156
- display: "inline-block",
8157
- ...chipStyle(theme, { variant: "warning", size: "md" }),
8158
- fontSize: theme.typography.fontSize.sm
8452
+ fontFamily: theme.typography.fontFamily.tabular,
8453
+ fontWeight: theme.typography.fontWeight.bold
8159
8454
  },
8160
- children: winnerMessage
8455
+ children: entry.value
8161
8456
  }
8162
8457
  )
8163
8458
  ]
8164
- }
8165
- ),
8166
- /* @__PURE__ */ jsx36(
8167
- motion9.div,
8459
+ },
8460
+ entry.id
8461
+ ))
8462
+ }
8463
+ )
8464
+ ] });
8465
+ }
8466
+ function StandingsTable({
8467
+ rows,
8468
+ playerName,
8469
+ provisional = false,
8470
+ className
8471
+ }) {
8472
+ const theme = useTheme();
8473
+ return /* @__PURE__ */ jsx37(
8474
+ "div",
8475
+ {
8476
+ className,
8477
+ role: "table",
8478
+ "aria-label": provisional ? "Provisional standings" : "Final standings",
8479
+ style: {
8480
+ display: "grid",
8481
+ gap: theme.space[3]
8482
+ },
8483
+ children: rows.map((row) => {
8484
+ const intent = intentForVariant(theme, rankIntent(row));
8485
+ const emphasized = row.result === "win" || row.result === "draw";
8486
+ return /* @__PURE__ */ jsxs20(
8487
+ "div",
8168
8488
  {
8169
- initial: { opacity: 0 },
8170
- animate: { opacity: 1 },
8171
- transition: { delay: reducedMotion ? 0 : 0.6 },
8489
+ role: "row",
8172
8490
  style: {
8173
- display: "flex",
8174
- flexDirection: "column",
8491
+ display: "grid",
8492
+ gridTemplateColumns: "minmax(0, 1fr) auto",
8175
8493
  gap: theme.space[3],
8176
- marginBottom: theme.space[8],
8177
- textAlign: "left"
8494
+ alignItems: "start",
8495
+ padding: theme.space[3],
8496
+ background: emphasized ? intent.soft : theme.semantic.surface.card,
8497
+ border: `1px solid ${emphasized ? intent.border : theme.semantic.border.subtle}`,
8498
+ borderRadius: theme.radius.lg,
8499
+ boxShadow: emphasized ? theme.elevation.hover : theme.elevation.rest
8178
8500
  },
8179
- role: "list",
8180
- "aria-label": "Final scores",
8181
- children: sortedScores.map((player, index) => {
8182
- const rank = index + 1;
8183
- const intent = intentForVariant(theme, rankIntent(rank));
8184
- const isWinner = player.isWinner ?? rank === 1;
8185
- return /* @__PURE__ */ jsxs19(
8186
- motion9.div,
8501
+ children: [
8502
+ /* @__PURE__ */ jsxs20(
8503
+ "div",
8187
8504
  {
8188
- initial: reducedMotion ? { opacity: 0 } : { opacity: 0, x: -20 },
8189
- animate: reducedMotion ? { opacity: 1 } : { opacity: 1, x: 0 },
8190
- transition: {
8191
- delay: reducedMotion ? 0 : 0.6 + index * 0.1
8192
- },
8193
8505
  style: {
8194
- display: "flex",
8195
- alignItems: "center",
8196
- justifyContent: "space-between",
8197
- padding: theme.space[3],
8198
- background: isWinner ? intent.soft : theme.semantic.surface.card,
8199
- border: `1px solid ${isWinner ? intent.border : theme.semantic.border.subtle}`,
8200
- borderRadius: theme.radius.lg,
8201
- boxShadow: isWinner ? theme.elevation.hover : theme.elevation.rest
8506
+ display: "grid",
8507
+ gap: theme.space[2],
8508
+ minWidth: 0
8202
8509
  },
8203
- role: "listitem",
8204
8510
  children: [
8205
- /* @__PURE__ */ jsxs19(
8511
+ /* @__PURE__ */ jsxs20(
8206
8512
  "div",
8207
8513
  {
8208
8514
  style: {
8209
8515
  display: "flex",
8210
8516
  alignItems: "center",
8211
- gap: theme.space[3]
8517
+ gap: theme.space[3],
8518
+ minWidth: 0
8212
8519
  },
8213
8520
  children: [
8214
- /* @__PURE__ */ jsx36(RankIcon, { rank, theme }),
8215
- /* @__PURE__ */ jsx36(
8521
+ /* @__PURE__ */ jsx37(RankIcon, { row, theme }),
8522
+ /* @__PURE__ */ jsx37(
8216
8523
  "span",
8217
8524
  {
8218
8525
  style: {
8526
+ minWidth: 0,
8527
+ overflowWrap: "anywhere",
8528
+ color: emphasized ? intent.onSoft : theme.semantic.text.primary,
8219
8529
  fontFamily: theme.typography.fontFamily.body,
8220
8530
  fontSize: theme.typography.fontSize.lg,
8221
- fontWeight: theme.typography.fontWeight.bold,
8222
- color: isWinner ? intent.onSoft : theme.semantic.text.primary
8531
+ fontWeight: theme.typography.fontWeight.bold
8223
8532
  },
8224
- children: player.name
8533
+ children: playerName(row.playerId)
8225
8534
  }
8226
8535
  ),
8227
- isWinner && /* @__PURE__ */ jsx36(
8228
- Crown,
8536
+ /* @__PURE__ */ jsx37(
8537
+ "span",
8229
8538
  {
8230
- width: 20,
8231
- height: 20,
8232
- strokeWidth: 3,
8233
- "aria-label": "Winner",
8234
- style: { color: intent.solid }
8539
+ style: {
8540
+ ...chipStyle(theme, {
8541
+ variant: rankIntent(row),
8542
+ size: "sm"
8543
+ }),
8544
+ flexShrink: 0
8545
+ },
8546
+ children: resultLabel(row.result)
8235
8547
  }
8236
8548
  )
8237
8549
  ]
8238
8550
  }
8239
8551
  ),
8240
- /* @__PURE__ */ jsx36(
8552
+ /* @__PURE__ */ jsx37(
8553
+ DetailsList,
8554
+ {
8555
+ label: "Breakdown",
8556
+ entries: row.scoreBreakdown ?? []
8557
+ }
8558
+ ),
8559
+ /* @__PURE__ */ jsx37(DetailsList, { label: "Tie-breaks", entries: row.tieBreaks ?? [] })
8560
+ ]
8561
+ }
8562
+ ),
8563
+ /* @__PURE__ */ jsxs20(
8564
+ "div",
8565
+ {
8566
+ role: "cell",
8567
+ "aria-label": `Rank ${row.rank}${row.score === void 0 ? "" : `, score ${row.score}`}`,
8568
+ style: {
8569
+ display: "grid",
8570
+ gap: theme.space[1],
8571
+ justifyItems: "end",
8572
+ flexShrink: 0
8573
+ },
8574
+ children: [
8575
+ /* @__PURE__ */ jsxs20(
8241
8576
  "span",
8242
8577
  {
8243
8578
  style: {
8244
- fontFamily: theme.typography.fontFamily.tabular,
8245
- fontSize: theme.typography.fontSize["2xl"],
8579
+ color: theme.semantic.text.muted,
8580
+ fontSize: theme.typography.fontSize.xs,
8246
8581
  fontWeight: theme.typography.fontWeight.bold,
8247
- color: isWinner ? intent.onSoft : theme.semantic.text.primary,
8582
+ textTransform: "uppercase"
8583
+ },
8584
+ children: [
8585
+ "Rank ",
8586
+ row.rank
8587
+ ]
8588
+ }
8589
+ ),
8590
+ row.score !== void 0 && /* @__PURE__ */ jsx37(
8591
+ "span",
8592
+ {
8593
+ style: {
8248
8594
  paddingInline: theme.space[2],
8249
8595
  paddingBlock: theme.space[0.5],
8250
8596
  background: theme.semantic.surface.inset,
8597
+ border: `1px solid ${theme.semantic.border.subtle}`,
8251
8598
  borderRadius: theme.radius.md,
8252
- border: `1px solid ${theme.semantic.border.subtle}`
8599
+ color: theme.semantic.text.primary,
8600
+ fontFamily: theme.typography.fontFamily.tabular,
8601
+ fontSize: theme.typography.fontSize["2xl"],
8602
+ fontWeight: theme.typography.fontWeight.bold
8253
8603
  },
8254
- children: player.score
8604
+ children: row.score
8255
8605
  }
8256
8606
  )
8257
8607
  ]
8258
- },
8259
- player.playerId
8260
- );
8261
- })
8262
- }
8263
- ),
8264
- showDetails && winner?.details && /* @__PURE__ */ jsxs19(
8608
+ }
8609
+ )
8610
+ ]
8611
+ },
8612
+ row.playerId
8613
+ );
8614
+ })
8615
+ }
8616
+ );
8617
+ }
8618
+ function OutcomeDialog({
8619
+ outcome,
8620
+ playerName,
8621
+ onReturnToLobby,
8622
+ className
8623
+ }) {
8624
+ const theme = useTheme();
8625
+ const reducedMotion = theme.motion.reducedMotion === "true";
8626
+ const [isOpen, setIsOpen] = useState17(Boolean(outcome));
8627
+ useEffect13(() => {
8628
+ setIsOpen(Boolean(outcome));
8629
+ }, [outcome]);
8630
+ if (!outcome) return null;
8631
+ const title = outcomeTitle(outcome);
8632
+ const message = outcome.reason.message ?? outcome.reason.code;
8633
+ const titleIntent = intentForVariant(
8634
+ theme,
8635
+ outcome.standings.some((row) => row.result === "win") ? "warning" : "info"
8636
+ );
8637
+ return /* @__PURE__ */ jsx37(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs20(
8638
+ DialogContent,
8639
+ {
8640
+ className: `border-0 p-6 text-center shadow-none sm:max-w-lg ${className ?? ""}`,
8641
+ overlayClassName: "bg-black/50 backdrop-blur-md",
8642
+ "aria-describedby": void 0,
8643
+ style: {
8644
+ ...surfaceStyle(theme, { tone: "sheet", radius: "hud" }),
8645
+ width: "100%",
8646
+ maxWidth: 560,
8647
+ padding: `${theme.space[8]} ${theme.space[6]}`,
8648
+ textAlign: "center",
8649
+ boxShadow: theme.elevation.overlay,
8650
+ overflow: "hidden",
8651
+ backgroundImage: `radial-gradient(circle at top, ${titleIntent.soft} 0%, ${theme.semantic.surface.sheet} 60%)`,
8652
+ fontFamily: theme.typography.fontFamily.body
8653
+ },
8654
+ children: [
8655
+ /* @__PURE__ */ jsx37(DialogTitle, { className: "sr-only", children: title }),
8656
+ /* @__PURE__ */ jsx37(
8265
8657
  motion9.div,
8266
8658
  {
8267
- initial: { opacity: 0 },
8268
- animate: { opacity: 1 },
8269
- transition: { delay: reducedMotion ? 0 : 0.8 },
8659
+ initial: reducedMotion ? { scale: 1 } : { scale: 0.95, rotate: -180, opacity: 0 },
8660
+ animate: reducedMotion ? { scale: 1 } : { scale: 1, rotate: 0, opacity: 1 },
8661
+ transition: {
8662
+ type: "spring",
8663
+ stiffness: 200,
8664
+ damping: 15,
8665
+ delay: reducedMotion ? 0 : 0.2
8666
+ },
8270
8667
  style: {
8271
- marginBottom: theme.space[8],
8272
- padding: theme.space[4],
8273
- background: theme.semantic.surface.inset,
8274
- border: `1px dashed ${theme.semantic.border.default}`,
8275
- borderRadius: theme.radius.lg,
8276
- textAlign: "left"
8668
+ marginBottom: theme.space[6],
8669
+ display: "inline-flex",
8670
+ alignItems: "center",
8671
+ justifyContent: "center",
8672
+ width: 96,
8673
+ height: 96,
8674
+ borderRadius: theme.radius.pill,
8675
+ background: titleIntent.soft,
8676
+ border: `3px solid ${titleIntent.border}`,
8677
+ boxShadow: theme.elevation.lifted
8277
8678
  },
8679
+ children: /* @__PURE__ */ jsx37(
8680
+ Trophy,
8681
+ {
8682
+ width: 48,
8683
+ height: 48,
8684
+ strokeWidth: 2.5,
8685
+ "aria-hidden": "true",
8686
+ style: { color: titleIntent.solid }
8687
+ }
8688
+ )
8689
+ }
8690
+ ),
8691
+ /* @__PURE__ */ jsxs20(
8692
+ motion9.div,
8693
+ {
8694
+ initial: reducedMotion ? { opacity: 0 } : { opacity: 0, y: 10 },
8695
+ animate: reducedMotion ? { opacity: 1 } : { opacity: 1, y: 0 },
8696
+ transition: { delay: reducedMotion ? 0 : 0.4 },
8278
8697
  children: [
8279
- /* @__PURE__ */ jsxs19(
8280
- "h3",
8698
+ /* @__PURE__ */ jsx37(
8699
+ "h2",
8281
8700
  {
8701
+ "aria-hidden": "true",
8282
8702
  style: {
8283
8703
  margin: 0,
8284
- marginBottom: theme.space[3],
8704
+ marginBottom: theme.space[2],
8705
+ color: theme.semantic.text.primary,
8285
8706
  fontFamily: theme.typography.fontFamily.display,
8286
- fontSize: theme.typography.fontSize.md,
8707
+ fontSize: theme.typography.fontSize["3xl"],
8287
8708
  fontWeight: theme.typography.fontWeight.bold,
8288
- color: theme.semantic.text.primary,
8289
- display: "flex",
8290
- alignItems: "center",
8291
- gap: theme.space[2]
8709
+ lineHeight: theme.typography.lineHeight.tight
8292
8710
  },
8293
- children: [
8294
- /* @__PURE__ */ jsx36(
8295
- "span",
8296
- {
8297
- style: {
8298
- width: 8,
8299
- height: 8,
8300
- background: theme.semantic.intent.primary.solid,
8301
- borderRadius: theme.radius.pill,
8302
- display: "inline-block"
8303
- }
8304
- }
8305
- ),
8306
- "Score Breakdown"
8307
- ]
8711
+ children: title
8308
8712
  }
8309
8713
  ),
8310
- /* @__PURE__ */ jsx36(
8311
- "div",
8714
+ /* @__PURE__ */ jsx37(
8715
+ "p",
8312
8716
  {
8313
8717
  style: {
8314
- display: "flex",
8315
- flexDirection: "column",
8316
- gap: theme.space[2]
8718
+ margin: 0,
8719
+ marginBottom: theme.space[6],
8720
+ display: "inline-block",
8721
+ ...chipStyle(theme, { variant: "secondary", size: "md" }),
8722
+ fontSize: theme.typography.fontSize.sm
8317
8723
  },
8318
- children: Object.entries(winner.details).map(([key, value]) => /* @__PURE__ */ jsxs19(
8319
- "div",
8320
- {
8321
- style: {
8322
- display: "flex",
8323
- justifyContent: "space-between",
8324
- fontSize: theme.typography.fontSize.md,
8325
- color: theme.semantic.text.primary
8326
- },
8327
- children: [
8328
- /* @__PURE__ */ jsx36("span", { style: { textTransform: "capitalize" }, children: key.replace(/([A-Z])/g, " $1") }),
8329
- /* @__PURE__ */ jsx36(
8330
- "span",
8331
- {
8332
- style: {
8333
- fontFamily: theme.typography.fontFamily.tabular,
8334
- fontWeight: theme.typography.fontWeight.bold
8335
- },
8336
- children: value
8337
- }
8338
- )
8339
- ]
8340
- },
8341
- key
8342
- ))
8724
+ children: message
8343
8725
  }
8344
8726
  )
8345
8727
  ]
8346
8728
  }
8347
8729
  ),
8348
- onReturnToLobby && /* @__PURE__ */ jsx36(
8730
+ /* @__PURE__ */ jsx37(
8731
+ motion9.div,
8732
+ {
8733
+ initial: { opacity: 0 },
8734
+ animate: { opacity: 1 },
8735
+ transition: { delay: reducedMotion ? 0 : 0.6 },
8736
+ style: {
8737
+ marginBottom: onReturnToLobby ? theme.space[8] : 0,
8738
+ textAlign: "left"
8739
+ },
8740
+ children: /* @__PURE__ */ jsx37(StandingsTable, { rows: outcome.standings, playerName })
8741
+ }
8742
+ ),
8743
+ onReturnToLobby && /* @__PURE__ */ jsx37(
8349
8744
  motion9.div,
8350
8745
  {
8351
8746
  initial: reducedMotion ? { opacity: 0 } : { opacity: 0, y: 10 },
8352
8747
  animate: reducedMotion ? { opacity: 1 } : { opacity: 1, y: 0 },
8353
8748
  transition: { delay: reducedMotion ? 0 : 1 },
8354
8749
  style: { display: "flex", justifyContent: "center" },
8355
- children: /* @__PURE__ */ jsxs19(
8750
+ children: /* @__PURE__ */ jsxs20(
8356
8751
  ThemedButton,
8357
8752
  {
8358
8753
  type: "button",
@@ -8363,7 +8758,7 @@ function GameEndDisplay({
8363
8758
  gap: theme.space[2]
8364
8759
  },
8365
8760
  children: [
8366
- /* @__PURE__ */ jsx36(Home, { size: 20, strokeWidth: 3, "aria-hidden": "true" }),
8761
+ /* @__PURE__ */ jsx37(Home, { size: 20, strokeWidth: 3, "aria-hidden": "true" }),
8367
8762
  "Return to Lobby"
8368
8763
  ]
8369
8764
  }
@@ -8375,6 +8770,240 @@ function GameEndDisplay({
8375
8770
  ) });
8376
8771
  }
8377
8772
 
8773
+ // src/ui/components/GameEventLog.tsx
8774
+ import { Activity, ChevronDown as ChevronDown2 } from "lucide-react";
8775
+ import { useId as useId7 } from "react";
8776
+ import { jsx as jsx38, jsxs as jsxs21 } from "react/jsx-runtime";
8777
+ function formatDetailValue(value) {
8778
+ if (typeof value === "boolean") return value ? "Yes" : "No";
8779
+ return String(value);
8780
+ }
8781
+ function eventKey(event) {
8782
+ return `${event.version}:${event.index}`;
8783
+ }
8784
+ function SystemActionSummary({
8785
+ event,
8786
+ className,
8787
+ style
8788
+ }) {
8789
+ const theme = useTheme();
8790
+ const titleId = useId7();
8791
+ const summaryId = useId7();
8792
+ return /* @__PURE__ */ jsxs21(
8793
+ "article",
8794
+ {
8795
+ className,
8796
+ "aria-labelledby": titleId,
8797
+ "aria-describedby": event.summary ? summaryId : void 0,
8798
+ style: {
8799
+ ...eventItemStyle(theme),
8800
+ ...style
8801
+ },
8802
+ children: [
8803
+ /* @__PURE__ */ jsx38(
8804
+ Activity,
8805
+ {
8806
+ "aria-hidden": "true",
8807
+ size: 18,
8808
+ strokeWidth: 2.5,
8809
+ style: {
8810
+ color: theme.semantic.intent.info.solid,
8811
+ flex: "0 0 auto",
8812
+ marginTop: 2
8813
+ }
8814
+ }
8815
+ ),
8816
+ /* @__PURE__ */ jsxs21("div", { style: { display: "grid", gap: theme.space[2], minWidth: 0 }, children: [
8817
+ /* @__PURE__ */ jsxs21("div", { style: { display: "grid", gap: theme.space[1] }, children: [
8818
+ /* @__PURE__ */ jsx38("h3", { id: titleId, style: eventTitleStyle(theme), children: event.title }),
8819
+ event.summary ? /* @__PURE__ */ jsx38("p", { id: summaryId, style: eventBodyStyle(theme), children: event.summary }) : null
8820
+ ] }),
8821
+ event.details && event.details.length > 0 ? /* @__PURE__ */ jsx38("dl", { style: detailGridStyle(theme), children: event.details.map((detail, index) => /* @__PURE__ */ jsxs21(
8822
+ "div",
8823
+ {
8824
+ style: {
8825
+ display: "flex",
8826
+ justifyContent: "space-between",
8827
+ gap: theme.space[3],
8828
+ minWidth: 0
8829
+ },
8830
+ children: [
8831
+ /* @__PURE__ */ jsx38("dt", { style: detailLabelStyle(theme), children: detail.label }),
8832
+ /* @__PURE__ */ jsx38("dd", { style: detailValueStyle(theme), children: formatDetailValue(detail.value) })
8833
+ ]
8834
+ },
8835
+ `${detail.label}:${index}`
8836
+ )) }) : null
8837
+ ] })
8838
+ ]
8839
+ }
8840
+ );
8841
+ }
8842
+ function GameEventLog({
8843
+ events,
8844
+ empty = "No automated actions yet.",
8845
+ maxVisible,
8846
+ className,
8847
+ style
8848
+ }) {
8849
+ const theme = useTheme();
8850
+ const titleId = useId7();
8851
+ const visibleEvents = maxVisible === void 0 ? events : events.slice(0, maxVisible);
8852
+ const hiddenCount = Math.max(0, events.length - visibleEvents.length);
8853
+ return /* @__PURE__ */ jsxs21(
8854
+ "section",
8855
+ {
8856
+ className,
8857
+ "aria-labelledby": titleId,
8858
+ style: {
8859
+ ...logContainerStyle(theme),
8860
+ ...style
8861
+ },
8862
+ children: [
8863
+ /* @__PURE__ */ jsxs21("header", { style: logHeaderStyle(theme), children: [
8864
+ /* @__PURE__ */ jsx38("h2", { id: titleId, style: logTitleStyle(theme), children: "Automated actions" }),
8865
+ /* @__PURE__ */ jsx38("span", { style: logCountStyle(theme), children: events.length })
8866
+ ] }),
8867
+ visibleEvents.length === 0 ? /* @__PURE__ */ jsx38("p", { style: emptyStyle(theme), children: empty }) : /* @__PURE__ */ jsx38(
8868
+ "ol",
8869
+ {
8870
+ "aria-live": "polite",
8871
+ style: {
8872
+ display: "grid",
8873
+ gap: theme.space[2],
8874
+ margin: 0,
8875
+ padding: 0,
8876
+ listStyle: "none"
8877
+ },
8878
+ children: visibleEvents.map((event) => /* @__PURE__ */ jsx38("li", { children: /* @__PURE__ */ jsx38(SystemActionSummary, { event }) }, eventKey(event)))
8879
+ }
8880
+ ),
8881
+ hiddenCount > 0 ? /* @__PURE__ */ jsxs21("div", { style: moreStyle(theme), children: [
8882
+ /* @__PURE__ */ jsx38(ChevronDown2, { "aria-hidden": "true", size: 16 }),
8883
+ /* @__PURE__ */ jsxs21("span", { children: [
8884
+ hiddenCount,
8885
+ " earlier actions hidden"
8886
+ ] })
8887
+ ] }) : null
8888
+ ]
8889
+ }
8890
+ );
8891
+ }
8892
+ function logContainerStyle(theme) {
8893
+ return {
8894
+ ...surfaceStyle(theme, { tone: "card" }),
8895
+ display: "grid",
8896
+ gap: theme.space[3],
8897
+ padding: theme.space[4],
8898
+ borderRadius: theme.radius.lg,
8899
+ border: `1px solid ${theme.semantic.border.subtle}`,
8900
+ minWidth: 0
8901
+ };
8902
+ }
8903
+ function logHeaderStyle(theme) {
8904
+ return {
8905
+ display: "flex",
8906
+ justifyContent: "space-between",
8907
+ alignItems: "center",
8908
+ gap: theme.space[3],
8909
+ minWidth: 0
8910
+ };
8911
+ }
8912
+ function logTitleStyle(theme) {
8913
+ return {
8914
+ margin: 0,
8915
+ color: theme.semantic.text.primary,
8916
+ fontSize: theme.typography.fontSize.lg,
8917
+ fontWeight: theme.typography.fontWeight.bold
8918
+ };
8919
+ }
8920
+ function logCountStyle(theme) {
8921
+ return {
8922
+ minWidth: 28,
8923
+ height: 28,
8924
+ display: "inline-flex",
8925
+ alignItems: "center",
8926
+ justifyContent: "center",
8927
+ borderRadius: theme.radius.pill,
8928
+ background: theme.semantic.intent.info.soft,
8929
+ color: theme.semantic.intent.info.onSoft,
8930
+ fontFamily: theme.typography.fontFamily.tabular,
8931
+ fontSize: theme.typography.fontSize.sm,
8932
+ fontWeight: theme.typography.fontWeight.bold
8933
+ };
8934
+ }
8935
+ function eventItemStyle(theme) {
8936
+ return {
8937
+ display: "grid",
8938
+ gridTemplateColumns: "20px minmax(0, 1fr)",
8939
+ gap: theme.space[3],
8940
+ padding: theme.space[3],
8941
+ borderRadius: theme.radius.md,
8942
+ border: `1px solid ${theme.semantic.intent.info.border}`,
8943
+ background: theme.semantic.intent.info.soft,
8944
+ minWidth: 0
8945
+ };
8946
+ }
8947
+ function eventTitleStyle(theme) {
8948
+ return {
8949
+ margin: 0,
8950
+ color: theme.semantic.text.primary,
8951
+ fontSize: theme.typography.fontSize.sm,
8952
+ fontWeight: theme.typography.fontWeight.bold
8953
+ };
8954
+ }
8955
+ function eventBodyStyle(theme) {
8956
+ return {
8957
+ margin: 0,
8958
+ color: theme.semantic.text.muted,
8959
+ fontSize: theme.typography.fontSize.sm,
8960
+ lineHeight: theme.typography.lineHeight.normal
8961
+ };
8962
+ }
8963
+ function detailGridStyle(theme) {
8964
+ return {
8965
+ display: "grid",
8966
+ gap: theme.space[1],
8967
+ margin: 0,
8968
+ paddingTop: theme.space[2],
8969
+ borderTop: `1px solid ${theme.semantic.intent.info.border}`
8970
+ };
8971
+ }
8972
+ function detailLabelStyle(theme) {
8973
+ return {
8974
+ color: theme.semantic.text.muted,
8975
+ fontSize: theme.typography.fontSize.xs,
8976
+ minWidth: 0
8977
+ };
8978
+ }
8979
+ function detailValueStyle(theme) {
8980
+ return {
8981
+ margin: 0,
8982
+ color: theme.semantic.text.primary,
8983
+ fontFamily: theme.typography.fontFamily.tabular,
8984
+ fontSize: theme.typography.fontSize.xs,
8985
+ fontWeight: theme.typography.fontWeight.bold,
8986
+ textAlign: "right",
8987
+ minWidth: 0
8988
+ };
8989
+ }
8990
+ function emptyStyle(theme) {
8991
+ return {
8992
+ margin: 0,
8993
+ color: theme.semantic.text.muted,
8994
+ fontSize: theme.typography.fontSize.sm
8995
+ };
8996
+ }
8997
+ function moreStyle(theme) {
8998
+ return {
8999
+ display: "inline-flex",
9000
+ alignItems: "center",
9001
+ gap: theme.space[1],
9002
+ color: theme.semantic.text.muted,
9003
+ fontSize: theme.typography.fontSize.xs
9004
+ };
9005
+ }
9006
+
8378
9007
  // src/ui/components/board/NetworkGraph.tsx
8379
9008
  import { useMemo as useMemo11 } from "react";
8380
9009
  import { clsx as clsx16 } from "clsx";
@@ -8395,7 +9024,7 @@ function handleKeyboardActivation(event, onActivate, options) {
8395
9024
  }
8396
9025
 
8397
9026
  // src/ui/components/board/NetworkGraph.tsx
8398
- import { Fragment as Fragment5, jsx as jsx37, jsxs as jsxs20 } from "react/jsx-runtime";
9027
+ import { Fragment as Fragment5, jsx as jsx39, jsxs as jsxs22 } from "react/jsx-runtime";
8399
9028
  var EMPTY_NETWORK_EDGES = [];
8400
9029
  var EMPTY_NETWORK_PIECES = [];
8401
9030
  function DefaultNetworkNode({
@@ -8416,7 +9045,7 @@ function DefaultNetworkNode({
8416
9045
  const effectiveStroke = isSelected ? "#60a5fa" : isHighlighted ? "#4ade80" : stroke;
8417
9046
  const effectiveStrokeWidth = isSelected || isHighlighted ? 3 : strokeWidth;
8418
9047
  const displayLabel = label ? label.length > maxLabelLength ? label.slice(0, maxLabelLength - 1) + "\u2026" : label : void 0;
8419
- return /* @__PURE__ */ jsxs20(
9048
+ return /* @__PURE__ */ jsxs22(
8420
9049
  "g",
8421
9050
  {
8422
9051
  onClick,
@@ -8432,7 +9061,7 @@ function DefaultNetworkNode({
8432
9061
  tabIndex: onClick ? 0 : void 0,
8433
9062
  "aria-label": onClick ? label ?? "Network node" : void 0,
8434
9063
  children: [
8435
- /* @__PURE__ */ jsx37(
9064
+ /* @__PURE__ */ jsx39(
8436
9065
  "circle",
8437
9066
  {
8438
9067
  r: radius,
@@ -8441,7 +9070,7 @@ function DefaultNetworkNode({
8441
9070
  strokeWidth: effectiveStrokeWidth
8442
9071
  }
8443
9072
  ),
8444
- displayLabel && /* @__PURE__ */ jsx37(
9073
+ displayLabel && /* @__PURE__ */ jsx39(
8445
9074
  "text",
8446
9075
  {
8447
9076
  textAnchor: "middle",
@@ -8473,7 +9102,7 @@ function DefaultNetworkEdge({
8473
9102
  const effectiveWidth = isSelected || isHighlighted ? strokeWidth + 2 : strokeWidth;
8474
9103
  const midX = (from.x + to.x) / 2;
8475
9104
  const midY = (from.y + to.y) / 2;
8476
- return /* @__PURE__ */ jsxs20(
9105
+ return /* @__PURE__ */ jsxs22(
8477
9106
  "g",
8478
9107
  {
8479
9108
  onClick,
@@ -8489,7 +9118,7 @@ function DefaultNetworkEdge({
8489
9118
  tabIndex: onClick ? 0 : void 0,
8490
9119
  "aria-label": onClick ? label !== void 0 ? `Network edge ${label}` : "Network edge" : void 0,
8491
9120
  children: [
8492
- /* @__PURE__ */ jsx37(
9121
+ /* @__PURE__ */ jsx39(
8493
9122
  "line",
8494
9123
  {
8495
9124
  x1: from.x,
@@ -8501,8 +9130,8 @@ function DefaultNetworkEdge({
8501
9130
  strokeLinecap: "round"
8502
9131
  }
8503
9132
  ),
8504
- label !== void 0 && /* @__PURE__ */ jsxs20(Fragment5, { children: [
8505
- /* @__PURE__ */ jsx37(
9133
+ label !== void 0 && /* @__PURE__ */ jsxs22(Fragment5, { children: [
9134
+ /* @__PURE__ */ jsx39(
8506
9135
  "circle",
8507
9136
  {
8508
9137
  cx: midX,
@@ -8513,7 +9142,7 @@ function DefaultNetworkEdge({
8513
9142
  strokeWidth: 1
8514
9143
  }
8515
9144
  ),
8516
- /* @__PURE__ */ jsx37(
9145
+ /* @__PURE__ */ jsx39(
8517
9146
  "text",
8518
9147
  {
8519
9148
  x: midX,
@@ -8538,7 +9167,7 @@ function DefaultNetworkPiece({
8538
9167
  onClick,
8539
9168
  className
8540
9169
  }) {
8541
- return /* @__PURE__ */ jsx37(
9170
+ return /* @__PURE__ */ jsx39(
8542
9171
  "g",
8543
9172
  {
8544
9173
  onClick,
@@ -8547,7 +9176,7 @@ function DefaultNetworkPiece({
8547
9176
  role: onClick ? "button" : void 0,
8548
9177
  tabIndex: onClick ? 0 : void 0,
8549
9178
  "aria-label": onClick ? "Network piece" : void 0,
8550
- children: shape === "square" ? /* @__PURE__ */ jsx37(
9179
+ children: shape === "square" ? /* @__PURE__ */ jsx39(
8551
9180
  "rect",
8552
9181
  {
8553
9182
  x: -radius,
@@ -8558,7 +9187,7 @@ function DefaultNetworkPiece({
8558
9187
  stroke: "white",
8559
9188
  strokeWidth: 1.5
8560
9189
  }
8561
- ) : /* @__PURE__ */ jsx37("circle", { r: radius, fill: color, stroke: "white", strokeWidth: 1.5 })
9190
+ ) : /* @__PURE__ */ jsx39("circle", { r: radius, fill: color, stroke: "white", strokeWidth: 1.5 })
8562
9191
  }
8563
9192
  );
8564
9193
  }
@@ -8625,7 +9254,7 @@ function NetworkGraph({
8625
9254
  const viewBoxX = viewBoxParts[0] ?? 0;
8626
9255
  const viewBoxY = viewBoxParts[1] ?? 0;
8627
9256
  const viewBoxHeight = viewBoxParts[3] ?? 0;
8628
- return /* @__PURE__ */ jsxs20(
9257
+ return /* @__PURE__ */ jsxs22(
8629
9258
  "svg",
8630
9259
  {
8631
9260
  width,
@@ -8642,11 +9271,11 @@ function NetworkGraph({
8642
9271
  role: "img",
8643
9272
  "aria-label": "Network graph",
8644
9273
  children: [
8645
- /* @__PURE__ */ jsx37("g", { className: "network-edges", role: "list", "aria-label": "Network connections", children: edges.map((edge) => {
9274
+ /* @__PURE__ */ jsx39("g", { className: "network-edges", role: "list", "aria-label": "Network connections", children: edges.map((edge) => {
8646
9275
  const fromNode = nodeMap[edge.from];
8647
9276
  const toNode = nodeMap[edge.to];
8648
9277
  if (!fromNode || !toNode) return null;
8649
- return /* @__PURE__ */ jsx37(
9278
+ return /* @__PURE__ */ jsx39(
8650
9279
  "g",
8651
9280
  {
8652
9281
  role: "listitem",
@@ -8656,9 +9285,9 @@ function NetworkGraph({
8656
9285
  edge.id
8657
9286
  );
8658
9287
  }) }),
8659
- /* @__PURE__ */ jsx37("g", { className: "network-nodes", role: "list", "aria-label": "Network nodes", children: nodes.map((node) => {
9288
+ /* @__PURE__ */ jsx39("g", { className: "network-nodes", role: "list", "aria-label": "Network nodes", children: nodes.map((node) => {
8660
9289
  const nodePieces = piecesByNode[node.id] ?? [];
8661
- return /* @__PURE__ */ jsxs20(
9290
+ return /* @__PURE__ */ jsxs22(
8662
9291
  "g",
8663
9292
  {
8664
9293
  transform: `translate(${node.position.x}, ${node.position.y})`,
@@ -8666,11 +9295,11 @@ function NetworkGraph({
8666
9295
  "aria-label": node.label ?? node.id,
8667
9296
  children: [
8668
9297
  renderNode(node, nodePieces),
8669
- nodePieces.length > 0 && /* @__PURE__ */ jsx37("g", { className: "node-pieces", children: nodePieces.map((piece, i) => {
9298
+ nodePieces.length > 0 && /* @__PURE__ */ jsx39("g", { className: "node-pieces", children: nodePieces.map((piece, i) => {
8670
9299
  const angle = i / nodePieces.length * 2 * Math.PI - Math.PI / 2;
8671
9300
  const pieceX = Math.cos(angle) * (nodeRadius + 8);
8672
9301
  const pieceY = Math.sin(angle) * (nodeRadius + 8);
8673
- return /* @__PURE__ */ jsx37(
9302
+ return /* @__PURE__ */ jsx39(
8674
9303
  "g",
8675
9304
  {
8676
9305
  transform: `translate(${pieceX}, ${pieceY})`,
@@ -8684,12 +9313,12 @@ function NetworkGraph({
8684
9313
  node.id
8685
9314
  );
8686
9315
  }) }),
8687
- enablePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsxs20(
9316
+ enablePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsxs22(
8688
9317
  "g",
8689
9318
  {
8690
9319
  transform: `translate(${viewBoxX + 10}, ${viewBoxY + viewBoxHeight - 30})`,
8691
9320
  children: [
8692
- /* @__PURE__ */ jsx37(
9321
+ /* @__PURE__ */ jsx39(
8693
9322
  "rect",
8694
9323
  {
8695
9324
  x: 0,
@@ -8700,7 +9329,7 @@ function NetworkGraph({
8700
9329
  fill: "rgba(0,0,0,0.6)"
8701
9330
  }
8702
9331
  ),
8703
- /* @__PURE__ */ jsxs20("text", { x: 30, y: 14, textAnchor: "middle", fill: "white", fontSize: 12, children: [
9332
+ /* @__PURE__ */ jsxs22("text", { x: 30, y: 14, textAnchor: "middle", fill: "white", fontSize: 12, children: [
8704
9333
  Math.round(transform.zoom * 100),
8705
9334
  "%"
8706
9335
  ] })
@@ -8715,7 +9344,7 @@ function NetworkGraph({
8715
9344
  // src/ui/components/board/ZoneMap.tsx
8716
9345
  import { useMemo as useMemo12 } from "react";
8717
9346
  import { clsx as clsx17 } from "clsx";
8718
- import { jsx as jsx38, jsxs as jsxs21 } from "react/jsx-runtime";
9347
+ import { jsx as jsx40, jsxs as jsxs23 } from "react/jsx-runtime";
8719
9348
  var HIGHLIGHT_COLORS = {
8720
9349
  valid: "rgba(34, 197, 94, 0.4)",
8721
9350
  // Green
@@ -8768,7 +9397,7 @@ function DefaultZone({
8768
9397
  switch (zone.shape.type) {
8769
9398
  case "polygon":
8770
9399
  if (!zone.shape.points) return null;
8771
- return /* @__PURE__ */ jsx38(
9400
+ return /* @__PURE__ */ jsx40(
8772
9401
  "polygon",
8773
9402
  {
8774
9403
  points: zone.shape.points.map((p) => `${p.x},${p.y}`).join(" "),
@@ -8779,7 +9408,7 @@ function DefaultZone({
8779
9408
  );
8780
9409
  case "path":
8781
9410
  if (!zone.shape.path) return null;
8782
- return /* @__PURE__ */ jsx38(
9411
+ return /* @__PURE__ */ jsx40(
8783
9412
  "path",
8784
9413
  {
8785
9414
  d: zone.shape.path,
@@ -8790,7 +9419,7 @@ function DefaultZone({
8790
9419
  );
8791
9420
  case "circle":
8792
9421
  if (!zone.shape.center) return null;
8793
- return /* @__PURE__ */ jsx38(
9422
+ return /* @__PURE__ */ jsx40(
8794
9423
  "circle",
8795
9424
  {
8796
9425
  cx: zone.shape.center.x,
@@ -8805,7 +9434,7 @@ function DefaultZone({
8805
9434
  return null;
8806
9435
  }
8807
9436
  };
8808
- return /* @__PURE__ */ jsxs21(
9437
+ return /* @__PURE__ */ jsxs23(
8809
9438
  "g",
8810
9439
  {
8811
9440
  onClick,
@@ -8818,7 +9447,7 @@ function DefaultZone({
8818
9447
  tabIndex: onClick ? 0 : void 0,
8819
9448
  children: [
8820
9449
  renderShape(),
8821
- showLabel && zone.shape?.center && /* @__PURE__ */ jsx38(
9450
+ showLabel && zone.shape?.center && /* @__PURE__ */ jsx40(
8822
9451
  "text",
8823
9452
  {
8824
9453
  x: zone.shape.center.x,
@@ -8832,7 +9461,7 @@ function DefaultZone({
8832
9461
  children: zone.name
8833
9462
  }
8834
9463
  ),
8835
- showValue && zone.value !== void 0 && zone.shape?.center && /* @__PURE__ */ jsxs21(
9464
+ showValue && zone.value !== void 0 && zone.shape?.center && /* @__PURE__ */ jsxs23(
8836
9465
  "text",
8837
9466
  {
8838
9467
  x: zone.shape.center.x,
@@ -8878,19 +9507,19 @@ function DefaultZonePieces({
8878
9507
  });
8879
9508
  const owners = Object.keys(piecesByOwner);
8880
9509
  const startOffset = -((owners.length - 1) * spacing) / 2;
8881
- return /* @__PURE__ */ jsx38("g", { className: clsx17("zone-pieces", className), children: owners.map((owner, i) => {
9510
+ return /* @__PURE__ */ jsx40("g", { className: clsx17("zone-pieces", className), children: owners.map((owner, i) => {
8882
9511
  const ownerPieces = piecesByOwner[owner] || [];
8883
9512
  const totalCount = ownerPieces.reduce(
8884
9513
  (sum, p) => sum + (p.count || 1),
8885
9514
  0
8886
9515
  );
8887
9516
  const offsetX = startOffset + i * spacing;
8888
- return /* @__PURE__ */ jsxs21(
9517
+ return /* @__PURE__ */ jsxs23(
8889
9518
  "g",
8890
9519
  {
8891
9520
  transform: `translate(${centerX + offsetX}, ${centerY + yOffset})`,
8892
9521
  children: [
8893
- /* @__PURE__ */ jsx38(
9522
+ /* @__PURE__ */ jsx40(
8894
9523
  "circle",
8895
9524
  {
8896
9525
  r: radius,
@@ -8899,7 +9528,7 @@ function DefaultZonePieces({
8899
9528
  strokeWidth: 2
8900
9529
  }
8901
9530
  ),
8902
- /* @__PURE__ */ jsx38(
9531
+ /* @__PURE__ */ jsx40(
8903
9532
  "text",
8904
9533
  {
8905
9534
  textAnchor: "middle",
@@ -8926,7 +9555,7 @@ function DefaultZonePiece({
8926
9555
  className
8927
9556
  }) {
8928
9557
  const count = piece.count || 1;
8929
- return /* @__PURE__ */ jsxs21(
9558
+ return /* @__PURE__ */ jsxs23(
8930
9559
  "g",
8931
9560
  {
8932
9561
  transform: `translate(${x}, ${y})`,
@@ -8940,8 +9569,8 @@ function DefaultZonePiece({
8940
9569
  tabIndex: onClick ? 0 : void 0,
8941
9570
  "aria-label": `Piece ${piece.id}`,
8942
9571
  children: [
8943
- /* @__PURE__ */ jsx38("circle", { r: radius, fill: color, stroke: "white", strokeWidth: 2 }),
8944
- /* @__PURE__ */ jsx38(
9572
+ /* @__PURE__ */ jsx40("circle", { r: radius, fill: color, stroke: "white", strokeWidth: 2 }),
9573
+ /* @__PURE__ */ jsx40(
8945
9574
  "text",
8946
9575
  {
8947
9576
  textAnchor: "middle",
@@ -8994,7 +9623,7 @@ function ZoneMap({
8994
9623
  const viewBoxHeight = baseHeight / transform.zoom;
8995
9624
  const viewBoxX = (baseWidth - viewBoxWidth) / 2 - transform.pan.x;
8996
9625
  const viewBoxY = (baseHeight - viewBoxHeight) / 2 - transform.pan.y;
8997
- return /* @__PURE__ */ jsxs21(
9626
+ return /* @__PURE__ */ jsxs23(
8998
9627
  "svg",
8999
9628
  {
9000
9629
  width,
@@ -9011,17 +9640,17 @@ function ZoneMap({
9011
9640
  role: "img",
9012
9641
  "aria-label": "Zone map",
9013
9642
  children: [
9014
- backgroundImage && /* @__PURE__ */ jsx38("image", { href: backgroundImage, width, height }),
9015
- /* @__PURE__ */ jsx38("g", { className: "zones", role: "list", "aria-label": "Map zones", children: zones.map((zone) => {
9643
+ backgroundImage && /* @__PURE__ */ jsx40("image", { href: backgroundImage, width, height }),
9644
+ /* @__PURE__ */ jsx40("g", { className: "zones", role: "list", "aria-label": "Map zones", children: zones.map((zone) => {
9016
9645
  const zonePieces = piecesByZone[zone.id] || [];
9017
- return /* @__PURE__ */ jsx38("g", { children: renderZone(zone, zonePieces) }, zone.id);
9646
+ return /* @__PURE__ */ jsx40("g", { children: renderZone(zone, zonePieces) }, zone.id);
9018
9647
  }) }),
9019
- enablePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsxs21(
9648
+ enablePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsxs23(
9020
9649
  "g",
9021
9650
  {
9022
9651
  transform: `translate(${viewBoxX + 10}, ${viewBoxY + viewBoxHeight - 30})`,
9023
9652
  children: [
9024
- /* @__PURE__ */ jsx38(
9653
+ /* @__PURE__ */ jsx40(
9025
9654
  "rect",
9026
9655
  {
9027
9656
  x: 0,
@@ -9032,7 +9661,7 @@ function ZoneMap({
9032
9661
  fill: "rgba(0,0,0,0.6)"
9033
9662
  }
9034
9663
  ),
9035
- /* @__PURE__ */ jsxs21("text", { x: 30, y: 14, textAnchor: "middle", fill: "white", fontSize: 12, children: [
9664
+ /* @__PURE__ */ jsxs23("text", { x: 30, y: 14, textAnchor: "middle", fill: "white", fontSize: 12, children: [
9036
9665
  Math.round(transform.zoom * 100),
9037
9666
  "%"
9038
9667
  ] })
@@ -9047,7 +9676,7 @@ function ZoneMap({
9047
9676
  // src/ui/components/board/TrackBoard.tsx
9048
9677
  import { useMemo as useMemo13 } from "react";
9049
9678
  import { clsx as clsx18 } from "clsx";
9050
- import { jsx as jsx39, jsxs as jsxs22 } from "react/jsx-runtime";
9679
+ import { jsx as jsx41, jsxs as jsxs24 } from "react/jsx-runtime";
9051
9680
  function DefaultTrackSpace({
9052
9681
  space,
9053
9682
  size = 50,
@@ -9066,7 +9695,7 @@ function DefaultTrackSpace({
9066
9695
  const computedFill = isHighlighted ? "rgba(59, 130, 246, 0.3)" : fill;
9067
9696
  const computedStroke = isSelected ? "#3b82f6" : isHighlighted ? "#60a5fa" : stroke;
9068
9697
  const computedStrokeWidth = isHighlighted || isSelected ? 3 : strokeWidth;
9069
- return /* @__PURE__ */ jsxs22(
9698
+ return /* @__PURE__ */ jsxs24(
9070
9699
  "g",
9071
9700
  {
9072
9701
  onClick,
@@ -9078,7 +9707,7 @@ function DefaultTrackSpace({
9078
9707
  "aria-label": space.name || `Space ${space.index}`,
9079
9708
  tabIndex: onClick ? 0 : void 0,
9080
9709
  children: [
9081
- /* @__PURE__ */ jsx39(
9710
+ /* @__PURE__ */ jsx41(
9082
9711
  "rect",
9083
9712
  {
9084
9713
  x: -halfSize,
@@ -9091,7 +9720,7 @@ function DefaultTrackSpace({
9091
9720
  strokeWidth: computedStrokeWidth
9092
9721
  }
9093
9722
  ),
9094
- space.name ? /* @__PURE__ */ jsx39(
9723
+ space.name ? /* @__PURE__ */ jsx41(
9095
9724
  "text",
9096
9725
  {
9097
9726
  textAnchor: "middle",
@@ -9101,7 +9730,7 @@ function DefaultTrackSpace({
9101
9730
  fontWeight: "bold",
9102
9731
  children: space.name.length > 8 ? space.name.slice(0, 7) + "\u2026" : space.name
9103
9732
  }
9104
- ) : /* @__PURE__ */ jsx39(
9733
+ ) : /* @__PURE__ */ jsx41(
9105
9734
  "text",
9106
9735
  {
9107
9736
  textAnchor: "middle",
@@ -9112,9 +9741,9 @@ function DefaultTrackSpace({
9112
9741
  children: space.index
9113
9742
  }
9114
9743
  ),
9115
- showJumpIndicator && space.jumpTo && /* @__PURE__ */ jsxs22("g", { transform: `translate(${halfSize - 6}, ${-halfSize + 6})`, children: [
9116
- /* @__PURE__ */ jsx39("circle", { r: 6, fill: "#fbbf24" }),
9117
- /* @__PURE__ */ jsx39(
9744
+ showJumpIndicator && space.jumpTo && /* @__PURE__ */ jsxs24("g", { transform: `translate(${halfSize - 6}, ${-halfSize + 6})`, children: [
9745
+ /* @__PURE__ */ jsx41("circle", { r: 6, fill: "#fbbf24" }),
9746
+ /* @__PURE__ */ jsx41(
9118
9747
  "text",
9119
9748
  {
9120
9749
  textAnchor: "middle",
@@ -9145,7 +9774,7 @@ function DefaultTrackPiece({
9145
9774
  const offset = total > 1 ? spacing : 0;
9146
9775
  const px = Math.cos(angle) * offset;
9147
9776
  const py = Math.sin(angle) * offset;
9148
- return /* @__PURE__ */ jsx39(
9777
+ return /* @__PURE__ */ jsx41(
9149
9778
  "circle",
9150
9779
  {
9151
9780
  cx: px,
@@ -9173,7 +9802,7 @@ function DefaultTrackConnection({
9173
9802
  strokeWidth = 2,
9174
9803
  className
9175
9804
  }) {
9176
- return /* @__PURE__ */ jsx39(
9805
+ return /* @__PURE__ */ jsx41(
9177
9806
  "line",
9178
9807
  {
9179
9808
  x1: from.x,
@@ -9208,8 +9837,8 @@ function DefaultTrackJump({
9208
9837
  const endX = to.x - unitX * (spaceSize / 2 + 5);
9209
9838
  const endY = to.y - unitY * (spaceSize / 2 + 5);
9210
9839
  const markerId = `arrow-${isUp ? "up" : "down"}-${from.x}-${from.y}`;
9211
- return /* @__PURE__ */ jsxs22("g", { className, children: [
9212
- /* @__PURE__ */ jsx39("defs", { children: /* @__PURE__ */ jsx39(
9840
+ return /* @__PURE__ */ jsxs24("g", { className, children: [
9841
+ /* @__PURE__ */ jsx41("defs", { children: /* @__PURE__ */ jsx41(
9213
9842
  "marker",
9214
9843
  {
9215
9844
  id: markerId,
@@ -9218,10 +9847,10 @@ function DefaultTrackJump({
9218
9847
  refX: "9",
9219
9848
  refY: "3.5",
9220
9849
  orient: "auto",
9221
- children: /* @__PURE__ */ jsx39("polygon", { points: "0 0, 10 3.5, 0 7", fill: color })
9850
+ children: /* @__PURE__ */ jsx41("polygon", { points: "0 0, 10 3.5, 0 7", fill: color })
9222
9851
  }
9223
9852
  ) }),
9224
- /* @__PURE__ */ jsx39(
9853
+ /* @__PURE__ */ jsx41(
9225
9854
  "line",
9226
9855
  {
9227
9856
  x1: startX,
@@ -9285,7 +9914,7 @@ function TrackBoard({
9285
9914
  return nextSpaceIds.map((nextId) => {
9286
9915
  const targetSpace = spaceMap.get(nextId);
9287
9916
  if (!targetSpace) return null;
9288
- return /* @__PURE__ */ jsx39("g", { children: renderConnection(
9917
+ return /* @__PURE__ */ jsx41("g", { children: renderConnection(
9289
9918
  space.position,
9290
9919
  targetSpace.position,
9291
9920
  space,
@@ -9302,7 +9931,7 @@ function TrackBoard({
9302
9931
  if (!targetSpace) return [];
9303
9932
  const isUp = targetSpace.index > space.index;
9304
9933
  return [
9305
- /* @__PURE__ */ jsx39("g", { children: renderJump(
9934
+ /* @__PURE__ */ jsx41("g", { children: renderJump(
9306
9935
  space.position,
9307
9936
  targetSpace.position,
9308
9937
  space,
@@ -9318,7 +9947,7 @@ function TrackBoard({
9318
9947
  const viewBoxHeight = baseHeight / transform.zoom;
9319
9948
  const viewBoxX = (baseWidth - viewBoxWidth) / 2 - transform.pan.x;
9320
9949
  const viewBoxY = (baseHeight - viewBoxHeight) / 2 - transform.pan.y;
9321
- return /* @__PURE__ */ jsxs22(
9950
+ return /* @__PURE__ */ jsxs24(
9322
9951
  "svg",
9323
9952
  {
9324
9953
  width,
@@ -9335,11 +9964,11 @@ function TrackBoard({
9335
9964
  role: "img",
9336
9965
  "aria-label": "Track board",
9337
9966
  children: [
9338
- /* @__PURE__ */ jsx39("g", { className: "track-connections", children: renderConnections() }),
9339
- /* @__PURE__ */ jsx39("g", { className: "track-jumps", children: renderJumps() }),
9340
- /* @__PURE__ */ jsx39("g", { className: "track-spaces", role: "list", "aria-label": "Track spaces", children: spaces.map((space) => {
9967
+ /* @__PURE__ */ jsx41("g", { className: "track-connections", children: renderConnections() }),
9968
+ /* @__PURE__ */ jsx41("g", { className: "track-jumps", children: renderJumps() }),
9969
+ /* @__PURE__ */ jsx41("g", { className: "track-spaces", role: "list", "aria-label": "Track spaces", children: spaces.map((space) => {
9341
9970
  const spacePieces = piecesBySpace[space.id] || [];
9342
- return /* @__PURE__ */ jsx39(
9971
+ return /* @__PURE__ */ jsx41(
9343
9972
  "g",
9344
9973
  {
9345
9974
  transform: `translate(${space.position.x}, ${space.position.y})`,
@@ -9348,12 +9977,12 @@ function TrackBoard({
9348
9977
  space.id
9349
9978
  );
9350
9979
  }) }),
9351
- enablePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsxs22(
9980
+ enablePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsxs24(
9352
9981
  "g",
9353
9982
  {
9354
9983
  transform: `translate(${viewBoxX + 10}, ${viewBoxY + viewBoxHeight - 30})`,
9355
9984
  children: [
9356
- /* @__PURE__ */ jsx39(
9985
+ /* @__PURE__ */ jsx41(
9357
9986
  "rect",
9358
9987
  {
9359
9988
  x: 0,
@@ -9364,7 +9993,7 @@ function TrackBoard({
9364
9993
  fill: "rgba(0,0,0,0.6)"
9365
9994
  }
9366
9995
  ),
9367
- /* @__PURE__ */ jsxs22("text", { x: 30, y: 14, textAnchor: "middle", fill: "white", fontSize: 12, children: [
9996
+ /* @__PURE__ */ jsxs24("text", { x: 30, y: 14, textAnchor: "middle", fill: "white", fontSize: 12, children: [
9368
9997
  Math.round(transform.zoom * 100),
9369
9998
  "%"
9370
9999
  ] })
@@ -9380,7 +10009,7 @@ function TrackBoard({
9380
10009
  import { useMemo as useMemo14 } from "react";
9381
10010
  import { clsx as clsx19 } from "clsx";
9382
10011
  import { Users, Lock, Gift, Coins } from "lucide-react";
9383
- import { jsx as jsx40, jsxs as jsxs23 } from "react/jsx-runtime";
10012
+ import { jsx as jsx42, jsxs as jsxs25 } from "react/jsx-runtime";
9384
10013
  var EMPTY_SLOT_OCCUPANTS = [];
9385
10014
  function DefaultSlotItem({
9386
10015
  name,
@@ -9404,7 +10033,7 @@ function DefaultSlotItem({
9404
10033
  const borderColor = isSelected ? theme.semantic.intent.primary.border : isFull ? theme.semantic.border.strong : isAvailable ? theme.semantic.border.default : theme.semantic.border.subtle;
9405
10034
  const background = isSelected ? theme.semantic.intent.primary.soft : isFull ? theme.semantic.surface.inset : theme.semantic.surface.card;
9406
10035
  const ringColor = isSelected ? theme.semantic.intent.primary.border : isHighlighted ? theme.semantic.intent.warning.border : void 0;
9407
- return /* @__PURE__ */ jsxs23(
10036
+ return /* @__PURE__ */ jsxs25(
9408
10037
  "div",
9409
10038
  {
9410
10039
  onClick: isAvailable ? onClick : void 0,
@@ -9426,9 +10055,9 @@ function DefaultSlotItem({
9426
10055
  "aria-disabled": !isAvailable,
9427
10056
  tabIndex: isAvailable && onClick ? 0 : void 0,
9428
10057
  children: [
9429
- /* @__PURE__ */ jsxs23("div", { className: "flex items-start justify-between gap-2", children: [
9430
- /* @__PURE__ */ jsxs23("div", { children: [
9431
- /* @__PURE__ */ jsx40(
10058
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-start justify-between gap-2", children: [
10059
+ /* @__PURE__ */ jsxs25("div", { children: [
10060
+ /* @__PURE__ */ jsx42(
9432
10061
  "h3",
9433
10062
  {
9434
10063
  className: "font-bold",
@@ -9436,7 +10065,7 @@ function DefaultSlotItem({
9436
10065
  children: name
9437
10066
  }
9438
10067
  ),
9439
- description && /* @__PURE__ */ jsx40(
10068
+ description && /* @__PURE__ */ jsx42(
9440
10069
  "p",
9441
10070
  {
9442
10071
  className: "text-xs mt-0.5",
@@ -9445,8 +10074,8 @@ function DefaultSlotItem({
9445
10074
  }
9446
10075
  )
9447
10076
  ] }),
9448
- /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-1", children: [
9449
- isExclusive && /* @__PURE__ */ jsx40(
10077
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-1", children: [
10078
+ isExclusive && /* @__PURE__ */ jsx42(
9450
10079
  Lock,
9451
10080
  {
9452
10081
  className: "w-4 h-4",
@@ -9454,46 +10083,46 @@ function DefaultSlotItem({
9454
10083
  "aria-label": "Exclusive slot"
9455
10084
  }
9456
10085
  ),
9457
- capacity > 1 && /* @__PURE__ */ jsxs23(
10086
+ capacity > 1 && /* @__PURE__ */ jsxs25(
9458
10087
  "div",
9459
10088
  {
9460
10089
  className: "flex items-center gap-0.5 text-xs",
9461
10090
  style: { color: theme.semantic.text.muted },
9462
10091
  title: `Capacity: ${capacity}`,
9463
10092
  children: [
9464
- /* @__PURE__ */ jsx40(Users, { className: "w-3 h-3" }),
9465
- /* @__PURE__ */ jsx40("span", { children: capacity })
10093
+ /* @__PURE__ */ jsx42(Users, { className: "w-3 h-3" }),
10094
+ /* @__PURE__ */ jsx42("span", { children: capacity })
9466
10095
  ]
9467
10096
  }
9468
10097
  )
9469
10098
  ] })
9470
10099
  ] }),
9471
- (costLabel || rewardLabel) && /* @__PURE__ */ jsxs23("div", { className: "mt-2 flex flex-wrap gap-2 text-xs", children: [
9472
- costLabel && /* @__PURE__ */ jsxs23(
10100
+ (costLabel || rewardLabel) && /* @__PURE__ */ jsxs25("div", { className: "mt-2 flex flex-wrap gap-2 text-xs", children: [
10101
+ costLabel && /* @__PURE__ */ jsxs25(
9473
10102
  "div",
9474
10103
  {
9475
10104
  className: "flex items-center gap-1",
9476
10105
  style: { color: theme.semantic.intent.danger.solid },
9477
10106
  children: [
9478
- /* @__PURE__ */ jsx40(Coins, { className: "w-3 h-3", "aria-hidden": "true" }),
9479
- /* @__PURE__ */ jsx40("span", { children: costLabel })
10107
+ /* @__PURE__ */ jsx42(Coins, { className: "w-3 h-3", "aria-hidden": "true" }),
10108
+ /* @__PURE__ */ jsx42("span", { children: costLabel })
9480
10109
  ]
9481
10110
  }
9482
10111
  ),
9483
- rewardLabel && /* @__PURE__ */ jsxs23(
10112
+ rewardLabel && /* @__PURE__ */ jsxs25(
9484
10113
  "div",
9485
10114
  {
9486
10115
  className: "flex items-center gap-1",
9487
10116
  style: { color: theme.semantic.intent.success.solid },
9488
10117
  children: [
9489
- /* @__PURE__ */ jsx40(Gift, { className: "w-3 h-3", "aria-hidden": "true" }),
9490
- /* @__PURE__ */ jsx40("span", { children: rewardLabel })
10118
+ /* @__PURE__ */ jsx42(Gift, { className: "w-3 h-3", "aria-hidden": "true" }),
10119
+ /* @__PURE__ */ jsx42("span", { children: rewardLabel })
9491
10120
  ]
9492
10121
  }
9493
10122
  )
9494
10123
  ] }),
9495
- renderOccupants && /* @__PURE__ */ jsx40("div", { className: "mt-2", children: renderOccupants() }),
9496
- !isAvailable && !isFull && /* @__PURE__ */ jsx40(
10124
+ renderOccupants && /* @__PURE__ */ jsx42("div", { className: "mt-2", children: renderOccupants() }),
10125
+ !isAvailable && !isFull && /* @__PURE__ */ jsx42(
9497
10126
  "div",
9498
10127
  {
9499
10128
  className: "mt-2 text-xs",
@@ -9513,7 +10142,7 @@ function DefaultSlotOccupant({
9513
10142
  onClick,
9514
10143
  className
9515
10144
  }) {
9516
- return /* @__PURE__ */ jsx40(
10145
+ return /* @__PURE__ */ jsx42(
9517
10146
  "div",
9518
10147
  {
9519
10148
  onClick,
@@ -9541,7 +10170,7 @@ function DefaultEmptySlot({
9541
10170
  className
9542
10171
  }) {
9543
10172
  const theme = useTheme();
9544
- return /* @__PURE__ */ jsx40(
10173
+ return /* @__PURE__ */ jsx42(
9545
10174
  "div",
9546
10175
  {
9547
10176
  className: clsx19("rounded-full border-2 border-dashed", className),
@@ -9596,18 +10225,18 @@ function SlotSystem({
9596
10225
  }, [slots, layout]);
9597
10226
  const renderSlotItem = (slot) => {
9598
10227
  const slotOccupants = occupantsBySlot[slot.id] ?? [];
9599
- return /* @__PURE__ */ jsx40("div", { role: "listitem", "aria-label": slot.name, children: renderSlot(slot, slotOccupants) }, slot.id);
10228
+ return /* @__PURE__ */ jsx42("div", { role: "listitem", "aria-label": slot.name, children: renderSlot(slot, slotOccupants) }, slot.id);
9600
10229
  };
9601
10230
  const responsiveGridStyle = {
9602
10231
  display: "grid",
9603
10232
  gridTemplateColumns: `repeat(auto-fit, minmax(${minSlotWidth}px, 1fr))`,
9604
10233
  gap: "1rem"
9605
10234
  };
9606
- const wrapContent = (content) => /* @__PURE__ */ jsx40("div", { style: { width, height }, className: clsx19("slot-system", className), children: content });
10235
+ const wrapContent = (content) => /* @__PURE__ */ jsx42("div", { style: { width, height }, className: clsx19("slot-system", className), children: content });
9607
10236
  if (layout === "grouped" && slotGroups) {
9608
10237
  return wrapContent(
9609
- /* @__PURE__ */ jsx40("div", { className: "space-y-6", role: "list", children: Object.entries(slotGroups).map(([groupName, groupSlots]) => /* @__PURE__ */ jsxs23("div", { children: [
9610
- /* @__PURE__ */ jsx40(
10238
+ /* @__PURE__ */ jsx42("div", { className: "space-y-6", role: "list", children: Object.entries(slotGroups).map(([groupName, groupSlots]) => /* @__PURE__ */ jsxs25("div", { children: [
10239
+ /* @__PURE__ */ jsx42(
9611
10240
  "h3",
9612
10241
  {
9613
10242
  className: "text-lg font-semibold mb-3",
@@ -9615,17 +10244,17 @@ function SlotSystem({
9615
10244
  children: groupName
9616
10245
  }
9617
10246
  ),
9618
- /* @__PURE__ */ jsx40("div", { style: responsiveGridStyle, children: groupSlots.map(renderSlotItem) })
10247
+ /* @__PURE__ */ jsx42("div", { style: responsiveGridStyle, children: groupSlots.map(renderSlotItem) })
9619
10248
  ] }, groupName)) })
9620
10249
  );
9621
10250
  }
9622
10251
  if (layout === "list") {
9623
10252
  return wrapContent(
9624
- /* @__PURE__ */ jsx40("div", { className: "flex flex-col gap-2", role: "list", children: slots.map(renderSlotItem) })
10253
+ /* @__PURE__ */ jsx42("div", { className: "flex flex-col gap-2", role: "list", children: slots.map(renderSlotItem) })
9625
10254
  );
9626
10255
  }
9627
10256
  return wrapContent(
9628
- /* @__PURE__ */ jsx40("div", { style: responsiveGridStyle, role: "list", children: slots.map(renderSlotItem) })
10257
+ /* @__PURE__ */ jsx42("div", { style: responsiveGridStyle, role: "list", children: slots.map(renderSlotItem) })
9629
10258
  );
9630
10259
  }
9631
10260
 
@@ -9747,7 +10376,7 @@ function isInteractiveTargetSelectable(layer, state) {
9747
10376
  }
9748
10377
 
9749
10378
  // src/ui/components/board/tiled-grid/interactive-layer.tsx
9750
- import { jsx as jsx41 } from "react/jsx-runtime";
10379
+ import { jsx as jsx43 } from "react/jsx-runtime";
9751
10380
  function InteractiveTargetLayerGroup({
9752
10381
  layer,
9753
10382
  targets,
@@ -9756,14 +10385,14 @@ function InteractiveTargetLayerGroup({
9756
10385
  groupClassName,
9757
10386
  groupAriaLabel,
9758
10387
  groupRole,
9759
- spreadBrowserAttributes,
10388
+ browserAttributeOrder,
9760
10389
  selectMode,
9761
10390
  hover,
9762
10391
  getTargetTransform,
9763
10392
  renderTargetContent
9764
10393
  }) {
9765
10394
  const { hoveredTargetId, setHoveredTargetId } = hover;
9766
- return /* @__PURE__ */ jsx41("g", { className: groupClassName, role: groupRole, "aria-label": groupAriaLabel, children: targets.map((target) => {
10395
+ return /* @__PURE__ */ jsx43("g", { className: groupClassName, role: groupRole, "aria-label": groupAriaLabel, children: targets.map((target) => {
9767
10396
  const targetId = getTargetId(target);
9768
10397
  const state = interactiveTargetRenderState(
9769
10398
  layer,
@@ -9776,11 +10405,11 @@ function InteractiveTargetLayerGroup({
9776
10405
  } : () => {
9777
10406
  void layer.selectTargetId?.(targetId);
9778
10407
  };
9779
- return spreadBrowserAttributes ? (
10408
+ return browserAttributeOrder === "before-transform" ? (
9780
10409
  // HexGrid markup variant: browserAttributes spread first, then
9781
10410
  // transform, role, className (preserves HexGrid's rendered
9782
10411
  // attribute order).
9783
- /* @__PURE__ */ jsx41(
10412
+ /* @__PURE__ */ jsx43(
9784
10413
  "g",
9785
10414
  {
9786
10415
  ...state.browserAttributes,
@@ -9803,13 +10432,14 @@ function InteractiveTargetLayerGroup({
9803
10432
  targetId
9804
10433
  )
9805
10434
  ) : (
9806
- // SquareGrid markup variant: no browserAttributes spread;
9807
- // transform, className, role (preserves SquareGrid's rendered
9808
- // attribute order).
9809
- /* @__PURE__ */ jsx41(
10435
+ // SquareGrid markup variant: transform first, then browser
10436
+ // attributes, className, role (preserves SquareGrid's rendered
10437
+ // attribute order while exposing semantic replay metadata).
10438
+ /* @__PURE__ */ jsx43(
9810
10439
  "g",
9811
10440
  {
9812
10441
  ...getTargetTransform ? { transform: getTargetTransform(target) } : {},
10442
+ ...state.browserAttributes,
9813
10443
  onClick: isSelectable ? activate : void 0,
9814
10444
  onKeyDown: (event) => handleKeyboardActivation(
9815
10445
  event,
@@ -9837,7 +10467,7 @@ function resolveBoardProp(props, buildInlineBoard) {
9837
10467
  }
9838
10468
 
9839
10469
  // src/ui/components/board/SquareGrid.tsx
9840
- import { Fragment as Fragment6, jsx as jsx42, jsxs as jsxs24 } from "react/jsx-runtime";
10470
+ import { Fragment as Fragment6, jsx as jsx44, jsxs as jsxs26 } from "react/jsx-runtime";
9841
10471
  function DefaultGridCell({
9842
10472
  size,
9843
10473
  isLight = true,
@@ -9855,7 +10485,7 @@ function DefaultGridCell({
9855
10485
  className
9856
10486
  }) {
9857
10487
  const baseColor = isLight ? lightColor : darkColor;
9858
- return /* @__PURE__ */ jsxs24(
10488
+ return /* @__PURE__ */ jsxs26(
9859
10489
  "g",
9860
10490
  {
9861
10491
  onClick,
@@ -9871,8 +10501,8 @@ function DefaultGridCell({
9871
10501
  tabIndex: onClick ? 0 : void 0,
9872
10502
  "aria-label": onClick ? "Grid cell" : void 0,
9873
10503
  children: [
9874
- /* @__PURE__ */ jsx42("rect", { width: size, height: size, fill: baseColor }),
9875
- isSelected && /* @__PURE__ */ jsx42(
10504
+ /* @__PURE__ */ jsx44("rect", { width: size, height: size, fill: baseColor }),
10505
+ isSelected && /* @__PURE__ */ jsx44(
9876
10506
  "rect",
9877
10507
  {
9878
10508
  width: size,
@@ -9881,7 +10511,7 @@ function DefaultGridCell({
9881
10511
  pointerEvents: "none"
9882
10512
  }
9883
10513
  ),
9884
- isHighlighted && !isSelected && /* @__PURE__ */ jsx42(
10514
+ isHighlighted && !isSelected && /* @__PURE__ */ jsx44(
9885
10515
  "rect",
9886
10516
  {
9887
10517
  width: size,
@@ -9890,7 +10520,7 @@ function DefaultGridCell({
9890
10520
  pointerEvents: "none"
9891
10521
  }
9892
10522
  ),
9893
- isValidMove && !isCapture && /* @__PURE__ */ jsx42(
10523
+ isValidMove && !isCapture && /* @__PURE__ */ jsx44(
9894
10524
  "circle",
9895
10525
  {
9896
10526
  cx: size / 2,
@@ -9900,7 +10530,7 @@ function DefaultGridCell({
9900
10530
  pointerEvents: "none"
9901
10531
  }
9902
10532
  ),
9903
- isCapture && /* @__PURE__ */ jsx42(
10533
+ isCapture && /* @__PURE__ */ jsx44(
9904
10534
  "circle",
9905
10535
  {
9906
10536
  cx: size / 2,
@@ -9928,7 +10558,7 @@ function DefaultGridPiece({
9928
10558
  }) {
9929
10559
  const radius = size * 0.38;
9930
10560
  const effectiveStroke = strokeColor ?? (color === "#f8fafc" || color === "#ffffff" ? "#1e293b" : "#f8fafc");
9931
- return /* @__PURE__ */ jsxs24(
10561
+ return /* @__PURE__ */ jsxs26(
9932
10562
  "g",
9933
10563
  {
9934
10564
  onClick,
@@ -9944,7 +10574,7 @@ function DefaultGridPiece({
9944
10574
  tabIndex: onClick ? 0 : void 0,
9945
10575
  "aria-label": onClick ? label ?? "Grid piece" : void 0,
9946
10576
  children: [
9947
- /* @__PURE__ */ jsx42(
10577
+ /* @__PURE__ */ jsx44(
9948
10578
  "circle",
9949
10579
  {
9950
10580
  r: isDragging ? radius * 1.1 : radius,
@@ -9954,7 +10584,7 @@ function DefaultGridPiece({
9954
10584
  style: { filter: "drop-shadow(1px 2px 2px rgba(0,0,0,0.4))" }
9955
10585
  }
9956
10586
  ),
9957
- label && /* @__PURE__ */ jsx42(
10587
+ label && /* @__PURE__ */ jsx44(
9958
10588
  "text",
9959
10589
  {
9960
10590
  y: 4,
@@ -9999,7 +10629,7 @@ function DefaultChessPiece({
9999
10629
  const symbol = CHESS_SYMBOLS[owner]?.[type] ?? "?";
10000
10630
  const textColor = owner === "white" ? "#f8fafc" : "#1e293b";
10001
10631
  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))";
10002
- return /* @__PURE__ */ jsx42(
10632
+ return /* @__PURE__ */ jsx44(
10003
10633
  "g",
10004
10634
  {
10005
10635
  onClick,
@@ -10012,7 +10642,7 @@ function DefaultChessPiece({
10012
10642
  role: onClick ? "button" : void 0,
10013
10643
  tabIndex: onClick ? 0 : void 0,
10014
10644
  "aria-label": onClick ? `${owner} ${type}` : void 0,
10015
- children: /* @__PURE__ */ jsx42(
10645
+ children: /* @__PURE__ */ jsx44(
10016
10646
  "text",
10017
10647
  {
10018
10648
  textAnchor: "middle",
@@ -10269,7 +10899,7 @@ function SquareGridImpl(props) {
10269
10899
  bounds: { minX: 0, minY: 0, width: totalWidth, height: totalHeight },
10270
10900
  viewBoxMode: "static-when-disabled"
10271
10901
  });
10272
- return /* @__PURE__ */ jsxs24(
10902
+ return /* @__PURE__ */ jsxs26(
10273
10903
  "svg",
10274
10904
  {
10275
10905
  width: svgWidth,
@@ -10286,11 +10916,11 @@ function SquareGridImpl(props) {
10286
10916
  role: "img",
10287
10917
  "aria-label": `${rows}x${cols} game grid`,
10288
10918
  children: [
10289
- /* @__PURE__ */ jsx42("defs", { children: /* @__PURE__ */ jsx42("filter", { id: "pieceShadow", x: "-20%", y: "-20%", width: "140%", height: "140%", children: /* @__PURE__ */ jsx42("feDropShadow", { dx: "1", dy: "2", stdDeviation: "2", floodOpacity: "0.4" }) }) }),
10290
- /* @__PURE__ */ jsx42("g", { className: "cells", role: "list", "aria-label": "Grid cells", children: renderableCells.map(({ row, col }) => {
10919
+ /* @__PURE__ */ jsx44("defs", { children: /* @__PURE__ */ jsx44("filter", { id: "pieceShadow", x: "-20%", y: "-20%", width: "140%", height: "140%", children: /* @__PURE__ */ jsx44("feDropShadow", { dx: "1", dy: "2", stdDeviation: "2", floodOpacity: "0.4" }) }) }),
10920
+ /* @__PURE__ */ jsx44("g", { className: "cells", role: "list", "aria-label": "Grid cells", children: renderableCells.map(({ row, col }) => {
10291
10921
  const x = labelMargin + col * cellSize;
10292
10922
  const y = row * cellSize;
10293
- return /* @__PURE__ */ jsx42(
10923
+ return /* @__PURE__ */ jsx44(
10294
10924
  "g",
10295
10925
  {
10296
10926
  transform: `translate(${x}, ${y})`,
@@ -10301,7 +10931,7 @@ function SquareGridImpl(props) {
10301
10931
  `${row}-${col}`
10302
10932
  );
10303
10933
  }) }),
10304
- interactiveSpaces && /* @__PURE__ */ jsx42(
10934
+ interactiveSpaces && /* @__PURE__ */ jsx44(
10305
10935
  InteractiveTargetLayerGroup,
10306
10936
  {
10307
10937
  layer: interactiveSpaces,
@@ -10310,12 +10940,12 @@ function SquareGridImpl(props) {
10310
10940
  targetKind: "space",
10311
10941
  groupClassName: "interactive-spaces",
10312
10942
  groupAriaLabel: "Interactive spaces",
10313
- spreadBrowserAttributes: false,
10943
+ browserAttributeOrder: "after-transform",
10314
10944
  selectMode: "layer-direct",
10315
10945
  hover: spaceHover,
10316
10946
  getTargetTransform: (space) => `translate(${labelMargin + space.col * cellSize}, ${space.row * cellSize})`,
10317
- renderTargetContent: (space, state, isSelectable) => /* @__PURE__ */ jsxs24(Fragment6, { children: [
10318
- isSelectable && /* @__PURE__ */ jsx42(
10947
+ renderTargetContent: (space, state, isSelectable) => /* @__PURE__ */ jsxs26(Fragment6, { children: [
10948
+ isSelectable && /* @__PURE__ */ jsx44(
10319
10949
  "rect",
10320
10950
  {
10321
10951
  x: 0,
@@ -10330,8 +10960,8 @@ function SquareGridImpl(props) {
10330
10960
  ] })
10331
10961
  }
10332
10962
  ),
10333
- renderEdge && resolvedEdgePositions.length > 0 && /* @__PURE__ */ jsx42("g", { className: "edges", "aria-label": "Board edges", children: resolvedEdgePositions.map(({ edge, interactiveEdge }) => /* @__PURE__ */ jsx42("g", { children: renderEdge(edge, interactiveEdge.position) }, edge.id)) }),
10334
- interactiveEdges && /* @__PURE__ */ jsx42(
10963
+ renderEdge && resolvedEdgePositions.length > 0 && /* @__PURE__ */ jsx44("g", { className: "edges", "aria-label": "Board edges", children: resolvedEdgePositions.map(({ edge, interactiveEdge }) => /* @__PURE__ */ jsx44("g", { children: renderEdge(edge, interactiveEdge.position) }, edge.id)) }),
10964
+ interactiveEdges && /* @__PURE__ */ jsx44(
10335
10965
  InteractiveTargetLayerGroup,
10336
10966
  {
10337
10967
  layer: interactiveEdges,
@@ -10340,10 +10970,10 @@ function SquareGridImpl(props) {
10340
10970
  targetKind: "edge",
10341
10971
  groupClassName: "interactive-edges",
10342
10972
  groupAriaLabel: "Interactive edges",
10343
- spreadBrowserAttributes: false,
10973
+ browserAttributeOrder: "after-transform",
10344
10974
  selectMode: "layer-direct",
10345
10975
  hover: edgeHover,
10346
- renderTargetContent: ({ interactiveEdge: edge }, state) => renderInteractiveEdge ? renderInteractiveEdge(edge, edge.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx42(
10976
+ renderTargetContent: ({ interactiveEdge: edge }, state) => renderInteractiveEdge ? renderInteractiveEdge(edge, edge.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx44(
10347
10977
  "line",
10348
10978
  {
10349
10979
  x1: edge.position.x1,
@@ -10357,8 +10987,8 @@ function SquareGridImpl(props) {
10357
10987
  ) : null
10358
10988
  }
10359
10989
  ),
10360
- renderVertex && resolvedVertexPositions.length > 0 && /* @__PURE__ */ jsx42("g", { className: "vertices", "aria-label": "Board vertices", children: resolvedVertexPositions.map(({ vertex, interactiveVertex }) => /* @__PURE__ */ jsx42("g", { children: renderVertex(vertex, interactiveVertex.position) }, vertex.id)) }),
10361
- interactiveVertices && /* @__PURE__ */ jsx42(
10990
+ renderVertex && resolvedVertexPositions.length > 0 && /* @__PURE__ */ jsx44("g", { className: "vertices", "aria-label": "Board vertices", children: resolvedVertexPositions.map(({ vertex, interactiveVertex }) => /* @__PURE__ */ jsx44("g", { children: renderVertex(vertex, interactiveVertex.position) }, vertex.id)) }),
10991
+ interactiveVertices && /* @__PURE__ */ jsx44(
10362
10992
  InteractiveTargetLayerGroup,
10363
10993
  {
10364
10994
  layer: interactiveVertices,
@@ -10367,10 +10997,10 @@ function SquareGridImpl(props) {
10367
10997
  targetKind: "vertex",
10368
10998
  groupClassName: "interactive-vertices",
10369
10999
  groupAriaLabel: "Interactive vertices",
10370
- spreadBrowserAttributes: false,
11000
+ browserAttributeOrder: "after-transform",
10371
11001
  selectMode: "layer-direct",
10372
11002
  hover: vertexHover,
10373
- renderTargetContent: ({ interactiveVertex: vertex }, state) => renderInteractiveVertex ? renderInteractiveVertex(vertex, vertex.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx42(
11003
+ renderTargetContent: ({ interactiveVertex: vertex }, state) => renderInteractiveVertex ? renderInteractiveVertex(vertex, vertex.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx44(
10374
11004
  "circle",
10375
11005
  {
10376
11006
  cx: vertex.position.x,
@@ -10382,10 +11012,10 @@ function SquareGridImpl(props) {
10382
11012
  ) : null
10383
11013
  }
10384
11014
  ),
10385
- showCoordinates && coordinateStyle !== "none" && /* @__PURE__ */ jsxs24("g", { className: "coordinates", "aria-hidden": "true", children: [
11015
+ showCoordinates && coordinateStyle !== "none" && /* @__PURE__ */ jsxs26("g", { className: "coordinates", "aria-hidden": "true", children: [
10386
11016
  Array.from({ length: cols }).map((_, col) => {
10387
11017
  const label = coordinateStyle === "algebraic" ? String.fromCharCode(97 + col) : String(col + 1);
10388
- return /* @__PURE__ */ jsx42(
11018
+ return /* @__PURE__ */ jsx44(
10389
11019
  "text",
10390
11020
  {
10391
11021
  x: labelMargin + col * cellSize + cellSize / 2,
@@ -10401,7 +11031,7 @@ function SquareGridImpl(props) {
10401
11031
  }),
10402
11032
  Array.from({ length: rows }).map((_, row) => {
10403
11033
  const label = coordinateStyle === "algebraic" ? String(rows - row) : String(row + 1);
10404
- return /* @__PURE__ */ jsx42(
11034
+ return /* @__PURE__ */ jsx44(
10405
11035
  "text",
10406
11036
  {
10407
11037
  x: 10,
@@ -10416,10 +11046,10 @@ function SquareGridImpl(props) {
10416
11046
  );
10417
11047
  })
10418
11048
  ] }),
10419
- /* @__PURE__ */ jsx42("g", { className: "pieces", role: "list", "aria-label": "Game pieces", children: resolvedPieces.map((piece) => {
11049
+ /* @__PURE__ */ jsx44("g", { className: "pieces", role: "list", "aria-label": "Game pieces", children: resolvedPieces.map((piece) => {
10420
11050
  const x = labelMargin + piece.col * cellSize + cellSize / 2;
10421
11051
  const y = piece.row * cellSize + cellSize / 2;
10422
- return /* @__PURE__ */ jsx42(
11052
+ return /* @__PURE__ */ jsx44(
10423
11053
  "g",
10424
11054
  {
10425
11055
  transform: `translate(${x}, ${y})`,
@@ -10430,7 +11060,7 @@ function SquareGridImpl(props) {
10430
11060
  piece.id
10431
11061
  );
10432
11062
  }) }),
10433
- enablePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsx42(
11063
+ enablePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsx44(
10434
11064
  GridZoomIndicator,
10435
11065
  {
10436
11066
  viewBoxX,
@@ -10448,7 +11078,7 @@ var SquareGrid = SquareGridImpl;
10448
11078
  // src/ui/components/board/HexGrid.tsx
10449
11079
  import { useMemo as useMemo16 } from "react";
10450
11080
  import { clsx as clsx22 } from "clsx";
10451
- import { Fragment as Fragment7, jsx as jsx43, jsxs as jsxs25 } from "react/jsx-runtime";
11081
+ import { Fragment as Fragment7, jsx as jsx45, jsxs as jsxs27 } from "react/jsx-runtime";
10452
11082
  function DefaultHexTile({
10453
11083
  size,
10454
11084
  fill,
@@ -10469,7 +11099,7 @@ function DefaultHexTile({
10469
11099
  const effectiveStroke = isSelected ? "#3b82f6" : isHighlighted ? "#22c55e" : stroke;
10470
11100
  const effectiveStrokeWidth = isSelected || isHighlighted ? 3 : strokeWidth;
10471
11101
  const points = hexUtils.getHexPoints(0, 0, size * 0.95, orientation);
10472
- return /* @__PURE__ */ jsxs25(
11102
+ return /* @__PURE__ */ jsxs27(
10473
11103
  "g",
10474
11104
  {
10475
11105
  onClick,
@@ -10485,7 +11115,7 @@ function DefaultHexTile({
10485
11115
  tabIndex: onClick ? 0 : void 0,
10486
11116
  "aria-label": onClick ? label ?? "Hex tile" : void 0,
10487
11117
  children: [
10488
- /* @__PURE__ */ jsx43(
11118
+ /* @__PURE__ */ jsx45(
10489
11119
  "polygon",
10490
11120
  {
10491
11121
  points,
@@ -10495,7 +11125,7 @@ function DefaultHexTile({
10495
11125
  filter: "url(#hexShadow)"
10496
11126
  }
10497
11127
  ),
10498
- label && /* @__PURE__ */ jsx43(
11128
+ label && /* @__PURE__ */ jsx45(
10499
11129
  "text",
10500
11130
  {
10501
11131
  x: 0,
@@ -10510,7 +11140,7 @@ function DefaultHexTile({
10510
11140
  children: label
10511
11141
  }
10512
11142
  ),
10513
- showCoordinates && coordinates && /* @__PURE__ */ jsxs25(
11143
+ showCoordinates && coordinates && /* @__PURE__ */ jsxs27(
10514
11144
  "text",
10515
11145
  {
10516
11146
  x: 0,
@@ -10544,7 +11174,7 @@ function DefaultHexEdge({
10544
11174
  position.x2 - position.x1,
10545
11175
  position.y2 - position.y1
10546
11176
  );
10547
- return /* @__PURE__ */ jsxs25(
11177
+ return /* @__PURE__ */ jsxs27(
10548
11178
  "g",
10549
11179
  {
10550
11180
  onClick,
@@ -10558,7 +11188,7 @@ function DefaultHexEdge({
10558
11188
  tabIndex: onClick ? 0 : void 0,
10559
11189
  "aria-label": onClick ? "Hex edge" : void 0,
10560
11190
  children: [
10561
- /* @__PURE__ */ jsx43(
11191
+ /* @__PURE__ */ jsx45(
10562
11192
  "rect",
10563
11193
  {
10564
11194
  x: position.midX - touchTargetLength / 2,
@@ -10571,7 +11201,7 @@ function DefaultHexEdge({
10571
11201
  pointerEvents: "all"
10572
11202
  }
10573
11203
  ),
10574
- /* @__PURE__ */ jsx43(
11204
+ /* @__PURE__ */ jsx45(
10575
11205
  "line",
10576
11206
  {
10577
11207
  x1: position.x1,
@@ -10607,7 +11237,7 @@ function DefaultHexVertex({
10607
11237
  const effectiveColor = isSelected ? "rgba(59, 130, 246, 0.8)" : isHighlighted ? "rgba(34, 197, 94, 0.8)" : color;
10608
11238
  const effectiveStroke = isSelected ? "#3b82f6" : isHighlighted ? "#22c55e" : stroke;
10609
11239
  const effectiveStrokeWidth = isSelected || isHighlighted ? 3 : strokeWidth;
10610
- return /* @__PURE__ */ jsxs25(
11240
+ return /* @__PURE__ */ jsxs27(
10611
11241
  "g",
10612
11242
  {
10613
11243
  onClick,
@@ -10624,7 +11254,7 @@ function DefaultHexVertex({
10624
11254
  tabIndex: onClick ? 0 : void 0,
10625
11255
  "aria-label": onClick ? "Hex vertex" : void 0,
10626
11256
  children: [
10627
- /* @__PURE__ */ jsx43(
11257
+ /* @__PURE__ */ jsx45(
10628
11258
  "circle",
10629
11259
  {
10630
11260
  cx: position.x,
@@ -10634,7 +11264,7 @@ function DefaultHexVertex({
10634
11264
  pointerEvents: "all"
10635
11265
  }
10636
11266
  ),
10637
- shape === "square" ? /* @__PURE__ */ jsx43(
11267
+ shape === "square" ? /* @__PURE__ */ jsx45(
10638
11268
  "rect",
10639
11269
  {
10640
11270
  x: position.x - size,
@@ -10646,7 +11276,7 @@ function DefaultHexVertex({
10646
11276
  strokeWidth: effectiveStrokeWidth,
10647
11277
  className: hasOwner ? "" : "opacity-30"
10648
11278
  }
10649
- ) : /* @__PURE__ */ jsx43(
11279
+ ) : /* @__PURE__ */ jsx45(
10650
11280
  "circle",
10651
11281
  {
10652
11282
  cx: position.x,
@@ -10670,7 +11300,7 @@ function DefaultInteractiveVertex({
10670
11300
  hoverColor = "rgba(34, 197, 94, 0.8)",
10671
11301
  className
10672
11302
  }) {
10673
- return /* @__PURE__ */ jsx43(
11303
+ return /* @__PURE__ */ jsx45(
10674
11304
  "circle",
10675
11305
  {
10676
11306
  cx: position.x,
@@ -10691,7 +11321,7 @@ function DefaultInteractiveEdge({
10691
11321
  hoverColor = "rgba(251, 146, 60, 0.8)",
10692
11322
  className
10693
11323
  }) {
10694
- return /* @__PURE__ */ jsx43(
11324
+ return /* @__PURE__ */ jsx45(
10695
11325
  "line",
10696
11326
  {
10697
11327
  x1: position.x1,
@@ -10971,7 +11601,7 @@ function HexGridImpl(props) {
10971
11601
  bounds,
10972
11602
  viewBoxMode: "transformed"
10973
11603
  });
10974
- return /* @__PURE__ */ jsxs25(
11604
+ return /* @__PURE__ */ jsxs27(
10975
11605
  "svg",
10976
11606
  {
10977
11607
  width,
@@ -10988,18 +11618,18 @@ function HexGridImpl(props) {
10988
11618
  role: "img",
10989
11619
  "aria-label": "Hex grid game board",
10990
11620
  children: [
10991
- /* @__PURE__ */ jsxs25("defs", { children: [
10992
- /* @__PURE__ */ jsxs25("linearGradient", { id: "oceanGradient", x1: "0%", y1: "0%", x2: "100%", y2: "100%", children: [
10993
- /* @__PURE__ */ jsx43("stop", { offset: "0%", stopColor: "#0ea5e9" }),
10994
- /* @__PURE__ */ jsx43("stop", { offset: "100%", stopColor: "#0284c7" })
11621
+ /* @__PURE__ */ jsxs27("defs", { children: [
11622
+ /* @__PURE__ */ jsxs27("linearGradient", { id: "oceanGradient", x1: "0%", y1: "0%", x2: "100%", y2: "100%", children: [
11623
+ /* @__PURE__ */ jsx45("stop", { offset: "0%", stopColor: "#0ea5e9" }),
11624
+ /* @__PURE__ */ jsx45("stop", { offset: "100%", stopColor: "#0284c7" })
10995
11625
  ] }),
10996
- /* @__PURE__ */ jsx43("filter", { id: "hexShadow", x: "-20%", y: "-20%", width: "140%", height: "140%", children: /* @__PURE__ */ jsx43("feDropShadow", { dx: "1", dy: "1", stdDeviation: "2", floodOpacity: "0.3" }) })
11626
+ /* @__PURE__ */ jsx45("filter", { id: "hexShadow", x: "-20%", y: "-20%", width: "140%", height: "140%", children: /* @__PURE__ */ jsx45("feDropShadow", { dx: "1", dy: "1", stdDeviation: "2", floodOpacity: "0.3" }) })
10997
11627
  ] }),
10998
- /* @__PURE__ */ jsx43("g", { className: "tiles", role: "list", "aria-label": "Hex tiles", children: resolvedTiles.map((tile) => {
11628
+ /* @__PURE__ */ jsx45("g", { className: "tiles", role: "list", "aria-label": "Hex tiles", children: resolvedTiles.map((tile) => {
10999
11629
  const pos = tilePositions.get(tile.id);
11000
11630
  if (!pos) return null;
11001
11631
  const geometry = buildTileGeometry(pos);
11002
- return /* @__PURE__ */ jsx43(
11632
+ return /* @__PURE__ */ jsx45(
11003
11633
  "g",
11004
11634
  {
11005
11635
  transform: `translate(${pos.x}, ${pos.y})`,
@@ -11010,7 +11640,7 @@ function HexGridImpl(props) {
11010
11640
  tile.id
11011
11641
  );
11012
11642
  }) }),
11013
- interactiveSpaces && resolvedTiles.length > 0 && /* @__PURE__ */ jsx43(
11643
+ interactiveSpaces && resolvedTiles.length > 0 && /* @__PURE__ */ jsx45(
11014
11644
  InteractiveTargetLayerGroup,
11015
11645
  {
11016
11646
  layer: interactiveSpaces,
@@ -11020,12 +11650,12 @@ function HexGridImpl(props) {
11020
11650
  groupClassName: "interactive-spaces",
11021
11651
  groupAriaLabel: "Interactive spaces",
11022
11652
  groupRole: "list",
11023
- spreadBrowserAttributes: true,
11653
+ browserAttributeOrder: "before-transform",
11024
11654
  selectMode: "render-state",
11025
11655
  hover: spaceHover,
11026
11656
  getTargetTransform: ({ pos }) => `translate(${pos.x}, ${pos.y})`,
11027
- renderTargetContent: ({ space, pos }, state, isSelectable) => /* @__PURE__ */ jsxs25(Fragment7, { children: [
11028
- isSelectable && /* @__PURE__ */ jsx43(
11657
+ renderTargetContent: ({ space, pos }, state, isSelectable) => /* @__PURE__ */ jsxs27(Fragment7, { children: [
11658
+ isSelectable && /* @__PURE__ */ jsx45(
11029
11659
  "polygon",
11030
11660
  {
11031
11661
  points: buildTileGeometry(pos).points({
@@ -11039,13 +11669,13 @@ function HexGridImpl(props) {
11039
11669
  ] })
11040
11670
  }
11041
11671
  ),
11042
- resolvedEdges.length > 0 && /* @__PURE__ */ jsx43("g", { className: "edges", role: "list", "aria-label": "Hex edges", children: resolvedEdgePositions.map(({ edge, interactiveEdge }) => {
11043
- return /* @__PURE__ */ jsx43("g", { role: "listitem", children: renderEdge(edge, interactiveEdge.position) }, edge.id);
11672
+ resolvedEdges.length > 0 && /* @__PURE__ */ jsx45("g", { className: "edges", role: "list", "aria-label": "Hex edges", children: resolvedEdgePositions.map(({ edge, interactiveEdge }) => {
11673
+ return /* @__PURE__ */ jsx45("g", { role: "listitem", children: renderEdge(edge, interactiveEdge.position) }, edge.id);
11044
11674
  }) }),
11045
- resolvedVertices.length > 0 && /* @__PURE__ */ jsx43("g", { className: "vertices", role: "list", "aria-label": "Hex vertices", children: resolvedVertexPositions.map(({ vertex, interactiveVertex }) => {
11046
- return /* @__PURE__ */ jsx43("g", { role: "listitem", children: renderVertex(vertex, interactiveVertex.position) }, vertex.id);
11675
+ resolvedVertices.length > 0 && /* @__PURE__ */ jsx45("g", { className: "vertices", role: "list", "aria-label": "Hex vertices", children: resolvedVertexPositions.map(({ vertex, interactiveVertex }) => {
11676
+ return /* @__PURE__ */ jsx45("g", { role: "listitem", children: renderVertex(vertex, interactiveVertex.position) }, vertex.id);
11047
11677
  }) }),
11048
- interactiveEdges && resolvedEdgePositions.length > 0 && /* @__PURE__ */ jsx43(
11678
+ interactiveEdges && resolvedEdgePositions.length > 0 && /* @__PURE__ */ jsx45(
11049
11679
  InteractiveTargetLayerGroup,
11050
11680
  {
11051
11681
  layer: interactiveEdges,
@@ -11055,7 +11685,7 @@ function HexGridImpl(props) {
11055
11685
  groupClassName: "interactive-edges",
11056
11686
  groupAriaLabel: "Interactive edges for placement",
11057
11687
  groupRole: "list",
11058
- spreadBrowserAttributes: true,
11688
+ browserAttributeOrder: "before-transform",
11059
11689
  selectMode: "render-state",
11060
11690
  hover: edgeHover,
11061
11691
  renderTargetContent: ({ interactiveEdge: edge }, state, isSelectable) => {
@@ -11063,8 +11693,8 @@ function HexGridImpl(props) {
11063
11693
  edge.position.x2 - edge.position.x1,
11064
11694
  edge.position.y2 - edge.position.y1
11065
11695
  );
11066
- return /* @__PURE__ */ jsxs25(Fragment7, { children: [
11067
- isSelectable && /* @__PURE__ */ jsx43(
11696
+ return /* @__PURE__ */ jsxs27(Fragment7, { children: [
11697
+ isSelectable && /* @__PURE__ */ jsx45(
11068
11698
  "rect",
11069
11699
  {
11070
11700
  x: edge.position.midX - touchTargetLength / 2,
@@ -11077,7 +11707,7 @@ function HexGridImpl(props) {
11077
11707
  pointerEvents: "all"
11078
11708
  }
11079
11709
  ),
11080
- renderInteractiveEdge ? renderInteractiveEdge(edge, edge.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx43(
11710
+ renderInteractiveEdge ? renderInteractiveEdge(edge, edge.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx45(
11081
11711
  DefaultInteractiveEdge,
11082
11712
  {
11083
11713
  position: edge.position,
@@ -11089,7 +11719,7 @@ function HexGridImpl(props) {
11089
11719
  }
11090
11720
  }
11091
11721
  ),
11092
- interactiveVertices && resolvedVertexPositions.length > 0 && /* @__PURE__ */ jsx43(
11722
+ interactiveVertices && resolvedVertexPositions.length > 0 && /* @__PURE__ */ jsx45(
11093
11723
  InteractiveTargetLayerGroup,
11094
11724
  {
11095
11725
  layer: interactiveVertices,
@@ -11099,11 +11729,11 @@ function HexGridImpl(props) {
11099
11729
  groupClassName: "interactive-vertices",
11100
11730
  groupAriaLabel: "Interactive vertices for placement",
11101
11731
  groupRole: "list",
11102
- spreadBrowserAttributes: true,
11732
+ browserAttributeOrder: "before-transform",
11103
11733
  selectMode: "render-state",
11104
11734
  hover: vertexHover,
11105
- renderTargetContent: ({ interactiveVertex: vertex }, state, isSelectable) => /* @__PURE__ */ jsxs25(Fragment7, { children: [
11106
- isSelectable && /* @__PURE__ */ jsx43(
11735
+ renderTargetContent: ({ interactiveVertex: vertex }, state, isSelectable) => /* @__PURE__ */ jsxs27(Fragment7, { children: [
11736
+ isSelectable && /* @__PURE__ */ jsx45(
11107
11737
  "circle",
11108
11738
  {
11109
11739
  cx: vertex.position.x,
@@ -11113,7 +11743,7 @@ function HexGridImpl(props) {
11113
11743
  pointerEvents: "all"
11114
11744
  }
11115
11745
  ),
11116
- renderInteractiveVertex ? renderInteractiveVertex(vertex, vertex.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx43(
11746
+ renderInteractiveVertex ? renderInteractiveVertex(vertex, vertex.position, state) : state.isEnabled && state.isEligible ? /* @__PURE__ */ jsx45(
11117
11747
  DefaultInteractiveVertex,
11118
11748
  {
11119
11749
  position: vertex.position,
@@ -11124,7 +11754,7 @@ function HexGridImpl(props) {
11124
11754
  ] })
11125
11755
  }
11126
11756
  ),
11127
- effectivePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsx43(
11757
+ effectivePanZoom && transform.zoom !== 1 && /* @__PURE__ */ jsx45(
11128
11758
  GridZoomIndicator,
11129
11759
  {
11130
11760
  viewBoxX,
@@ -11274,7 +11904,13 @@ export {
11274
11904
  MoreActions,
11275
11905
  DiceRoller,
11276
11906
  PhaseIndicator,
11277
- GameEndDisplay,
11907
+ GuidancePanel,
11908
+ SetupChecklist,
11909
+ ActionHelp,
11910
+ StandingsTable,
11911
+ OutcomeDialog,
11912
+ SystemActionSummary,
11913
+ GameEventLog,
11278
11914
  DefaultNetworkNode,
11279
11915
  DefaultNetworkEdge,
11280
11916
  DefaultNetworkPiece,
@@ -11305,4 +11941,4 @@ export {
11305
11941
  HexGrid,
11306
11942
  createHexBoardView
11307
11943
  };
11308
- //# sourceMappingURL=chunk-E3X552YM.js.map
11944
+ //# sourceMappingURL=chunk-2TRZSZGD.js.map