@puzzmo/sdk 0.0.7 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +80 -260
  2. package/dist/createSimulator-9IxV0l3_.js +2749 -0
  3. package/dist/createSimulator-9IxV0l3_.js.map +1 -0
  4. package/dist/createSimulator-DxhvbnJB.cjs +1428 -0
  5. package/dist/createSimulator-DxhvbnJB.cjs.map +1 -0
  6. package/dist/index.cjs +2 -2
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.ts +3 -13
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +267 -14
  11. package/dist/index.js.map +1 -1
  12. package/dist/objectSpread2-C4RR_HMd.cjs +1 -0
  13. package/dist/objectSpread2-CJo2CZQ6.js +76 -0
  14. package/dist/sdk.d.ts +61 -0
  15. package/dist/sdk.d.ts.map +1 -0
  16. package/dist/simulator/createSimulator.d.ts +41 -0
  17. package/dist/simulator/createSimulator.d.ts.map +1 -0
  18. package/dist/simulator/fixtures.d.ts +18 -0
  19. package/dist/simulator/fixtures.d.ts.map +1 -0
  20. package/dist/simulator/index.cjs +1 -0
  21. package/dist/simulator/index.d.ts +3 -0
  22. package/dist/simulator/index.d.ts.map +1 -0
  23. package/dist/simulator/index.js +2 -0
  24. package/dist/simulator/messaging.d.ts +12 -0
  25. package/dist/simulator/messaging.d.ts.map +1 -0
  26. package/dist/simulator/standalone.cjs +2 -0
  27. package/dist/simulator/standalone.cjs.map +1 -0
  28. package/dist/simulator/standalone.d.ts +7 -0
  29. package/dist/simulator/standalone.d.ts.map +1 -0
  30. package/dist/simulator/standalone.js +19 -0
  31. package/dist/simulator/standalone.js.map +1 -0
  32. package/dist/simulator/state.d.ts +12 -0
  33. package/dist/simulator/state.d.ts.map +1 -0
  34. package/dist/simulator/styles.d.ts +2 -0
  35. package/dist/simulator/styles.d.ts.map +1 -0
  36. package/dist/simulator/types.d.ts +72 -0
  37. package/dist/simulator/types.d.ts.map +1 -0
  38. package/dist/simulator/views/AuthView.d.ts +3 -0
  39. package/dist/simulator/views/AuthView.d.ts.map +1 -0
  40. package/dist/simulator/views/CheckpointsView.d.ts +3 -0
  41. package/dist/simulator/views/CheckpointsView.d.ts.map +1 -0
  42. package/dist/simulator/views/CtrlView.d.ts +3 -0
  43. package/dist/simulator/views/CtrlView.d.ts.map +1 -0
  44. package/dist/simulator/views/DataView.d.ts +3 -0
  45. package/dist/simulator/views/DataView.d.ts.map +1 -0
  46. package/dist/simulator/views/DoneView.d.ts +3 -0
  47. package/dist/simulator/views/DoneView.d.ts.map +1 -0
  48. package/dist/simulator/views/FeaturesView.d.ts +4 -0
  49. package/dist/simulator/views/FeaturesView.d.ts.map +1 -0
  50. package/dist/simulator/views/MsgsView.d.ts +6 -0
  51. package/dist/simulator/views/MsgsView.d.ts.map +1 -0
  52. package/dist/simulator/views/ThemeView.d.ts +3 -0
  53. package/dist/simulator/views/ThemeView.d.ts.map +1 -0
  54. package/dist/simulator/views/ThumbView.d.ts +6 -0
  55. package/dist/simulator/views/ThumbView.d.ts.map +1 -0
  56. package/dist/simulator/views/index.d.ts +10 -0
  57. package/dist/simulator/views/index.d.ts.map +1 -0
  58. package/dist/themes.d.ts +46 -0
  59. package/dist/themes.d.ts.map +1 -0
  60. package/dist/types.d.ts +232 -0
  61. package/dist/types.d.ts.map +1 -0
  62. package/dist/vite.cjs +11 -0
  63. package/dist/vite.cjs.map +1 -0
  64. package/dist/vite.d.ts +16 -0
  65. package/dist/vite.d.ts.map +1 -0
  66. package/dist/vite.js +45 -0
  67. package/dist/vite.js.map +1 -0
  68. package/dist/workshop.d.ts +7 -175
  69. package/dist/workshop.d.ts.map +1 -1
  70. package/package.json +21 -19
  71. package/dist/index.iife.js +0 -2
  72. package/dist/index.iife.js.map +0 -1
  73. package/dist/index.umd.js +0 -2
  74. package/dist/index.umd.js.map +0 -1
  75. package/dist/puzzmoSDK.d.ts +0 -237
@@ -0,0 +1,2749 @@
1
+ import { n as e, t } from "./objectSpread2-CJo2CZQ6.js";
2
+ const n = [
3
+ {
4
+ name: "Puzzmo (light)",
5
+ type: "light",
6
+ key: "#FFAAAC",
7
+ keyFG: "#000000",
8
+ keyStrong: "#F7868B",
9
+ keyLight: "#FFD2D3",
10
+ g_key: "#FFAAAC",
11
+ subBrand: "#FFC000",
12
+ subBrandFG: "#000000",
13
+ player: "#5DBAFC",
14
+ playerFG: "#000000",
15
+ playerLight: "#9EDDFF",
16
+ alt1: "#98B389",
17
+ alt2: "#FAC16C",
18
+ alt3: "#D298FF",
19
+ fg: "#000000",
20
+ error: "#FF3C3C",
21
+ alwaysDark: "#1B1D29",
22
+ alwaysLight: "#FFFFFF",
23
+ g_bg: "#FFFFFF",
24
+ g_bgAlt: "#EBEBEB",
25
+ g_bgDark: "#D6D6D6",
26
+ g_textDark: "#1B1B28",
27
+ g_textLight: "#FFFFFF",
28
+ g_blank: "#000000",
29
+ g_unsolved: "#C2C2C2",
30
+ g_outline: "#1B1D29",
31
+ a_bg: "#F2F2F2",
32
+ a_bgAlt: "#ECECEC",
33
+ a_puzmo: "#FFC000",
34
+ a_headerText: "#000000",
35
+ a_table: "#F9F9F9",
36
+ a_tableAlt: "#F6F4F4",
37
+ a_inlineTag: "#D9D9D9",
38
+ a_anchor: "#1F97EE",
39
+ a_infoBG: "#FFFFFF"
40
+ },
41
+ {
42
+ name: "Puzzmo (dark)",
43
+ type: "dark",
44
+ key: "#FFAAAC",
45
+ keyFG: "#000000",
46
+ keyStrong: "#F7868B",
47
+ keyLight: "#FFD2D3",
48
+ g_key: "#FFAAAC",
49
+ player: "#5DBAFC",
50
+ playerFG: "#000000",
51
+ playerLight: "#9EDDFF",
52
+ subBrand: "#FFC000",
53
+ subBrandFG: "#000000",
54
+ alt1: "#98B389",
55
+ alt2: "#FAC16C",
56
+ alt3: "#D298FF",
57
+ error: "#FF3C3C",
58
+ fg: "#ECECEC",
59
+ alwaysDark: "#1B1D29",
60
+ alwaysLight: "#FFFFFF",
61
+ g_bg: "#374351",
62
+ g_bgAlt: "#333D49",
63
+ g_bgDark: "#2C2F33",
64
+ g_textDark: "#F2F2F2",
65
+ g_textLight: "#20180E",
66
+ g_blank: "#000000",
67
+ g_unsolved: "#747474",
68
+ g_outline: "#646464",
69
+ a_bg: "#141620",
70
+ a_bgAlt: "#202433",
71
+ a_puzmo: "#FFC000",
72
+ a_headerText: "#A1BAD4",
73
+ a_table: "#303246",
74
+ a_tableAlt: "#393b52",
75
+ a_inlineTag: "#ECECEC",
76
+ a_anchor: "#1F97EE",
77
+ a_infoBG: "#282C3A"
78
+ },
79
+ {
80
+ name: "Foshay",
81
+ type: "light",
82
+ key: "#98B389",
83
+ keyFG: "#313540",
84
+ keyStrong: "#87BD69",
85
+ keyLight: "#809B77",
86
+ g_key: "#98B389",
87
+ player: "#3EC0E5",
88
+ subBrand: "#FFC000",
89
+ subBrandFG: "#000000",
90
+ playerFG: "#292B35",
91
+ playerLight: "#A8B5D6",
92
+ alt1: "#D87DA4",
93
+ alt2: "#E3A54F",
94
+ alt3: "#D298FF",
95
+ error: "#FF3C3C",
96
+ fg: "#292B35",
97
+ alwaysDark: "#292B35",
98
+ alwaysLight: "#D1DBF2",
99
+ g_bg: "#949EBA",
100
+ g_bgAlt: "#8891AB",
101
+ g_bgDark: "#7B839B",
102
+ g_textDark: "#292B35",
103
+ g_textLight: "#FFFFFF",
104
+ g_blank: "#292B35",
105
+ g_unsolved: "#B6B7BA",
106
+ g_outline: "#676F83",
107
+ a_bg: "#828CA3",
108
+ a_bgAlt: "#7F889F",
109
+ a_puzmo: "#FFC000",
110
+ a_headerText: "#292B35",
111
+ a_table: "#7A8399",
112
+ a_tableAlt: "#767E94",
113
+ a_inlineTag: "#ECECEC",
114
+ a_anchor: "#56C9E9",
115
+ a_infoBG: "#767F95"
116
+ },
117
+ {
118
+ name: "Bright white",
119
+ type: "light",
120
+ key: "#67ced2",
121
+ keyFG: "#000000",
122
+ keyStrong: "#26a0a5",
123
+ keyLight: "#ade6e9",
124
+ g_key: "#67ced2",
125
+ subBrand: "#FFC000",
126
+ subBrandFG: "#000000",
127
+ player: "#5DBAFC",
128
+ playerFG: "#000000",
129
+ playerLight: "#9EDDFF",
130
+ alt1: "#d26767",
131
+ alt2: "#fac16c",
132
+ alt3: "#7580bd",
133
+ fg: "#000000",
134
+ error: "#FF3C3C",
135
+ alwaysDark: "#111111",
136
+ alwaysLight: "#FFFFFF",
137
+ g_bg: "#f6f6f6",
138
+ g_bgAlt: "#F4F4F4",
139
+ g_bgDark: "#D6D6D6",
140
+ g_textDark: "#1B1B28",
141
+ g_textLight: "#FFFFFF",
142
+ g_blank: "#000000",
143
+ g_unsolved: "#C2C2C2",
144
+ g_outline: "#1B1D29",
145
+ a_bg: "#FFFFFF",
146
+ a_bgAlt: "#f8fbfc",
147
+ a_puzmo: "#FFC000",
148
+ a_headerText: "#000000",
149
+ a_table: "#EDEDED",
150
+ a_tableAlt: "#DBDBDB",
151
+ a_inlineTag: "#D9D9D9",
152
+ a_anchor: "#1F97EE",
153
+ a_infoBG: "#f6f6f6"
154
+ },
155
+ {
156
+ name: "Submersible",
157
+ type: "dark",
158
+ key: "#CD6DC6",
159
+ keyFG: "#031698",
160
+ keyStrong: "#FF7ABC",
161
+ keyLight: "#B467CB",
162
+ g_key: "#CD6DC6",
163
+ subBrand: "#FFC000",
164
+ subBrandFG: "#000000",
165
+ player: "#4AB1D1",
166
+ playerFG: "#071D47",
167
+ playerLight: "#3C99D7",
168
+ alt1: "#8BA964",
169
+ alt2: "#C69A58",
170
+ alt3: "#7644B5",
171
+ fg: "#FFEBFF",
172
+ error: "#FF3C3C",
173
+ alwaysDark: "#031698",
174
+ alwaysLight: "#FFEBFF",
175
+ g_bg: "#043BED",
176
+ g_bgAlt: "#0A31CC",
177
+ g_bgDark: "#0E2DA8",
178
+ g_textDark: "#031698",
179
+ g_textLight: "#FFEBFF",
180
+ g_blank: "#031698",
181
+ g_unsolved: "#3662F1",
182
+ g_outline: "#031698",
183
+ a_bg: "#043BED",
184
+ a_bgAlt: "#0A31CC",
185
+ a_puzmo: "#FFC000",
186
+ a_headerText: "#FFEBFF",
187
+ a_table: "#043BED",
188
+ a_tableAlt: "#0A31CC",
189
+ a_inlineTag: "#FF7ABC",
190
+ a_anchor: "#FF7ABC",
191
+ a_infoBG: "#0A31CC"
192
+ },
193
+ {
194
+ name: "Hot Dog (beta)",
195
+ type: "light",
196
+ key: "#FFFF00",
197
+ keyFG: "#000000",
198
+ keyStrong: "#FFE600",
199
+ keyLight: "#FFEC44",
200
+ g_key: "#FFFF00",
201
+ subBrand: "#FFC000",
202
+ subBrandFG: "#000000",
203
+ player: "#FF7A00",
204
+ playerFG: "#000000",
205
+ playerLight: "#FFA450",
206
+ alt1: "#3ABC5E",
207
+ alt2: "#5C3ABC",
208
+ alt3: "#BC3AAF",
209
+ fg: "#000000",
210
+ error: "#FF3C3C",
211
+ alwaysDark: "#1B1D29",
212
+ alwaysLight: "#FFFFFF",
213
+ g_bg: "#EBFF00",
214
+ g_bgAlt: "#EBEBEB",
215
+ g_bgDark: "#D6D6D6",
216
+ g_textDark: "#1B1B28",
217
+ g_textLight: "#FFFFFF",
218
+ g_blank: "#000000",
219
+ g_unsolved: "#C2C2C2",
220
+ g_outline: "#1B1D29",
221
+ a_bg: "#FF0000",
222
+ a_bgAlt: "#E50000",
223
+ a_puzmo: "#FFC000",
224
+ a_headerText: "#FFFFFF",
225
+ a_table: "#E50000",
226
+ a_tableAlt: "#FF2525",
227
+ a_inlineTag: "#000000",
228
+ a_anchor: "#000000",
229
+ a_infoBG: "#C6C6C6"
230
+ },
231
+ {
232
+ name: "Outlook Hayesy (beta)",
233
+ type: "light",
234
+ key: "#DAB98C",
235
+ keyFG: "#000000",
236
+ keyStrong: "#B99368",
237
+ keyLight: "#DAB98C",
238
+ subBrand: "#FFC000",
239
+ subBrandFG: "#000000",
240
+ g_key: "#DAB98C",
241
+ player: "#5DBAFC",
242
+ playerFG: "#000000",
243
+ playerLight: "#9EDDFF",
244
+ alt1: "#5EC386",
245
+ alt2: "#5E93C3",
246
+ alt3: "#C35E5E",
247
+ fg: "#000000",
248
+ error: "#FF3C3C",
249
+ alwaysDark: "#5E390F",
250
+ alwaysLight: "#FFF3E4",
251
+ g_bg: "#FFFFFF",
252
+ g_bgAlt: "#EBEBEB",
253
+ g_bgDark: "#D6D6D6",
254
+ g_textDark: "#1B1B28",
255
+ g_textLight: "#FFFFFF",
256
+ g_blank: "#000000",
257
+ g_unsolved: "#C2C2C2",
258
+ g_outline: "#1B1D29",
259
+ a_bg: "#FEF5E8",
260
+ a_bgAlt: "#ffffff",
261
+ a_puzmo: "#FAC7CE",
262
+ a_headerText: "#000000",
263
+ a_table: "#FAE8D3",
264
+ a_tableAlt: "#EED7BC",
265
+ a_inlineTag: "#D9D9D9",
266
+ a_anchor: "#B99368",
267
+ a_infoBG: "#FFFFFF"
268
+ },
269
+ {
270
+ name: "Console (beta)",
271
+ type: "dark",
272
+ key: "#957df9",
273
+ keyFG: "#000000",
274
+ keyStrong: "#590FF5",
275
+ keyLight: "#590FF5",
276
+ subBrand: "#FFC000",
277
+ subBrandFG: "#000000",
278
+ g_key: "#FFFF00",
279
+ player: "#ffffff",
280
+ playerFG: "#000000",
281
+ playerLight: "#9EDDFF",
282
+ alt1: "#590ff5",
283
+ alt2: "#00e200",
284
+ alt3: "#ff8a02",
285
+ fg: "#00e200",
286
+ error: "#FF3C3C",
287
+ alwaysDark: "#1B1D29",
288
+ alwaysLight: "#00e200",
289
+ g_bg: "#101428",
290
+ g_bgAlt: "#101428",
291
+ g_bgDark: "#00e200",
292
+ g_textDark: "#00e200",
293
+ g_textLight: "#590ff5",
294
+ g_blank: "#00e200",
295
+ g_unsolved: "#0000ff",
296
+ g_outline: "#00e200",
297
+ a_bg: "#000000",
298
+ a_bgAlt: "#112211",
299
+ a_puzmo: "#ffffff",
300
+ a_headerText: "#00e200",
301
+ a_table: "#000000",
302
+ a_tableAlt: "#002200",
303
+ a_inlineTag: "#D9D9D9",
304
+ a_anchor: "#957df9",
305
+ a_infoBG: "#001900"
306
+ }
307
+ ];
308
+ var r = {
309
+ collapsed: "simulator-collapsed",
310
+ tab: "simulator-tab",
311
+ theme: "simulator-theme",
312
+ fixtureCategory: "simulator-fixture-category",
313
+ fixturePuzzle: "simulator-fixture-puzzle",
314
+ renderHost: "simulator-render-host",
315
+ renderContext: "simulator-render-context"
316
+ };
317
+ function i() {
318
+ let e = localStorage.getItem(r.theme);
319
+ if (e) {
320
+ let t = n.find((t) => t.name === e);
321
+ if (t) return t;
322
+ }
323
+ return n[0];
324
+ }
325
+ function a(e) {
326
+ var t;
327
+ let n = localStorage.getItem(r.tab);
328
+ return n && e.includes(n) ? n : (t = e[0]) == null ? "ctrl" : t;
329
+ }
330
+ function o(e) {
331
+ let t = localStorage.getItem(r.collapsed);
332
+ return t === null ? e : t === "true";
333
+ }
334
+ function s() {
335
+ let e = localStorage.getItem(r.renderHost);
336
+ return e && [
337
+ "game",
338
+ "app",
339
+ "opengraph"
340
+ ].includes(e) ? e : "game";
341
+ }
342
+ function c() {
343
+ let e = localStorage.getItem(r.renderContext);
344
+ if (e && [
345
+ "preview",
346
+ "share",
347
+ "completed",
348
+ "timeline"
349
+ ].includes(e)) return e;
350
+ }
351
+ function l(e, t, n) {
352
+ var l, u;
353
+ let d = localStorage.getItem(r.fixtureCategory), f = localStorage.getItem(r.fixturePuzzle);
354
+ return {
355
+ isCollapsed: o((l = e.collapsed) == null ? !0 : l),
356
+ isPaused: !1,
357
+ hasStarted: !1,
358
+ activeTab: a(n),
359
+ puzzleData: null,
360
+ originalPuzzle: "",
361
+ currentInputStr: "",
362
+ completionData: null,
363
+ selectedTheme: i(),
364
+ selectedCategory: d && t.includes(d) ? d : (u = t[0]) == null ? null : u,
365
+ selectedPuzzle: f == null ? null : f,
366
+ renderHost: s(),
367
+ renderContext: c()
368
+ };
369
+ }
370
+ function u(e) {
371
+ localStorage.setItem(r.collapsed, String(e));
372
+ }
373
+ function d(e) {
374
+ localStorage.setItem(r.tab, e);
375
+ }
376
+ function f(e) {
377
+ localStorage.setItem(r.theme, e);
378
+ }
379
+ function p(e) {
380
+ localStorage.setItem(r.fixtureCategory, e);
381
+ }
382
+ function m(e) {
383
+ localStorage.setItem(r.fixturePuzzle, e);
384
+ }
385
+ function h() {
386
+ localStorage.removeItem(r.fixturePuzzle);
387
+ }
388
+ function g(e) {
389
+ e ? localStorage.setItem(r.renderHost, e) : localStorage.removeItem(r.renderHost);
390
+ }
391
+ function _(e) {
392
+ e ? localStorage.setItem(r.renderContext, e) : localStorage.removeItem(r.renderContext);
393
+ }
394
+ function ee(e) {
395
+ let t = [];
396
+ return {
397
+ log(n, r, i) {
398
+ let a = {
399
+ type: n,
400
+ data: r,
401
+ time: (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
402
+ hour12: !1,
403
+ hour: "2-digit",
404
+ minute: "2-digit",
405
+ second: "2-digit"
406
+ }),
407
+ direction: i
408
+ };
409
+ t.push(a), t.length > 100 && t.shift(), e == null || e(a);
410
+ },
411
+ clear() {
412
+ t.length = 0;
413
+ },
414
+ getLog() {
415
+ return t;
416
+ }
417
+ };
418
+ }
419
+ function te(e, t, n) {
420
+ console.log("Simulator sending:", e, t), n == null || n.log(e, t, "out"), window.postMessage({
421
+ type: e,
422
+ data: t
423
+ }, "*");
424
+ }
425
+ function ne(e, t) {
426
+ let n = (n) => {
427
+ var r, i, a;
428
+ if (!(!(n == null || (r = n.data) == null) && r.type)) return;
429
+ let o = n.data.type, s = (i = (a = n.data.data) == null ? n.data.json : a) == null ? {} : i;
430
+ ["TIMER_TICK", "TIMER_SYNC"].includes(o) || t == null || t.log(o, s, "in"), e(o, s);
431
+ };
432
+ return window.addEventListener("message", n), () => window.removeEventListener("message", n);
433
+ }
434
+ /**
435
+ * Parse fixture imports into a structured format: { category: { filename: data } }
436
+ */
437
+ function v(e) {
438
+ let t = /* @__PURE__ */ new Map();
439
+ console.log("Simulator: Parsing fixtures", Object.keys(e));
440
+ for (let [o, s] of Object.entries(e)) {
441
+ var n, r, i, a;
442
+ let e = o.split("/"), c = (n = (r = e.pop()) == null ? void 0 : r.replace(".json", "")) == null ? "" : n, l = (i = e.pop()) == null ? "default" : i;
443
+ t.has(l) || t.set(l, /* @__PURE__ */ new Map());
444
+ let u = (a = s.default) == null ? s : a;
445
+ t.get(l).set(c, u);
446
+ }
447
+ return t.forEach((e, n) => {
448
+ let r = new Map(Array.from(e.entries()).sort((e, t) => {
449
+ var n, r, i, a;
450
+ return parseInt((n = (r = e[0].match(/\d+/)) == null ? void 0 : r[0]) == null ? "0" : n) - parseInt((i = (a = t[0].match(/\d+/)) == null ? void 0 : a[0]) == null ? "0" : i);
451
+ }));
452
+ t.set(n, r);
453
+ }), t;
454
+ }
455
+ /**
456
+ * Render fixture selector HTML
457
+ */
458
+ function y(e, t) {
459
+ return e.length === 0 ? "" : `
460
+ <div class="simulator-fixtures">
461
+ <div class="simulator-field">
462
+ <label class="simulator-label">Category</label>
463
+ <select class="simulator-select" id="simulator-fixture-category">
464
+ ${e.map((e) => `<option value="${e}" ${e === t ? "selected" : ""}>${e}</option>`).join("")}
465
+ </select>
466
+ </div>
467
+ <div class="simulator-field">
468
+ <label class="simulator-label">Puzzle</label>
469
+ <select class="simulator-select" id="simulator-fixture-puzzle"></select>
470
+ </div>
471
+ </div>
472
+ `;
473
+ }
474
+ /**
475
+ * Update puzzle select options based on selected category
476
+ */
477
+ function b(e, t, n, r) {
478
+ let i = t.get(n);
479
+ if (!i) return null;
480
+ let a = Array.from(i.keys()), o = r;
481
+ if (!r || !i.has(r)) {
482
+ var s;
483
+ o = (s = a[0]) == null ? null : s;
484
+ }
485
+ return e.innerHTML = a.map((e) => `<option value="${e}" ${e === o ? "selected" : ""}>${e}</option>`).join(""), o;
486
+ }
487
+ /**
488
+ * Get puzzle data from fixtures
489
+ */
490
+ function x(e, t, n) {
491
+ var r, i;
492
+ return !t || !n || (r = (i = e.get(t)) == null ? void 0 : i.get(n)) == null ? null : r;
493
+ }
494
+ function re() {
495
+ return {
496
+ id: "ctrl",
497
+ label: "Ctrl",
498
+ render() {
499
+ return "\n <div id=\"simulator-fixtures-container\"></div>\n <div id=\"simulator-status\">\n <span class=\"indicator waiting\"></span>\n <span class=\"text\">Waiting for READY...</span>\n </div>\n <div class=\"simulator-row\">\n <button class=\"simulator-btn primary\" id=\"simulator-start\" disabled>Start</button>\n <button class=\"simulator-btn\" id=\"simulator-pause\" disabled>Pause</button>\n </div>\n <div class=\"simulator-row\">\n <button class=\"simulator-btn danger\" id=\"simulator-retry\" disabled>Retry</button>\n </div>\n ";
500
+ },
501
+ bind(e) {
502
+ let t = e.getElement("#simulator-start"), n = e.getElement("#simulator-pause"), r = e.getElement("#simulator-retry"), i = e.getElement("#simulator-fixtures-container");
503
+ if (console.log("Simulator: CtrlView.bind called", {
504
+ hasFixtures: !!e.fixtures,
505
+ categories: e.fixtureCategories,
506
+ selectedCategory: e.state.selectedCategory,
507
+ selectedPuzzle: e.state.selectedPuzzle
508
+ }), e.fixtures && e.fixtureCategories.length > 0 && i) {
509
+ i.innerHTML = y(e.fixtureCategories, e.state.selectedCategory);
510
+ let t = e.getElement("#simulator-fixture-category"), n = e.getElement("#simulator-fixture-puzzle");
511
+ if (t && n && e.state.selectedCategory) {
512
+ e.state.selectedPuzzle = b(n, e.fixtures, e.state.selectedCategory, e.state.selectedPuzzle);
513
+ let r = x(e.fixtures, e.state.selectedCategory, e.state.selectedPuzzle);
514
+ console.log("Simulator: Loading fixture puzzle", {
515
+ category: e.state.selectedCategory,
516
+ puzzle: e.state.selectedPuzzle,
517
+ hasPuzzleData: !!r
518
+ }), r && (e.state.puzzleData = r, e.state.originalPuzzle = JSON.stringify(r, null, 2), e.state.selectedCategory && p(e.state.selectedCategory), e.state.selectedPuzzle && m(e.state.selectedPuzzle)), t.addEventListener("change", () => {
519
+ console.log("Simulator: Category changed, reloading...", t.value), p(t.value), h(), window.location.reload();
520
+ }), n.addEventListener("change", () => {
521
+ console.log("Simulator: Puzzle changed, reloading...", n.value), m(n.value), window.location.reload();
522
+ });
523
+ }
524
+ }
525
+ t == null || t.addEventListener("click", () => {
526
+ e.state.isPaused ? (e.sendToGame("RESUME_GAME", {}), e.state.isPaused = !1, n && (n.textContent = "Pause"), e.updateStatus("Running", "ready")) : (e.sendToGame("START_GAME", void 0), e.state.hasStarted = !0, n && (n.disabled = !1), t && (t.textContent = "Resume"), e.updateStatus("Running", "ready"));
527
+ }), n == null || n.addEventListener("click", () => {
528
+ e.state.isPaused ? (e.sendToGame("RESUME_GAME", {}), e.state.isPaused = !1, n.textContent = "Pause", e.updateStatus("Running", "ready")) : (e.sendToGame("PAUSE_GAME", {}), e.state.isPaused = !0, n.textContent = "Resume", e.updateStatus("Paused", "paused"));
529
+ }), r == null || r.addEventListener("click", () => {
530
+ e.sendToGame("RETRY_PUZZLE", {}), e.state.hasStarted = !1, e.state.isPaused = !1, n && (n.disabled = !0, n.textContent = "Pause"), t && (t.textContent = "Start"), e.updateStatus("Ready to retry", "ready");
531
+ });
532
+ },
533
+ onMessage(e, t, n) {
534
+ let r = n.getElement("#simulator-start"), i = n.getElement("#simulator-pause"), a = n.getElement("#simulator-retry");
535
+ e === "READY_GAME_LOADED" && (r && (r.disabled = !1), a && (a.disabled = !1), n.updateStatus("Ready", "ready")), e === "GAME_COMPLETED" && (n.state.hasStarted = !1, i && (i.disabled = !0), r && (r.disabled = !0), n.updateStatus("Completed!", "ready"));
536
+ }
537
+ };
538
+ }
539
+ var S = "simulator-saved-states";
540
+ /**
541
+ * Find thumbnail function on globalThis (looks for functions ending in "Thumbnail")
542
+ */
543
+ function ie() {
544
+ let e = globalThis;
545
+ for (let t of Object.keys(e)) if (t.endsWith("Thumbnail") && typeof e[t] == "function") return {
546
+ name: t,
547
+ fn: e[t]
548
+ };
549
+ return null;
550
+ }
551
+ /**
552
+ * Generate a small thumbnail SVG for a given input string
553
+ */
554
+ function C(e, t) {
555
+ let n = ie();
556
+ if (!n) return "";
557
+ try {
558
+ let r = e.state.puzzleData ? JSON.stringify(e.state.puzzleData) : "", i = {
559
+ viewerIsOwner: !0,
560
+ theme: e.state.selectedTheme,
561
+ strict: !0,
562
+ renderHost: "game"
563
+ };
564
+ return n.fn(r, t, i);
565
+ } catch (e) {
566
+ return "";
567
+ }
568
+ }
569
+ var w = [];
570
+ function T(e, t = 8) {
571
+ let n = 14 * t + 8 + 4;
572
+ e.style.height = "auto";
573
+ let r = Math.min(Math.max(e.scrollHeight, 40), n);
574
+ e.style.height = `${r}px`;
575
+ }
576
+ function ae() {
577
+ let e = "", t = "";
578
+ return {
579
+ id: "data",
580
+ label: "Data",
581
+ render() {
582
+ return "\n <div class=\"data-view-container\">\n <div class=\"data-subtabs\">\n <button class=\"data-subtab active\" data-subtab=\"edit\">Edit</button>\n <button class=\"data-subtab\" data-subtab=\"history\">History</button>\n <button class=\"data-subtab\" data-subtab=\"saves\">Saves</button>\n </div>\n\n <div class=\"data-subtab-content active\" id=\"data-subtab-edit\">\n <div class=\"simulator-field\">\n <label class=\"simulator-label\">Puzzle String</label>\n <textarea class=\"simulator-textarea auto-resize\" id=\"simulator-puzzle\" placeholder=\"Loading...\"></textarea>\n <div class=\"simulator-row\">\n <button class=\"simulator-btn subtle\" id=\"simulator-puzzle-reset\">Reset</button>\n <button class=\"simulator-btn primary\" id=\"simulator-puzzle-apply\" disabled>Apply</button>\n </div>\n </div>\n <div class=\"simulator-divider\"></div>\n <div class=\"simulator-field\">\n <label class=\"simulator-label\">Input String</label>\n <textarea class=\"simulator-textarea auto-resize\" id=\"simulator-input\" placeholder=\"No input yet...\"></textarea>\n <div class=\"simulator-row\">\n <button class=\"simulator-btn subtle\" id=\"simulator-input-reset\">Reset</button>\n <button class=\"simulator-btn primary\" id=\"simulator-input-apply\" disabled>Apply</button>\n </div>\n </div>\n </div>\n\n <div class=\"data-subtab-content\" id=\"data-subtab-history\">\n <div class=\"history-header\">\n <span class=\"simulator-label\">Input String Timeline</span>\n <button class=\"simulator-btn tiny\" id=\"simulator-history-clear\">Clear</button>\n </div>\n <div class=\"history-list\" id=\"simulator-history-list\">\n <div class=\"simulator-empty\">No history yet</div>\n </div>\n </div>\n\n <div class=\"data-subtab-content\" id=\"data-subtab-saves\">\n <div class=\"save-new\">\n <input type=\"text\" class=\"simulator-input\" id=\"simulator-save-name\" placeholder=\"Save name...\" />\n <button class=\"simulator-btn primary\" id=\"simulator-save-btn\">Save</button>\n </div>\n <div class=\"simulator-divider\"></div>\n <div class=\"saves-list\" id=\"simulator-saves-list\">\n <div class=\"simulator-empty\">No saved states</div>\n </div>\n </div>\n </div>\n ";
583
+ },
584
+ bind(n) {
585
+ let r = n.getElement(".data-subtabs");
586
+ r == null || r.querySelectorAll(".data-subtab").forEach((e) => {
587
+ e.addEventListener("click", () => {
588
+ let t = e.getAttribute("data-subtab");
589
+ if (!t) return;
590
+ r.querySelectorAll(".data-subtab").forEach((e) => e.classList.remove("active")), e.classList.add("active");
591
+ let i = n.getElement(".data-view-container");
592
+ i == null || i.querySelectorAll(".data-subtab-content").forEach((e) => {
593
+ e.classList.toggle("active", e.id === `data-subtab-${t}`);
594
+ }), t === "edit" ? A(n) : t === "history" ? D(n) : t === "saves" && O(n);
595
+ });
596
+ });
597
+ let i = n.getElement("#simulator-puzzle"), a = n.getElement("#simulator-input"), o = n.getElement("#simulator-puzzle-reset"), s = n.getElement("#simulator-puzzle-apply"), c = n.getElement("#simulator-input-reset"), l = n.getElement("#simulator-input-apply"), u = n.getElement("#simulator-start"), d = n.getElement("#simulator-pause");
598
+ setTimeout(() => {
599
+ i && n.state.originalPuzzle && (i.value = n.state.originalPuzzle, e = n.state.originalPuzzle, T(i)), a && n.state.currentInputStr && (a.value = n.state.currentInputStr, t = n.state.currentInputStr, T(a));
600
+ }, 0), i == null || i.addEventListener("input", () => {
601
+ T(i);
602
+ let t = i.value !== e;
603
+ s && (s.disabled = !t);
604
+ }), a == null || a.addEventListener("input", () => {
605
+ T(a);
606
+ let e = a.value !== t;
607
+ l && (l.disabled = !e);
608
+ }), o == null || o.addEventListener("click", () => {
609
+ i && (i.value = n.state.originalPuzzle, e = n.state.originalPuzzle, T(i), s && (s.disabled = !0));
610
+ }), s == null || s.addEventListener("click", () => {
611
+ if (i) try {
612
+ let t = JSON.parse(i.value);
613
+ n.state.puzzleData = t, n.state.originalPuzzle = i.value, e = i.value, n.sendToGame("RETRY_PUZZLE", {}), n.state.hasStarted = !1, n.state.isPaused = !1, d && (d.disabled = !0, d.textContent = "Pause"), u && (u.textContent = "Start"), n.updateStatus("Puzzle updated", "ready"), s.disabled = !0;
614
+ } catch (e) {
615
+ console.error("Simulator: Invalid puzzle JSON", e), n.updateStatus("Invalid JSON", "paused");
616
+ }
617
+ }), c == null || c.addEventListener("click", () => {
618
+ a && (a.value = t, T(a), l && (l.disabled = !0));
619
+ }), l == null || l.addEventListener("click", () => {
620
+ a && (n.state.currentInputStr = a.value, t = a.value, console.log("Simulator: Input string updated (game restart required to apply)"), n.updateStatus("Input stored", "ready"), l.disabled = !0);
621
+ });
622
+ let f = n.getElement("#simulator-history-clear");
623
+ f == null || f.addEventListener("click", () => {
624
+ w = [], D(n);
625
+ });
626
+ let p = n.getElement("#simulator-save-name"), m = n.getElement("#simulator-save-btn");
627
+ m == null || m.addEventListener("click", () => {
628
+ if (!p || !p.value.trim()) return;
629
+ let e = E(), t = {
630
+ name: p.value.trim(),
631
+ puzzleStr: n.state.originalPuzzle,
632
+ inputStr: n.state.currentInputStr,
633
+ timestamp: Date.now()
634
+ };
635
+ e.push(t), localStorage.setItem(S, JSON.stringify(e)), p.value = "", O(n);
636
+ }), O(n);
637
+ },
638
+ onActivate(n) {
639
+ e = n.state.originalPuzzle, t = n.state.currentInputStr, A(n), D(n);
640
+ },
641
+ onMessage(e, n, r) {
642
+ var i, a;
643
+ let o = r.getElement("#simulator-input"), s = r.getElement("#simulator-input-apply"), c = (i = n == null || (a = n.input) == null ? void 0 : a.boardState) == null ? n == null ? void 0 : n.boardState : i;
644
+ if (e === "UPLOAD_NEW_GAME_STATE" && c) {
645
+ if (r.state.currentInputStr = c, w.length === 0 || w[w.length - 1].value !== c) {
646
+ w.push({
647
+ value: c,
648
+ timestamp: Date.now()
649
+ }), w.length > 100 && (w = w.slice(-100));
650
+ let e = r.getElement("#data-subtab-history");
651
+ e != null && e.classList.contains("active") && D(r);
652
+ }
653
+ o && (o.value = r.state.currentInputStr, t = r.state.currentInputStr, T(o), s && (s.disabled = !0));
654
+ }
655
+ }
656
+ };
657
+ }
658
+ function E() {
659
+ try {
660
+ let e = localStorage.getItem(S);
661
+ return e ? JSON.parse(e) : [];
662
+ } catch (e) {
663
+ return [];
664
+ }
665
+ }
666
+ function D(e) {
667
+ let t = e.getElement("#simulator-history-list");
668
+ if (t) {
669
+ if (t.style.setProperty("--history-thumb-bg", e.state.selectedTheme.a_bg), w.length === 0) {
670
+ t.innerHTML = "<div class=\"simulator-empty\">No history yet</div>";
671
+ return;
672
+ }
673
+ t.innerHTML = [...w].reverse().map((t, n) => {
674
+ let r = w.length - 1 - n, i = new Date(t.timestamp).toLocaleTimeString(), a = t.value.length > 60 ? t.value.slice(0, 60) + "..." : t.value;
675
+ return `
676
+ <div class="history-item" data-history-idx="${r}">
677
+ <div class="history-item-thumb">${C(e, t.value)}</div>
678
+ <div class="history-item-content">
679
+ <div class="history-item-header">
680
+ <span class="history-item-num">#${r + 1}</span>
681
+ <span class="history-item-time">${i}</span>
682
+ <button class="simulator-btn tiny history-restore-btn" data-history-idx="${r}">Restore</button>
683
+ </div>
684
+ <div class="history-item-preview">${k(a)}</div>
685
+ </div>
686
+ </div>
687
+ `;
688
+ }).join(""), t.querySelectorAll(".history-restore-btn").forEach((t) => {
689
+ t.addEventListener("click", (t) => {
690
+ let n = parseInt(t.target.getAttribute("data-history-idx") || "0"), r = w[n];
691
+ if (r) {
692
+ e.state.currentInputStr = r.value;
693
+ let t = e.getElement("#simulator-input");
694
+ t && (t.value = r.value, T(t)), e.updateStatus("Input restored from history", "ready");
695
+ let n = e.getElement(".data-subtab[data-subtab=\"edit\"]");
696
+ n == null || n.click();
697
+ }
698
+ });
699
+ });
700
+ }
701
+ }
702
+ function O(e) {
703
+ let t = e.getElement("#simulator-saves-list");
704
+ if (!t) return;
705
+ let n = E();
706
+ if (n.length === 0) {
707
+ t.innerHTML = "<div class=\"simulator-empty\">No saved states</div>";
708
+ return;
709
+ }
710
+ t.innerHTML = [...n].reverse().map((e, t) => {
711
+ let r = n.length - 1 - t, i = new Date(e.timestamp).toLocaleDateString(), a = new Date(e.timestamp).toLocaleTimeString();
712
+ return `
713
+ <div class="save-item">
714
+ <div class="save-item-header">
715
+ <span class="save-item-name">${k(e.name)}</span>
716
+ <span class="save-item-time">${i} ${a}</span>
717
+ </div>
718
+ <div class="save-item-actions">
719
+ <button class="simulator-btn tiny save-load-btn" data-save-idx="${r}">Load</button>
720
+ <button class="simulator-btn tiny danger save-delete-btn" data-save-idx="${r}">Delete</button>
721
+ </div>
722
+ </div>
723
+ `;
724
+ }).join(""), t.querySelectorAll(".save-load-btn").forEach((t) => {
725
+ t.addEventListener("click", (t) => {
726
+ let r = n[parseInt(t.target.getAttribute("data-save-idx") || "0")];
727
+ if (r) {
728
+ try {
729
+ e.state.puzzleData = JSON.parse(r.puzzleStr), e.state.originalPuzzle = r.puzzleStr;
730
+ } catch (t) {
731
+ e.state.originalPuzzle = r.puzzleStr;
732
+ }
733
+ e.state.currentInputStr = r.inputStr;
734
+ let t = e.getElement("#simulator-puzzle"), n = e.getElement("#simulator-input");
735
+ t && (t.value = r.puzzleStr, T(t)), n && (n.value = r.inputStr, T(n)), e.updateStatus(`Loaded: ${r.name}`, "ready");
736
+ let i = e.getElement(".data-subtab[data-subtab=\"edit\"]");
737
+ i == null || i.click();
738
+ }
739
+ });
740
+ }), t.querySelectorAll(".save-delete-btn").forEach((t) => {
741
+ t.addEventListener("click", (t) => {
742
+ let r = parseInt(t.target.getAttribute("data-save-idx") || "0"), i = n.filter((e, t) => t !== r);
743
+ localStorage.setItem(S, JSON.stringify(i)), O(e);
744
+ });
745
+ });
746
+ }
747
+ function k(e) {
748
+ return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
749
+ }
750
+ function A(e) {
751
+ let t = e.getElement("#simulator-puzzle"), n = e.getElement("#simulator-input"), r = e.getElement("#simulator-puzzle-apply"), i = e.getElement("#simulator-input-apply");
752
+ t && e.state.originalPuzzle && (t.value = e.state.originalPuzzle, T(t), r && (r.disabled = !0)), n && (n.value = e.state.currentInputStr, T(n), i && (i.disabled = !0));
753
+ }
754
+ function j(e) {
755
+ return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
756
+ }
757
+ function oe() {
758
+ let e = 0;
759
+ return {
760
+ id: "msgs",
761
+ label: "Msgs",
762
+ render() {
763
+ return "\n <div class=\"msgs-view-container\">\n <div class=\"msgs-header\">\n <span class=\"simulator-label\">Message Log</span>\n <button class=\"simulator-btn tiny\" id=\"simulator-msgs-clear\">Clear</button>\n </div>\n <div id=\"simulator-msgs-log\"></div>\n </div>\n ";
764
+ },
765
+ bind(t) {
766
+ let n = t.getElement("#simulator-msgs-clear");
767
+ n == null || n.addEventListener("click", () => {
768
+ let n = t.getElement("#simulator-msgs-log");
769
+ n && (n.innerHTML = ""), e = 0, t.updateBadge("msgs", 0);
770
+ });
771
+ },
772
+ addLogEntry(t, n) {
773
+ let r = n.getElement("#simulator-msgs-log");
774
+ if (!r) return;
775
+ e++, n.updateBadge("msgs", e);
776
+ let i = document.createElement("div");
777
+ i.className = `simulator-msg ${t.direction}`;
778
+ let a = t.data === void 0 ? "" : JSON.stringify(t.data, null, 2);
779
+ i.innerHTML = `
780
+ <div class="simulator-msg-header">
781
+ <span class="simulator-msg-type">${t.direction === "out" ? "→" : "←"} ${t.type}</span>
782
+ <span class="simulator-msg-time">${t.time}</span>
783
+ </div>
784
+ ${a ? `<div class="simulator-msg-data">${j(a)}</div>` : ""}
785
+ `;
786
+ let o = i.querySelector(".simulator-msg-data");
787
+ for (o && o.addEventListener("click", () => {
788
+ r.querySelectorAll(".simulator-msg.expanded").forEach((e) => {
789
+ e !== i && e.classList.remove("expanded");
790
+ }), i.classList.toggle("expanded");
791
+ }), r.insertBefore(i, r.firstChild); r.children.length > 50;) r.removeChild(r.lastChild);
792
+ }
793
+ };
794
+ }
795
+ function se() {
796
+ return {
797
+ id: "done",
798
+ label: "Done",
799
+ render() {
800
+ return "\n <div id=\"simulator-done-empty\" class=\"simulator-empty\">Game not completed yet</div>\n <div id=\"simulator-done-content\" style=\"display:none;\">\n <div class=\"simulator-field\">\n <label class=\"simulator-label\">Completion Text</label>\n <div id=\"simulator-done-text\" class=\"simulator-value\"></div>\n </div>\n <div class=\"simulator-divider\"></div>\n <div class=\"simulator-field\">\n <label class=\"simulator-label\">Board State</label>\n <textarea class=\"simulator-textarea\" id=\"simulator-done-input\" rows=\"2\" readonly></textarea>\n </div>\n <div class=\"simulator-divider\"></div>\n <div class=\"simulator-field\">\n <label class=\"simulator-label\">Deeds</label>\n <div id=\"simulator-done-deeds\" class=\"simulator-deeds\"></div>\n </div>\n <div class=\"simulator-divider\"></div>\n <div class=\"simulator-field\">\n <label class=\"simulator-label\">Raw Data</label>\n <textarea class=\"simulator-textarea\" id=\"simulator-done-raw\" rows=\"4\" readonly></textarea>\n </div>\n </div>\n ";
801
+ },
802
+ bind(e) {},
803
+ onMessage(e, t, n) {
804
+ var r, i;
805
+ if (e !== "GAME_COMPLETED") return;
806
+ n.state.completionData = t;
807
+ let a = n.getElement("#simulator-done-empty"), o = n.getElement("#simulator-done-content"), s = n.getElement("#simulator-done-text"), c = n.getElement("#simulator-done-input"), l = n.getElement("#simulator-done-deeds"), u = n.getElement("#simulator-done-raw");
808
+ a && (a.style.display = "none"), o && (o.style.display = "block");
809
+ let d = ((r = t.input) == null ? void 0 : r.completionText) || t.completionText || "(no completion text)";
810
+ s && (s.textContent = d);
811
+ let f = ((i = t.input) == null ? void 0 : i.boardState) || t.boardState || n.state.currentInputStr || "";
812
+ if (c && (c.value = f), l) {
813
+ var p;
814
+ l.innerHTML = "";
815
+ let e = ((p = t.config) == null ? void 0 : p.deeds) || t.deeds;
816
+ e && Array.isArray(e) ? e.forEach((e) => {
817
+ let t = document.createElement("div");
818
+ t.className = "simulator-deed", t.innerHTML = `
819
+ <span class="simulator-deed-name">${e.id}</span>
820
+ <span class="simulator-deed-value">${e.value}</span>
821
+ `, l.appendChild(t);
822
+ }) : l.innerHTML = "<div class=\"simulator-empty\">No deeds</div>";
823
+ }
824
+ u && (u.value = JSON.stringify(t, null, 2)), n.setCollapsed(!1), n.switchTab("done");
825
+ }
826
+ };
827
+ }
828
+ function ce() {
829
+ let e = [], t = () => (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: !1 }), n = (e) => {
830
+ let { checkpointName: t, augConfig: n, time: r } = e, i = n == null ? void 0 : n.deeds;
831
+ return `
832
+ <div class="checkpoint-item">
833
+ <div class="checkpoint-header">
834
+ <span class="checkpoint-name">${t}</span>
835
+ <span class="checkpoint-time">${r}</span>
836
+ </div>
837
+ ${i && i.length > 0 ? `<div class="simulator-deeds">
838
+ ${i.map((e) => `<div class="simulator-deed"><span class="simulator-deed-name">${e.id}</span><span class="simulator-deed-value">${e.value}</span></div>`).join("")}
839
+ </div>` : ""}
840
+ </div>
841
+ `;
842
+ }, r = () => e.length === 0 ? "<div class=\"simulator-empty\">No checkpoints received yet</div>" : e.map((e) => n(e)).join("");
843
+ return {
844
+ id: "checkpoints",
845
+ label: "Chkpt",
846
+ render() {
847
+ return `
848
+ <div class="checkpoints-view-container">
849
+ <div class="checkpoints-header">
850
+ <span class="simulator-label">Checkpoints</span>
851
+ <button class="simulator-btn subtle small" id="simulator-checkpoints-clear">Clear</button>
852
+ </div>
853
+ <div id="simulator-checkpoints-list" class="checkpoints-list">
854
+ ${r()}
855
+ </div>
856
+ </div>
857
+ `;
858
+ },
859
+ bind(t) {
860
+ let n = t.getElement("#simulator-checkpoints-clear"), i = t.getElement("#simulator-checkpoints-list");
861
+ n == null || n.addEventListener("click", () => {
862
+ e = [], i && (i.innerHTML = r()), t.updateBadge("checkpoints", 0);
863
+ });
864
+ },
865
+ onMessage(n, i, a) {
866
+ if (n !== "HIT_CHECKPOINT") return;
867
+ let o = {
868
+ checkpointName: i.checkpointName,
869
+ augConfig: i.augConfig,
870
+ time: t()
871
+ };
872
+ e.push(o), a.updateBadge("checkpoints", e.length);
873
+ let s = a.getElement("#simulator-checkpoints-list");
874
+ s && (s.innerHTML = r(), s.scrollTop = s.scrollHeight);
875
+ }
876
+ };
877
+ }
878
+ /**
879
+ * Find thumbnail function on globalThis (looks for functions ending in "Thumbnail")
880
+ */
881
+ function M() {
882
+ let e = globalThis;
883
+ for (let t of Object.keys(e)) if (t.endsWith("Thumbnail") && typeof e[t] == "function") return {
884
+ name: t,
885
+ fn: e[t]
886
+ };
887
+ return null;
888
+ }
889
+ function le() {
890
+ return {
891
+ id: "thumb",
892
+ label: "Thumb",
893
+ render() {
894
+ return "\n <div class=\"thumb-view-container\">\n <div class=\"thumb-header\">\n <span class=\"simulator-label\">Thumbnail Preview</span>\n <button class=\"simulator-btn tiny\" id=\"simulator-thumb-refresh\">Refresh</button>\n </div>\n <div id=\"simulator-thumb-preview\">\n <span class=\"simulator-empty\">No thumbnail function found</span>\n </div>\n <div id=\"simulator-thumb-fn\"></div>\n <div class=\"simulator-divider\"></div>\n <div class=\"simulator-field\">\n <label class=\"simulator-label\">Render Host</label>\n <select class=\"simulator-select\" id=\"simulator-render-host-select\">\n <option value=\"game\">game</option>\n <option value=\"app\">app</option>\n <option value=\"opengraph\">opengraph</option>\n </select>\n </div>\n <div class=\"simulator-field\" id=\"simulator-render-context-field\" style=\"display: none;\">\n <label class=\"simulator-label\">Render Context</label>\n <select class=\"simulator-select\" id=\"simulator-render-context-select\">\n <option value=\"preview\">preview</option>\n <option value=\"share\">share</option>\n <option value=\"completed\">completed</option>\n <option value=\"timeline\">timeline</option>\n </select>\n </div>\n </div>\n ";
895
+ },
896
+ bind(e) {
897
+ let t = e.getElement("#simulator-thumb-refresh");
898
+ t == null || t.addEventListener("click", () => e.updateThumbnail());
899
+ let n = e.getElement("#simulator-render-host-select"), r = e.getElement("#simulator-render-context-select"), i = e.getElement("#simulator-render-context-field"), a = () => {
900
+ i && (i.style.display = e.state.renderHost === "opengraph" ? "block" : "none");
901
+ };
902
+ n && (e.state.renderHost || (e.state.renderHost = "game", g(e.state.renderHost)), n.value = e.state.renderHost || "game", n.addEventListener("change", () => {
903
+ e.state.renderHost = n.value, g(e.state.renderHost), a(), e.updateThumbnail();
904
+ })), r && (e.state.renderContext || (e.state.renderContext = "preview", _(e.state.renderContext)), r.value = e.state.renderContext || "preview", r.addEventListener("change", () => {
905
+ e.state.renderContext = r.value, _(e.state.renderContext), e.updateThumbnail();
906
+ })), a();
907
+ },
908
+ onActivate(e) {
909
+ setTimeout(() => e.updateThumbnail(), 0);
910
+ },
911
+ updatePreview: (e) => {
912
+ let t = e.getElement("#simulator-thumb-preview"), n = e.getElement("#simulator-thumb-fn");
913
+ t == null || t.style.setProperty("--sim-thumb-bg", e.state.selectedTheme.g_bg);
914
+ let r = M();
915
+ if (!r) {
916
+ t && (t.innerHTML = "<span class=\"simulator-empty\">No thumbnail function found</span>"), n && (n.textContent = "");
917
+ return;
918
+ }
919
+ n && (n.textContent = `Using: ${r.name}()`);
920
+ try {
921
+ let n = e.state.puzzleData ? JSON.stringify(e.state.puzzleData) : "", i = {
922
+ viewerIsOwner: !0,
923
+ theme: e.state.selectedTheme,
924
+ strict: !0,
925
+ renderHost: e.state.renderHost,
926
+ renderContext: e.state.renderContext
927
+ }, a = r.fn(n, e.state.currentInputStr, i);
928
+ t && (t.innerHTML = a);
929
+ } catch (e) {
930
+ console.error("Simulator: Thumbnail error", e), t && (t.innerHTML = `<span class="simulator-empty">Error: ${e}</span>`);
931
+ }
932
+ }
933
+ };
934
+ }
935
+ /**
936
+ * Generate theme preview HTML showing key colors
937
+ */
938
+ function N(e) {
939
+ let t = [
940
+ e.key,
941
+ e.subBrand,
942
+ e.player,
943
+ e.alt1,
944
+ e.alt2,
945
+ e.alt3
946
+ ].map((e) => `<div class="simulator-theme-preview-cell" style="background: ${e}"></div>`).join("");
947
+ return `<div class="simulator-theme-preview" style="background: ${e.g_bg}">${t}</div>`;
948
+ }
949
+ function ue() {
950
+ return {
951
+ id: "theme",
952
+ label: "Theme",
953
+ render() {
954
+ return "\n <div class=\"theme-view-container\">\n <div class=\"theme-header\">\n <span class=\"simulator-label\">Select Theme</span>\n </div>\n <div id=\"simulator-themes\" class=\"simulator-themes\"></div>\n </div>\n ";
955
+ },
956
+ bind(e) {
957
+ let t = e.getElement("#simulator-themes");
958
+ t && n.forEach((n) => {
959
+ let r = document.createElement("div");
960
+ r.className = `simulator-theme-item${n.name === e.state.selectedTheme.name ? " selected" : ""}`, r.innerHTML = `
961
+ ${N(n)}
962
+ <div class="simulator-theme-name">${n.name}</div>
963
+ <div class="simulator-theme-type">${n.type}</div>
964
+ `, r.addEventListener("click", () => {
965
+ console.log("Simulator: Theme changed, reloading...", n.name), f(n.name), window.location.reload();
966
+ }), t.appendChild(r);
967
+ });
968
+ }
969
+ };
970
+ }
971
+ var P = "puzzmo_sim_api_mode", F = "http://localhost:8911", I = "https://api.puzzmo.com", L = () => localStorage.getItem(P) === "dev" ? "dev" : "prod", R = (e) => {
972
+ localStorage.setItem(P, e);
973
+ }, z = null, B = function() {
974
+ var t = e(function* () {
975
+ if (z !== null) return z;
976
+ try {
977
+ let e = new AbortController(), t = setTimeout(() => e.abort(), 1e3), n = yield fetch(`${F}/healthz`, { signal: e.signal });
978
+ return clearTimeout(t), z = n.ok, z;
979
+ } catch (e) {
980
+ return z = !1, !1;
981
+ }
982
+ });
983
+ return function() {
984
+ return t.apply(this, arguments);
985
+ };
986
+ }(), V = () => ({
987
+ apiURL: L() === "dev" ? F : I,
988
+ clientID: "protosdk:oauthclient",
989
+ redirectUri: `${window.location.origin}/oauth/callback`
990
+ }), H = () => {
991
+ let e = new Uint8Array(32);
992
+ return crypto.getRandomValues(e), Array.from(e, (e) => e.toString(16).padStart(2, "0")).join("");
993
+ }, U = "puzzmo_sim_oauth_token", W = "puzzmo_sim_oauth_refresh_token", G = (e) => localStorage.setItem(U, e), de = (e) => localStorage.setItem(W, e), K = () => {
994
+ let e = localStorage.getItem(U);
995
+ return console.log("[AuthView] getAccessToken:", {
996
+ TOKEN_KEY: U,
997
+ token: e ? `${e.substring(0, 20)}...` : null
998
+ }), e;
999
+ }, q = () => localStorage.getItem(W), J = () => {
1000
+ localStorage.removeItem(U), localStorage.removeItem(W);
1001
+ }, fe = () => {
1002
+ let e = V(), t = H();
1003
+ sessionStorage.setItem("oauth_state", t), sessionStorage.setItem("oauth_return_url", window.location.href);
1004
+ let n = new URL(`${e.apiURL}/oauth/auth`);
1005
+ n.searchParams.set("client_id", e.clientID), n.searchParams.set("response_type", "code"), n.searchParams.set("redirect_uri", e.redirectUri), n.searchParams.set("state", t), window.location.href = n.toString();
1006
+ }, pe = (e) => {
1007
+ try {
1008
+ let t = e.split(".");
1009
+ if (t.length !== 3) return !0;
1010
+ let n = JSON.parse(atob(t[1])).exp;
1011
+ return n ? Date.now() >= n * 1e3 - 300 * 1e3 : !0;
1012
+ } catch (e) {
1013
+ return !0;
1014
+ }
1015
+ }, me = function() {
1016
+ var t = e(function* () {
1017
+ let e = q();
1018
+ if (!e) return console.log("[AuthView] No refresh token available"), !1;
1019
+ let t = V();
1020
+ try {
1021
+ let n = new URLSearchParams({
1022
+ grant_type: "refresh_token",
1023
+ refresh_token: e,
1024
+ client_id: t.clientID
1025
+ }), r = yield fetch(`${t.apiURL}/oauth/token`, {
1026
+ method: "POST",
1027
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
1028
+ body: n.toString()
1029
+ });
1030
+ if (!r.ok) return console.error("[AuthView] Failed to refresh token:", r.statusText), !1;
1031
+ let i = yield r.json(), a = i.access_token || i.accessToken;
1032
+ if (!a) return console.error("[AuthView] No access token in refresh response"), !1;
1033
+ G(a);
1034
+ let o = i.refresh_token || i.refreshToken;
1035
+ return o && de(o), console.log("[AuthView] Successfully refreshed access token"), !0;
1036
+ } catch (e) {
1037
+ return console.error("[AuthView] Error refreshing token:", e), !1;
1038
+ }
1039
+ });
1040
+ return function() {
1041
+ return t.apply(this, arguments);
1042
+ };
1043
+ }(), he = function() {
1044
+ var t = e(function* (e, t) {
1045
+ let n = V(), r = sessionStorage.getItem("oauth_state");
1046
+ if (!r || r !== t) return console.error("OAuth state mismatch - possible CSRF attack"), null;
1047
+ sessionStorage.removeItem("oauth_state");
1048
+ try {
1049
+ let t = new URLSearchParams({
1050
+ grant_type: "authorization_code",
1051
+ code: e,
1052
+ client_id: n.clientID,
1053
+ redirect_uri: n.redirectUri
1054
+ }), r = yield fetch(`${n.apiURL}/oauth/token`, {
1055
+ method: "POST",
1056
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
1057
+ body: t.toString()
1058
+ });
1059
+ return r.ok ? yield r.json() : (console.error("Failed to exchange code for token:", r.statusText), null);
1060
+ } catch (e) {
1061
+ return console.error("Error exchanging code for token:", e), null;
1062
+ }
1063
+ });
1064
+ return function(e, n) {
1065
+ return t.apply(this, arguments);
1066
+ };
1067
+ }(), ge = function() {
1068
+ var t = e(function* (e, t = {}) {
1069
+ let n = V(), r = K();
1070
+ if (!r) throw Error("Not authenticated");
1071
+ if (pe(r)) if (console.log("[AuthView] Access token expired, attempting refresh..."), yield me()) {
1072
+ if (r = K(), !r) throw Error("Token refresh succeeded but no token available");
1073
+ } else throw J(), Error("Session expired. Please log in again.");
1074
+ let i = yield fetch(`${n.apiURL}/graphql`, {
1075
+ method: "POST",
1076
+ headers: {
1077
+ "Content-Type": "application/json",
1078
+ Authorization: `Bearer ${r}`,
1079
+ "auth-provider": "custom"
1080
+ },
1081
+ body: JSON.stringify({
1082
+ query: e,
1083
+ variables: t
1084
+ })
1085
+ });
1086
+ if (!i.ok) throw Error(`API request failed: ${i.statusText}`);
1087
+ return i.json();
1088
+ });
1089
+ return function(e) {
1090
+ return t.apply(this, arguments);
1091
+ };
1092
+ }(), _e = (e) => {
1093
+ try {
1094
+ console.log("[AuthView] decodeJWT input:", e);
1095
+ let t = e.split(".");
1096
+ if (console.log("[AuthView] JWT parts:", t.length), t.length !== 3) return null;
1097
+ let n = JSON.parse(atob(t[1]));
1098
+ return console.log("[AuthView] JWT payload:", n), n;
1099
+ } catch (e) {
1100
+ return console.error("[AuthView] decodeJWT error:", e), null;
1101
+ }
1102
+ };
1103
+ function ve() {
1104
+ let t = !1;
1105
+ return {
1106
+ id: "auth",
1107
+ label: "Auth",
1108
+ render() {
1109
+ let e = K(), t = !!e, n = L(), r = n === "dev" ? F : I, i = `<button class="simulator-btn tiny" id="auth-dev-toggle" style="display: none;">${n === "dev" ? "Using Dev" : "Dev"}</button>`;
1110
+ if (t) {
1111
+ let t = _e(e), n = t != null && t.exp ? (/* @__PURE__ */ new Date(t.exp * 1e3)).toLocaleString() : "Unknown", a = !!q(), o = a ? _e(q()) : null, s = o != null && o.exp ? (/* @__PURE__ */ new Date(o.exp * 1e3)).toLocaleString() : null;
1112
+ return console.log({ decoded: t }), `
1113
+ <div class="simulator-section">
1114
+ <div class="simulator-section-title auth-title-row">
1115
+ <span>Puzzmo Authentication</span>
1116
+ ${i}
1117
+ <button class="simulator-btn danger tiny" id="auth-logout">Logout</button>
1118
+ </div>
1119
+ <div id="auth-status" class="auth-status authenticated">
1120
+ <span class="indicator ready"></span>
1121
+ <span>Authenticated</span>
1122
+ </div>
1123
+ <div id="auth-user-info" class="auth-user-info">
1124
+ <div>User ID: <code>${(t == null ? void 0 : t.userID) || (t == null ? void 0 : t.sub) || "Unknown"}</code></div>
1125
+ <div>API: <code>${r}</code></div>
1126
+ <div>Access expires: <code>${n}</code></div>
1127
+ ${a ? `<div>Refresh expires: <code>${s || "Unknown"}</code></div>` : "<div class=\"auth-warning\">No refresh token</div>"}
1128
+ </div>
1129
+ ${a ? "<button class=\"simulator-btn secondary tiny\" id=\"auth-refresh\">Refresh Now</button>" : ""}
1130
+ </div>
1131
+ <div class="simulator-section">
1132
+ <div class="simulator-section-title">Test API Request</div>
1133
+ <div class="simulator-row">
1134
+ <button class="simulator-btn primary" id="auth-test-api">Fetch Current User</button>
1135
+ </div>
1136
+ <div id="auth-api-result" class="auth-api-result"></div>
1137
+ </div>
1138
+ `;
1139
+ }
1140
+ return `
1141
+ <div class="simulator-section">
1142
+ <div class="simulator-section-title auth-title-row">
1143
+ <span>Puzzmo Authentication</span>
1144
+ ${i}
1145
+ </div>
1146
+ <div id="auth-status" class="auth-status">
1147
+ <span class="indicator waiting"></span>
1148
+ <span>Not authenticated</span>
1149
+ </div>
1150
+ <p class="auth-description">
1151
+ Login with your Puzzmo account to make authenticated API requests.
1152
+ ${n === "dev" ? `<br><strong>Using local dev server:</strong> ${F}` : ""}
1153
+ </p>
1154
+ <div class="simulator-row">
1155
+ <button class="simulator-btn primary" id="auth-login">Login with Puzzmo</button>
1156
+ </div>
1157
+ <div id="auth-error" class="auth-error"></div>
1158
+ </div>
1159
+ `;
1160
+ },
1161
+ bind(n) {
1162
+ let r = n.getElement("#auth-login"), i = n.getElement("#auth-logout"), a = n.getElement("#auth-refresh"), o = n.getElement("#auth-test-api"), s = n.getElement("#auth-api-result"), c = n.getElement("#auth-dev-toggle");
1163
+ t ? z && c && (c.style.display = "", L() === "dev" && c.classList.add("active")) : (t = !0, B().then((e) => {
1164
+ e && c && (c.style.display = "", L() === "dev" && c.classList.add("active"));
1165
+ })), c == null || c.addEventListener("click", () => {
1166
+ R(L() === "dev" ? "prod" : "dev"), J(), window.location.reload();
1167
+ }), r == null || r.addEventListener("click", () => {
1168
+ fe();
1169
+ }), i == null || i.addEventListener("click", () => {
1170
+ J(), window.location.reload();
1171
+ }), a == null || a.addEventListener("click", e(function* () {
1172
+ a.disabled = !0, a.textContent = "Refreshing...", (yield me()) ? window.location.reload() : (a.textContent = "Refresh Failed", a.disabled = !1);
1173
+ })), o == null || o.addEventListener("click", e(function* () {
1174
+ if (s) {
1175
+ s.innerHTML = "<div class=\"loading\">Loading...</div>";
1176
+ try {
1177
+ let t = yield ge("\n query {\n currentUser {\n id\n username\n usernameID\n name\n }\n }\n ");
1178
+ if (t.errors) {
1179
+ var e;
1180
+ s.innerHTML = `<div class="error">Error: ${((e = t.errors[0]) == null ? void 0 : e.message) || "Unknown error"}</div>`;
1181
+ } else s.innerHTML = `<pre>${JSON.stringify(t.data, null, 2)}</pre>`;
1182
+ } catch (e) {
1183
+ s.innerHTML = `<div class="error">Error: ${e instanceof Error ? e.message : "Unknown error"}</div>`;
1184
+ }
1185
+ }
1186
+ }));
1187
+ },
1188
+ onActivate(t) {
1189
+ return e(function* () {
1190
+ let e = new URLSearchParams(window.location.search), n = e.get("code"), r = e.get("state"), i = e.get("error");
1191
+ if (i) {
1192
+ let e = t.getElement("#auth-error");
1193
+ e && (e.innerHTML = `<div class="error">OAuth error: ${i}</div>`), window.history.replaceState({}, "", window.location.pathname);
1194
+ return;
1195
+ }
1196
+ if (n && r) {
1197
+ let e = t.getElement("#auth-status");
1198
+ e && (e.innerHTML = "<span class=\"indicator waiting\"></span><span>Exchanging code...</span>");
1199
+ let i = yield he(n, r);
1200
+ if (window.history.replaceState({}, "", window.location.pathname), i) {
1201
+ let e = i.access_token || i.accessToken;
1202
+ if (e) {
1203
+ G(e);
1204
+ let t = i.refresh_token || i.refreshToken;
1205
+ t && de(t);
1206
+ }
1207
+ window.location.reload();
1208
+ } else {
1209
+ let e = t.getElement("#auth-error");
1210
+ e && (e.innerHTML = "<div class=\"error\">Failed to exchange code for token</div>");
1211
+ }
1212
+ }
1213
+ })();
1214
+ }
1215
+ };
1216
+ }
1217
+ var ye = "puzzmo_sim_api_mode", be = "http://localhost:8911", xe = "https://api.puzzmo.com", Y = "puzzmo_sim_oauth_token", X = "puzzmo_sim_oauth_refresh_token", Se = () => localStorage.getItem(ye) === "dev" ? "dev" : "prod", Z = () => localStorage.getItem(Y), Ce = () => localStorage.getItem(X), we = (e) => localStorage.setItem(Y, e), Te = (e) => localStorage.setItem(X, e), Ee = () => {
1218
+ localStorage.removeItem(Y), localStorage.removeItem(X);
1219
+ }, De = (e) => {
1220
+ try {
1221
+ let t = e.split(".");
1222
+ if (t.length !== 3) return !0;
1223
+ let n = JSON.parse(atob(t[1])).exp;
1224
+ return n ? Date.now() >= n * 1e3 - 300 * 1e3 : !0;
1225
+ } catch (e) {
1226
+ return !0;
1227
+ }
1228
+ }, Oe = function() {
1229
+ var t = e(function* () {
1230
+ let e = Ce();
1231
+ if (!e) return !1;
1232
+ let t = Se() === "dev" ? be : xe;
1233
+ try {
1234
+ let n = new URLSearchParams({
1235
+ grant_type: "refresh_token",
1236
+ refresh_token: e,
1237
+ client_id: "protosdk:oauthclient"
1238
+ }), r = yield fetch(`${t}/oauth/token`, {
1239
+ method: "POST",
1240
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
1241
+ body: n.toString()
1242
+ });
1243
+ if (!r.ok) return !1;
1244
+ let i = yield r.json(), a = i.access_token || i.accessToken;
1245
+ if (!a) return !1;
1246
+ we(a);
1247
+ let o = i.refresh_token || i.refreshToken;
1248
+ return o && Te(o), !0;
1249
+ } catch (e) {
1250
+ return !1;
1251
+ }
1252
+ });
1253
+ return function() {
1254
+ return t.apply(this, arguments);
1255
+ };
1256
+ }(), ke = function() {
1257
+ var t = e(function* (e, t = {}) {
1258
+ let n = Se() === "dev" ? be : xe, r = Z();
1259
+ if (!r) throw Error("Not authenticated");
1260
+ if (De(r)) if (yield Oe()) {
1261
+ if (r = Z(), !r) throw Error("Token refresh succeeded but no token available");
1262
+ } else throw Ee(), Error("Session expired. Please log in again.");
1263
+ let i = yield fetch(`${n}/graphql`, {
1264
+ method: "POST",
1265
+ headers: {
1266
+ "Content-Type": "application/json",
1267
+ Authorization: `Bearer ${r}`,
1268
+ "auth-provider": "custom"
1269
+ },
1270
+ body: JSON.stringify({
1271
+ query: e,
1272
+ variables: t
1273
+ })
1274
+ });
1275
+ if (!i.ok) throw Error(`API request failed: ${i.statusText}`);
1276
+ return i.json();
1277
+ });
1278
+ return function(e) {
1279
+ return t.apply(this, arguments);
1280
+ };
1281
+ }(), Ae = "\n query GameFeaturesQuery($slug: ID!) {\n game(id: $slug) {\n id\n slug\n displayName\n featuresArr\n gameFeatures {\n slug\n title\n features {\n featureID\n title\n isEnabled\n }\n }\n }\n }\n", je = "\n mutation ToggleFeatureMutation($gameSlug: ID!, $input: UpdateGameInput!) {\n updateGame(id: $gameSlug, input: $input) {\n id\n featuresArr\n gameFeatures {\n slug\n title\n features {\n featureID\n title\n isEnabled\n }\n }\n }\n }\n", Me = (e, t) => {
1282
+ let n = t - 1, r = Math.floor(n / 31), i = n % 31, a = [...e];
1283
+ for (; a.length <= r;) a.push(0);
1284
+ return a[r] = a[r] ^ 1 << i, a;
1285
+ };
1286
+ const Q = () => !!Z();
1287
+ function Ne() {
1288
+ let n = null, r = !1, i = null, a = function() {
1289
+ var t = e(function* (e) {
1290
+ r = !0, i = null;
1291
+ try {
1292
+ var t;
1293
+ let r = yield ke(Ae, { slug: e });
1294
+ if (r.errors) {
1295
+ var a;
1296
+ i = ((a = r.errors[0]) == null ? void 0 : a.message) || "Unknown error", n = null;
1297
+ } else (t = r.data) != null && t.game ? n = r.data.game : (i = "Game not found", n = null);
1298
+ } catch (e) {
1299
+ i = e instanceof Error ? e.message : "Unknown error", n = null;
1300
+ } finally {
1301
+ r = !1;
1302
+ }
1303
+ });
1304
+ return function(e) {
1305
+ return t.apply(this, arguments);
1306
+ };
1307
+ }(), o = function() {
1308
+ var r = e(function* (e) {
1309
+ if (!n) return;
1310
+ let r = Me(n.featuresArr, e);
1311
+ try {
1312
+ var i;
1313
+ let e = yield ke(je, {
1314
+ gameSlug: n.slug,
1315
+ input: { featuresArr: r }
1316
+ });
1317
+ if (e.errors) {
1318
+ var a;
1319
+ console.error("Failed to toggle feature:", (a = e.errors[0]) == null ? void 0 : a.message);
1320
+ } else (i = e.data) != null && i.updateGame && (n = t(t({}, n), {}, {
1321
+ featuresArr: e.data.updateGame.featuresArr,
1322
+ gameFeatures: e.data.updateGame.gameFeatures
1323
+ }));
1324
+ } catch (e) {
1325
+ console.error("Failed to toggle feature:", e);
1326
+ }
1327
+ });
1328
+ return function(e) {
1329
+ return r.apply(this, arguments);
1330
+ };
1331
+ }(), s = () => {
1332
+ if (r) return "<div class=\"features-loading\">Loading features...</div>";
1333
+ if (i) return `<div class="features-error">${i}</div>`;
1334
+ if (!n) return "<div class=\"features-empty\">Enter your game slug above to load features</div>";
1335
+ let e = n.gameFeatures.map((e) => {
1336
+ let t = e.features.map((e) => {
1337
+ let t = e.isEnabled ? "enabled" : "disabled", n = e.isEnabled ? "✓" : "✗";
1338
+ return `
1339
+ <div class="feature-item ${t}" data-feature-id="${e.featureID}">
1340
+ <span class="feature-status">${n}</span>
1341
+ <span class="feature-title">${e.title}</span>
1342
+ </div>
1343
+ `;
1344
+ }).join("");
1345
+ return `
1346
+ <div class="feature-group">
1347
+ <div class="feature-group-title">${e.title}</div>
1348
+ <div class="feature-group-items">${t}</div>
1349
+ </div>
1350
+ `;
1351
+ }).join("");
1352
+ return `
1353
+ <div class="features-game-name">${n.displayName}</div>
1354
+ ${e}
1355
+ `;
1356
+ };
1357
+ return {
1358
+ id: "features",
1359
+ label: "Features",
1360
+ render() {
1361
+ return Q() ? `
1362
+ <div class="features-view-container">
1363
+ <div class="simulator-section">
1364
+ <div class="simulator-section-title">Game Features</div>
1365
+ <div class="features-slug-input">
1366
+ <input type="text" class="simulator-input" id="features-game-slug" placeholder="Game slug (e.g. crossword)" />
1367
+ <button class="simulator-btn primary" id="features-load-btn">Load</button>
1368
+ </div>
1369
+ </div>
1370
+ <div class="simulator-divider"></div>
1371
+ <div id="features-content" class="features-content">
1372
+ ${s()}
1373
+ </div>
1374
+ </div>
1375
+ ` : "\n <div class=\"features-view-container\">\n <div class=\"simulator-section\">\n <div class=\"simulator-section-title\">Game Features</div>\n <div class=\"features-auth-required\">\n <p>You must be logged in to view and edit game features.</p>\n <p>Go to the <strong>Auth</strong> tab to log in with your Puzzmo account.</p>\n </div>\n </div>\n </div>\n ";
1376
+ },
1377
+ bind(t) {
1378
+ let r = t.getElement("#features-load-btn"), i = t.getElement("#features-game-slug"), c = t.getElement("#features-content"), l = () => {
1379
+ c && (c.innerHTML = s(), u());
1380
+ }, u = () => {
1381
+ var n;
1382
+ let r = (n = t.getElement("#features-content")) == null ? void 0 : n.querySelectorAll(".feature-item");
1383
+ r == null || r.forEach((t) => {
1384
+ t.addEventListener("click", e(function* () {
1385
+ let e = parseInt(t.getAttribute("data-feature-id") || "0");
1386
+ e > 0 && (t.classList.add("updating"), yield o(e), l());
1387
+ }));
1388
+ });
1389
+ }, d = function() {
1390
+ var t = e(function* (e) {
1391
+ e && (r && (r.disabled = !0, r.textContent = "Loading..."), yield a(e), l(), r && (r.disabled = !1, r.textContent = "Load"));
1392
+ });
1393
+ return function(e) {
1394
+ return t.apply(this, arguments);
1395
+ };
1396
+ }();
1397
+ r == null || r.addEventListener("click", e(function* () {
1398
+ let e = i == null ? void 0 : i.value.trim();
1399
+ e && (yield d(e));
1400
+ })), i == null || i.addEventListener("keypress", (e) => {
1401
+ e.key === "Enter" && (r == null || r.click());
1402
+ }), console.log("[FeaturesView] bind called, ctx.gameSlug:", t.gameSlug, "slugInput:", i), t.gameSlug && i && (i.value = t.gameSlug, Q() && !n && d(t.gameSlug)), u();
1403
+ },
1404
+ onActivate(e) {
1405
+ let t = e.getElement("#simulator-tab-features");
1406
+ t && (t.innerHTML = this.render(), this.bind(e));
1407
+ }
1408
+ };
1409
+ }
1410
+ var Pe = "./sample-puzzle.json", $ = null;
1411
+ /**
1412
+ * Creates the Simulator UI and message handling.
1413
+ * If called multiple times, updates the existing instance with new settings (e.g., fixtures).
1414
+ */
1415
+ function Fe(t = {}) {
1416
+ var n, r, i;
1417
+ if (console.log("[Simulator] createSimulator called with config:", {
1418
+ slug: t.slug,
1419
+ hasFixtures: !!t.fixtures
1420
+ }), $) return t.fixtures && (console.log("[Simulator] Instance already exists, updating fixtures"), $.updateFixtures(t.fixtures)), $;
1421
+ let a = (n = t.puzzlePath) == null ? Pe : n, o = (r = t.autoStart) == null ? !0 : r, s = t.fixtures ? v(t.fixtures) : null, c = s ? Array.from(s.keys()).sort() : [], f = oe(), p = le(), m = [
1422
+ re(),
1423
+ ae(),
1424
+ f,
1425
+ se(),
1426
+ ce(),
1427
+ p,
1428
+ ue(),
1429
+ ve(),
1430
+ Ne()
1431
+ ], h = m.map((e) => e.id), g = l(t, c, h), _ = {
1432
+ pause: "<svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"currentColor\"><rect x=\"1\" y=\"1\" width=\"3\" height=\"8\"/><rect x=\"6\" y=\"1\" width=\"3\" height=\"8\"/></svg>",
1433
+ play: "<svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"currentColor\"><polygon points=\"2,1 9,5 2,9\"/></svg>",
1434
+ retry: "<svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"currentColor\"><path d=\"M5 1C2.8 1 1 2.8 1 5s1.8 4 4 4c1.8 0 3.3-1.2 3.8-2.8H7.5c-.4.9-1.3 1.5-2.5 1.5-1.5 0-2.7-1.2-2.7-2.7S3.5 2.3 5 2.3c.7 0 1.4.3 1.9.8L5.5 4.5H9V1L7.6 2.4C6.9 1.5 5.9 1 5 1z\"/></svg>",
1435
+ cog: "<svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"currentColor\"><path d=\"M9.5 5.8l-.8-.5c0-.2.1-.5.1-.8s0-.5-.1-.8l.8-.5c.1-.1.2-.2.1-.4l-.8-1.4c-.1-.1-.2-.2-.4-.1l-1 .3c-.3-.3-.7-.5-1.1-.6L6.1.2C6.1.1 6 0 5.8 0H4.2c-.2 0-.3.1-.3.2l-.2 1c-.4.1-.7.3-1.1.6l-1-.3c-.2 0-.3 0-.4.1l-.8 1.4c-.1.2 0 .3.1.4l.8.5c0 .2-.1.5-.1.8s0 .5.1.8l-.8.5c-.1.1-.2.2-.1.4l.8 1.4c.1.1.2.2.4.1l1-.3c.3.3.7.5 1.1.6l.2 1c0 .1.1.2.3.2h1.6c.2 0 .3-.1.3-.2l.2-1c.4-.1.7-.3 1.1-.6l1 .3c.2 0 .3 0 .4-.1l.8-1.4c.1-.2 0-.3-.1-.4zM5 6.5c-.8 0-1.5-.7-1.5-1.5S4.2 3.5 5 3.5 6.5 4.2 6.5 5 5.8 6.5 5 6.5z\"/></svg>",
1436
+ minimize: "<svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"currentColor\"><rect x=\"1\" y=\"4\" width=\"8\" height=\"2\"/></svg>",
1437
+ expand: "<svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"currentColor\"><polygon points=\"1,1 7,4 1,7\"/></svg>"
1438
+ }, y = document.createElement("div");
1439
+ y.id = "simulator", y.innerHTML = `
1440
+ <style>
1441
+ :root {
1442
+ --sim-bg: #1a1a2e;
1443
+ --sim-bg-alt: #16213e;
1444
+ --sim-panel: #0f0f1a;
1445
+ --sim-border: #3a3a5c;
1446
+ --sim-border-light: #5a5a8c;
1447
+ --sim-accent: #ffd700;
1448
+ --sim-accent-hover: #ffed4a;
1449
+ --sim-text: #e8e8e8;
1450
+ --sim-text-dim: #888899;
1451
+ --sim-success: #4ade80;
1452
+ --sim-error: #f87171;
1453
+ --sim-warning: #fbbf24;
1454
+ --sim-blue: #60a5fa;
1455
+ }
1456
+ #simulator {
1457
+ position: fixed;
1458
+ bottom: 4px;
1459
+ left: 4px;
1460
+ z-index: 999999;
1461
+ font: 11px/1.4 "Menlo", "Monaco", "Consolas", monospace;
1462
+ user-select: none;
1463
+ }
1464
+ #simulator-panel {
1465
+ background: var(--sim-panel);
1466
+ border: 2px solid var(--sim-border);
1467
+ border-radius: 4px;
1468
+ color: var(--sim-text);
1469
+ width: 420px;
1470
+ box-shadow: 4px 4px 0 rgba(0,0,0,0.5);
1471
+ }
1472
+ #simulator-panel.collapsed {
1473
+ width: auto;
1474
+ }
1475
+ #simulator-header {
1476
+ display: flex;
1477
+ align-items: center;
1478
+ padding: 4px 8px;
1479
+ background: var(--sim-bg);
1480
+ border-bottom: 2px solid var(--sim-border);
1481
+ gap: 0;
1482
+ }
1483
+ #simulator-panel.collapsed #simulator-header {
1484
+ border-bottom: none;
1485
+ cursor: pointer;
1486
+ }
1487
+ #simulator-panel.collapsed #simulator-header:hover {
1488
+ background: var(--sim-bg-alt);
1489
+ }
1490
+ .header-sep {
1491
+ color: var(--sim-border-light);
1492
+ margin: 0 8px;
1493
+ opacity: 0.6;
1494
+ }
1495
+ .header-spacer {
1496
+ flex: 1;
1497
+ }
1498
+ #simulator-title {
1499
+ color: var(--sim-accent);
1500
+ text-transform: uppercase;
1501
+ letter-spacing: 1px;
1502
+ font-size: 10px;
1503
+ font-weight: bold;
1504
+ }
1505
+ #simulator-header-controls {
1506
+ display: flex;
1507
+ gap: 2px;
1508
+ }
1509
+ .header-icon-btn {
1510
+ width: 20px;
1511
+ height: 20px;
1512
+ display: flex;
1513
+ align-items: center;
1514
+ justify-content: center;
1515
+ background: transparent;
1516
+ border: none;
1517
+ border-radius: 2px;
1518
+ color: var(--sim-text);
1519
+ cursor: pointer;
1520
+ padding: 0;
1521
+ }
1522
+ .header-icon-btn:hover:not(:disabled) {
1523
+ background: var(--sim-border);
1524
+ color: var(--sim-accent);
1525
+ }
1526
+ .header-icon-btn:disabled {
1527
+ opacity: 0.3;
1528
+ cursor: not-allowed;
1529
+ }
1530
+ .header-icon-btn.active {
1531
+ background: var(--sim-accent);
1532
+ color: var(--sim-panel);
1533
+ }
1534
+ #simulator-header-status {
1535
+ display: flex;
1536
+ align-items: center;
1537
+ gap: 4px;
1538
+ font-size: 9px;
1539
+ color: var(--sim-text-dim);
1540
+ }
1541
+ #simulator-header-indicator {
1542
+ width: 6px;
1543
+ height: 6px;
1544
+ border-radius: 50%;
1545
+ background: var(--sim-text-dim);
1546
+ flex-shrink: 0;
1547
+ }
1548
+ #simulator-header-indicator.ready {
1549
+ background: var(--sim-success);
1550
+ box-shadow: 0 0 4px var(--sim-success);
1551
+ }
1552
+ #simulator-header-indicator.waiting {
1553
+ background: var(--sim-warning);
1554
+ box-shadow: 0 0 4px var(--sim-warning);
1555
+ }
1556
+ #simulator-header-indicator.paused {
1557
+ background: var(--sim-error);
1558
+ box-shadow: 0 0 4px var(--sim-error);
1559
+ }
1560
+ #simulator-timer {
1561
+ font-size: 11px;
1562
+ color: var(--sim-text);
1563
+ font-family: "Menlo", monospace;
1564
+ font-weight: bold;
1565
+ font-variant-numeric: tabular-nums;
1566
+ min-width: 38px;
1567
+ }
1568
+ #simulator-timer .penalty {
1569
+ color: var(--sim-error);
1570
+ margin-left: 2px;
1571
+ }
1572
+ /* Collapsed state - show minimal bar */
1573
+ #simulator-panel.collapsed .header-sep,
1574
+ #simulator-panel.collapsed #simulator-header-controls,
1575
+ #simulator-panel.collapsed #simulator-header-status,
1576
+ #simulator-panel.collapsed #simulator-header-settings,
1577
+ #simulator-panel.collapsed #simulator-toggle {
1578
+ display: none;
1579
+ }
1580
+ #simulator-panel.collapsed #simulator-title {
1581
+ cursor: pointer;
1582
+ }
1583
+ #simulator-panel.collapsed #simulator-timer {
1584
+ margin-left: 8px;
1585
+ }
1586
+ #simulator-body {
1587
+ display: flex;
1588
+ flex-direction: row;
1589
+ }
1590
+ #simulator-panel.collapsed #simulator-body {
1591
+ display: none;
1592
+ }
1593
+ #simulator-tabs {
1594
+ display: flex;
1595
+ flex-direction: column;
1596
+ background: var(--sim-bg);
1597
+ padding: 4px;
1598
+ gap: 2px;
1599
+ border-right: 2px solid var(--sim-border);
1600
+ }
1601
+ .simulator-tab {
1602
+ padding: 2px 3px;
1603
+ background: var(--sim-bg-alt);
1604
+ border: 2px solid var(--sim-border);
1605
+ border-radius: 2px;
1606
+ color: var(--sim-text-dim);
1607
+ cursor: pointer;
1608
+ font: inherit;
1609
+ text-transform: uppercase;
1610
+ font-size: 9px;
1611
+ font-weight: bold;
1612
+ letter-spacing: 0.5px;
1613
+ min-height: 0;
1614
+ }
1615
+ .simulator-tab:hover {
1616
+ color: var(--sim-text);
1617
+ background: var(--sim-border);
1618
+ }
1619
+ .simulator-tab.active {
1620
+ color: var(--sim-panel);
1621
+ background: var(--sim-accent);
1622
+ border-color: var(--sim-accent);
1623
+ }
1624
+ .simulator-tab {
1625
+ position: relative;
1626
+ }
1627
+ .simulator-tab-badge {
1628
+ position: absolute;
1629
+ top: -4px;
1630
+ right: -4px;
1631
+ min-width: 14px;
1632
+ height: 14px;
1633
+ padding: 0 3px;
1634
+ background: var(--sim-blue);
1635
+ color: #fff;
1636
+ font-size: 8px;
1637
+ font-weight: bold;
1638
+ border-radius: 7px;
1639
+ display: flex;
1640
+ align-items: center;
1641
+ justify-content: center;
1642
+ box-shadow: 0 1px 2px rgba(0,0,0,0.3);
1643
+ line-height: 1;
1644
+ text-align: center;
1645
+ box-sizing: border-box;
1646
+ }
1647
+ .simulator-tab-badge:empty {
1648
+ display: none;
1649
+ }
1650
+ #simulator-content {
1651
+ padding: 6px;
1652
+ background: var(--sim-panel);
1653
+ height: 500px;
1654
+ flex: 1;
1655
+ overflow-y: auto;
1656
+ }
1657
+ #simulator-content.hidden {
1658
+ display: none;
1659
+ }
1660
+ #simulator-content::-webkit-scrollbar {
1661
+ width: 8px;
1662
+ }
1663
+ #simulator-content::-webkit-scrollbar-track {
1664
+ background: var(--sim-bg);
1665
+ }
1666
+ #simulator-content::-webkit-scrollbar-thumb {
1667
+ background: var(--sim-border);
1668
+ border-radius: 2px;
1669
+ }
1670
+ .simulator-btn {
1671
+ padding: 4px 8px;
1672
+ background: var(--sim-bg-alt);
1673
+ border: 2px solid var(--sim-border);
1674
+ border-radius: 2px;
1675
+ color: var(--sim-text);
1676
+ font: inherit;
1677
+ font-size: 10px;
1678
+ font-weight: bold;
1679
+ text-transform: uppercase;
1680
+ letter-spacing: 1px;
1681
+ cursor: pointer;
1682
+ }
1683
+ .simulator-btn:hover {
1684
+ background: var(--sim-border);
1685
+ border-color: var(--sim-border-light);
1686
+ }
1687
+ .simulator-btn:active {
1688
+ transform: translate(1px, 1px);
1689
+ }
1690
+ .simulator-btn.primary {
1691
+ background: var(--sim-accent);
1692
+ border-color: var(--sim-accent);
1693
+ color: var(--sim-panel);
1694
+ }
1695
+ .simulator-btn.primary:hover {
1696
+ background: var(--sim-accent-hover);
1697
+ border-color: var(--sim-accent-hover);
1698
+ }
1699
+ .simulator-btn.danger {
1700
+ background: var(--sim-error);
1701
+ border-color: var(--sim-error);
1702
+ color: #fff;
1703
+ }
1704
+ .simulator-btn.danger:hover {
1705
+ background: #ef4444;
1706
+ border-color: #ef4444;
1707
+ }
1708
+ .simulator-btn:disabled {
1709
+ opacity: 0.4;
1710
+ cursor: not-allowed;
1711
+ transform: none;
1712
+ }
1713
+ .simulator-btn.subtle {
1714
+ background: transparent;
1715
+ border-color: transparent;
1716
+ color: var(--sim-text-dim);
1717
+ }
1718
+ .simulator-btn.subtle:hover:not(:disabled) {
1719
+ background: var(--sim-bg-alt);
1720
+ border-color: var(--sim-border);
1721
+ color: var(--sim-text);
1722
+ }
1723
+ #simulator-status {
1724
+ font-size: 10px;
1725
+ color: var(--sim-text-dim);
1726
+ padding: 4px 0 6px;
1727
+ display: flex;
1728
+ align-items: center;
1729
+ gap: 6px;
1730
+ }
1731
+ #simulator-status .indicator {
1732
+ width: 8px;
1733
+ height: 8px;
1734
+ border-radius: 2px;
1735
+ background: var(--sim-text-dim);
1736
+ }
1737
+ #simulator-status .indicator.ready {
1738
+ background: var(--sim-success);
1739
+ box-shadow: 0 0 6px var(--sim-success);
1740
+ }
1741
+ #simulator-status .indicator.waiting {
1742
+ background: var(--sim-warning);
1743
+ box-shadow: 0 0 6px var(--sim-warning);
1744
+ }
1745
+ #simulator-status .indicator.paused {
1746
+ background: var(--sim-error);
1747
+ box-shadow: 0 0 6px var(--sim-error);
1748
+ }
1749
+ .simulator-row {
1750
+ display: flex;
1751
+ gap: 4px;
1752
+ margin-top: 4px;
1753
+ }
1754
+ .simulator-row .simulator-btn {
1755
+ flex: 1;
1756
+ }
1757
+ .simulator-divider {
1758
+ height: 2px;
1759
+ background: var(--sim-border);
1760
+ margin: 8px 0;
1761
+ }
1762
+ .simulator-field {
1763
+ margin-bottom: 6px;
1764
+ }
1765
+ .simulator-select {
1766
+ width: 100%;
1767
+ padding: 4px 6px;
1768
+ background: var(--sim-bg);
1769
+ border: 2px solid var(--sim-border);
1770
+ border-radius: 2px;
1771
+ color: var(--sim-text);
1772
+ font: inherit;
1773
+ font-size: 10px;
1774
+ cursor: pointer;
1775
+ }
1776
+ .simulator-select:focus {
1777
+ outline: none;
1778
+ border-color: var(--sim-accent);
1779
+ }
1780
+ .simulator-select option {
1781
+ background: var(--sim-bg);
1782
+ color: var(--sim-text);
1783
+ }
1784
+ .simulator-fixtures {
1785
+ margin-bottom: 8px;
1786
+ padding-bottom: 8px;
1787
+ border-bottom: 2px solid var(--sim-border);
1788
+ }
1789
+ .simulator-label {
1790
+ display: block;
1791
+ color: var(--sim-accent);
1792
+ text-transform: uppercase;
1793
+ font-size: 9px;
1794
+ font-weight: bold;
1795
+ letter-spacing: 1px;
1796
+ margin-bottom: 4px;
1797
+ }
1798
+ .simulator-textarea {
1799
+ width: 100%;
1800
+ min-height: 40px;
1801
+ background: var(--sim-bg);
1802
+ border: 2px solid var(--sim-border);
1803
+ border-radius: 2px;
1804
+ color: var(--sim-text);
1805
+ font: 10px/1.4 "Menlo", monospace;
1806
+ padding: 4px;
1807
+ resize: none;
1808
+ box-sizing: border-box;
1809
+ overflow-y: auto;
1810
+ }
1811
+ .simulator-textarea.auto-resize {
1812
+ resize: none;
1813
+ overflow-y: auto;
1814
+ }
1815
+ .simulator-textarea:focus {
1816
+ outline: none;
1817
+ border-color: var(--sim-accent);
1818
+ }
1819
+ .simulator-input {
1820
+ width: 100%;
1821
+ background: var(--sim-bg);
1822
+ border: 2px solid var(--sim-border);
1823
+ border-radius: 2px;
1824
+ color: var(--sim-text);
1825
+ font: 10px/1.4 "Menlo", monospace;
1826
+ padding: 4px 6px;
1827
+ box-sizing: border-box;
1828
+ }
1829
+ .simulator-input:focus {
1830
+ outline: none;
1831
+ border-color: var(--sim-accent);
1832
+ }
1833
+ .simulator-input::placeholder {
1834
+ color: var(--sim-text-dim);
1835
+ }
1836
+ .simulator-tab-content {
1837
+ display: none;
1838
+ }
1839
+ .simulator-tab-content.active {
1840
+ display: block;
1841
+ }
1842
+ .msgs-view-container {
1843
+ display: flex;
1844
+ flex-direction: column;
1845
+ height: 100%;
1846
+ overflow: hidden;
1847
+ }
1848
+ .msgs-header {
1849
+ display: flex;
1850
+ justify-content: space-between;
1851
+ align-items: center;
1852
+ margin-bottom: 6px;
1853
+ flex-shrink: 0;
1854
+ }
1855
+ #simulator-msgs-log {
1856
+ display: flex;
1857
+ flex-direction: column;
1858
+ gap: 2px;
1859
+ flex: 1;
1860
+ overflow-y: auto;
1861
+ }
1862
+ .simulator-msg {
1863
+ padding: 3px 4px;
1864
+ background: var(--sim-bg);
1865
+ border: 1px solid var(--sim-border);
1866
+ border-radius: 2px;
1867
+ font-size: 10px;
1868
+ }
1869
+ .simulator-msg.out {
1870
+ border-left: 2px solid var(--sim-accent);
1871
+ }
1872
+ .simulator-msg.in {
1873
+ border-left: 2px solid var(--sim-blue);
1874
+ }
1875
+ .simulator-msg-header {
1876
+ display: flex;
1877
+ justify-content: space-between;
1878
+ align-items: center;
1879
+ margin-bottom: 2px;
1880
+ }
1881
+ .simulator-msg-type {
1882
+ font-weight: bold;
1883
+ color: var(--sim-text);
1884
+ }
1885
+ .simulator-msg.out .simulator-msg-type {
1886
+ color: var(--sim-accent);
1887
+ }
1888
+ .simulator-msg.in .simulator-msg-type {
1889
+ color: var(--sim-blue);
1890
+ }
1891
+ .simulator-msg-time {
1892
+ color: var(--sim-text-dim);
1893
+ font-size: 9px;
1894
+ }
1895
+ .simulator-msg-data {
1896
+ color: var(--sim-text-dim);
1897
+ font-size: 9px;
1898
+ white-space: pre-wrap;
1899
+ word-break: break-all;
1900
+ max-height: 60px;
1901
+ overflow: hidden;
1902
+ cursor: pointer;
1903
+ border-radius: 2px;
1904
+ padding: 2px 4px;
1905
+ background: var(--sim-bg-alt);
1906
+ }
1907
+ .simulator-msg-data:hover {
1908
+ background: var(--sim-border);
1909
+ }
1910
+ .simulator-msg.expanded {
1911
+ flex: 1;
1912
+ display: flex;
1913
+ flex-direction: column;
1914
+ }
1915
+ .simulator-msg.expanded .simulator-msg-data {
1916
+ max-height: none;
1917
+ flex: 1;
1918
+ overflow-y: auto;
1919
+ }
1920
+ .simulator-empty {
1921
+ color: var(--sim-text-dim);
1922
+ font-size: 10px;
1923
+ text-align: center;
1924
+ padding: 20px;
1925
+ }
1926
+ .simulator-value {
1927
+ color: var(--sim-text);
1928
+ font-size: 10px;
1929
+ padding: 4px;
1930
+ background: var(--sim-bg);
1931
+ border: 1px solid var(--sim-border);
1932
+ border-radius: 2px;
1933
+ }
1934
+ .simulator-deeds {
1935
+ display: flex;
1936
+ flex-direction: column;
1937
+ gap: 2px;
1938
+ }
1939
+ .simulator-deed {
1940
+ display: flex;
1941
+ justify-content: space-between;
1942
+ padding: 3px 4px;
1943
+ background: var(--sim-bg);
1944
+ border: 1px solid var(--sim-border);
1945
+ border-radius: 2px;
1946
+ font-size: 10px;
1947
+ }
1948
+ .simulator-deed-name {
1949
+ color: var(--sim-text);
1950
+ }
1951
+ .simulator-deed-value {
1952
+ color: var(--sim-accent);
1953
+ font-weight: bold;
1954
+ }
1955
+ .thumb-view-container {
1956
+ display: flex;
1957
+ flex-direction: column;
1958
+ height: 100%;
1959
+ overflow: hidden;
1960
+ }
1961
+ .thumb-header {
1962
+ display: flex;
1963
+ justify-content: space-between;
1964
+ align-items: center;
1965
+ margin-bottom: 6px;
1966
+ flex-shrink: 0;
1967
+ }
1968
+ #simulator-thumb-preview {
1969
+ background: var(--sim-thumb-bg, transparent);
1970
+ border: 2px solid var(--sim-border);
1971
+ border-radius: 2px;
1972
+ padding: 8px;
1973
+ display: flex;
1974
+ align-items: center;
1975
+ justify-content: center;
1976
+ aspect-ratio: 1;
1977
+ width: 100%;
1978
+ box-sizing: border-box;
1979
+ }
1980
+ #simulator-thumb-preview svg {
1981
+ width: 100%;
1982
+ height: 100%;
1983
+ max-width: 100%;
1984
+ max-height: 100%;
1985
+ }
1986
+ #simulator-thumb-fn {
1987
+ font-size: 10px;
1988
+ color: var(--sim-text-dim);
1989
+ margin-top: 4px;
1990
+ }
1991
+ .theme-view-container {
1992
+ display: flex;
1993
+ flex-direction: column;
1994
+ height: 100%;
1995
+ overflow: hidden;
1996
+ }
1997
+ .theme-header {
1998
+ display: flex;
1999
+ justify-content: space-between;
2000
+ align-items: center;
2001
+ margin-bottom: 6px;
2002
+ flex-shrink: 0;
2003
+ }
2004
+ .simulator-themes {
2005
+ display: flex;
2006
+ flex-direction: column;
2007
+ gap: 4px;
2008
+ flex: 1;
2009
+ overflow-y: auto;
2010
+ }
2011
+ .simulator-theme-item {
2012
+ display: flex;
2013
+ align-items: center;
2014
+ gap: 8px;
2015
+ padding: 4px;
2016
+ background: var(--sim-bg);
2017
+ border: 2px solid var(--sim-border);
2018
+ border-radius: 2px;
2019
+ cursor: pointer;
2020
+ }
2021
+ .simulator-theme-item:hover {
2022
+ border-color: var(--sim-border-light);
2023
+ }
2024
+ .simulator-theme-item.selected {
2025
+ border-color: var(--sim-accent);
2026
+ background: var(--sim-bg-alt);
2027
+ }
2028
+ .simulator-theme-preview {
2029
+ width: 48px;
2030
+ height: 32px;
2031
+ display: grid;
2032
+ grid-template-columns: repeat(3, 1fr);
2033
+ grid-template-rows: repeat(2, 1fr);
2034
+ gap: 1px;
2035
+ border-radius: 2px;
2036
+ overflow: hidden;
2037
+ flex-shrink: 0;
2038
+ }
2039
+ .simulator-theme-preview-cell {
2040
+ width: 100%;
2041
+ height: 100%;
2042
+ }
2043
+ .simulator-theme-name {
2044
+ font-size: 10px;
2045
+ color: var(--sim-text);
2046
+ flex: 1;
2047
+ }
2048
+ .simulator-theme-type {
2049
+ font-size: 9px;
2050
+ color: var(--sim-text-dim);
2051
+ text-transform: uppercase;
2052
+ }
2053
+ /* Auth tab styles */
2054
+ .simulator-section {
2055
+ margin-bottom: 12px;
2056
+ }
2057
+ .simulator-section-title {
2058
+ color: var(--sim-accent);
2059
+ text-transform: uppercase;
2060
+ font-size: 10px;
2061
+ font-weight: bold;
2062
+ letter-spacing: 1px;
2063
+ margin-bottom: 6px;
2064
+ padding-bottom: 4px;
2065
+ border-bottom: 1px solid var(--sim-border);
2066
+ }
2067
+ .auth-header-row {
2068
+ display: flex;
2069
+ align-items: center;
2070
+ justify-content: space-between;
2071
+ margin-bottom: 6px;
2072
+ }
2073
+ .auth-status {
2074
+ display: flex;
2075
+ align-items: center;
2076
+ gap: 6px;
2077
+ font-size: 10px;
2078
+ color: var(--sim-text-dim);
2079
+ padding: 4px 0;
2080
+ }
2081
+ .auth-status.authenticated {
2082
+ color: var(--sim-success);
2083
+ }
2084
+ .simulator-btn.small {
2085
+ padding: 2px 6px;
2086
+ font-size: 9px;
2087
+ }
2088
+ .simulator-btn.tiny {
2089
+ padding: 3px 2px;
2090
+ font-size: 8px;
2091
+ border-width: 1px;
2092
+ line-height: 1;
2093
+ min-height: 0;
2094
+ height: auto;
2095
+ }
2096
+ .auth-title-row {
2097
+ display: flex;
2098
+ align-items: center;
2099
+ gap: 6px;
2100
+ }
2101
+ .auth-title-row > span:first-child {
2102
+ flex: 1;
2103
+ }
2104
+ .auth-title-row .simulator-btn.active {
2105
+ background: var(--sim-accent);
2106
+ color: black;
2107
+ }
2108
+ .auth-description {
2109
+ font-size: 10px;
2110
+ color: var(--sim-text-dim);
2111
+ margin: 6px 0;
2112
+ line-height: 1.4;
2113
+ }
2114
+ .auth-user-info {
2115
+ font-size: 10px;
2116
+ color: var(--sim-text-dim);
2117
+ padding: 6px;
2118
+ background: var(--sim-bg);
2119
+ border: 1px solid var(--sim-border);
2120
+ border-radius: 2px;
2121
+ margin-bottom: 8px;
2122
+ }
2123
+ .auth-user-info div {
2124
+ margin-bottom: 4px;
2125
+ }
2126
+ .auth-user-info div:last-child {
2127
+ margin-bottom: 0;
2128
+ }
2129
+ .auth-user-info code {
2130
+ color: var(--sim-text);
2131
+ background: var(--sim-bg-alt);
2132
+ padding: 1px 4px;
2133
+ border-radius: 2px;
2134
+ }
2135
+ .auth-warning {
2136
+ color: var(--sim-warning);
2137
+ font-style: italic;
2138
+ }
2139
+ .auth-error {
2140
+ margin-top: 8px;
2141
+ }
2142
+ .auth-error .error,
2143
+ .auth-api-result .error {
2144
+ color: var(--sim-error);
2145
+ font-size: 10px;
2146
+ padding: 6px;
2147
+ background: rgba(248, 113, 113, 0.1);
2148
+ border: 1px solid var(--sim-error);
2149
+ border-radius: 2px;
2150
+ }
2151
+ .auth-api-result {
2152
+ margin-top: 8px;
2153
+ }
2154
+ .auth-api-result pre {
2155
+ font-size: 9px;
2156
+ color: var(--sim-text);
2157
+ background: var(--sim-bg);
2158
+ border: 1px solid var(--sim-border);
2159
+ border-radius: 2px;
2160
+ padding: 6px;
2161
+ margin: 0;
2162
+ white-space: pre-wrap;
2163
+ word-break: break-all;
2164
+ max-height: 150px;
2165
+ overflow-y: auto;
2166
+ }
2167
+ .auth-api-result .loading {
2168
+ font-size: 10px;
2169
+ color: var(--sim-text-dim);
2170
+ padding: 6px;
2171
+ background: var(--sim-bg);
2172
+ border: 1px solid var(--sim-border);
2173
+ border-radius: 2px;
2174
+ }
2175
+ /* Data view styles */
2176
+ .data-view-container {
2177
+ display: flex;
2178
+ flex-direction: column;
2179
+ height: 100%;
2180
+ overflow: hidden;
2181
+ }
2182
+ .data-subtabs {
2183
+ display: flex;
2184
+ gap: 2px;
2185
+ margin-bottom: 8px;
2186
+ flex-shrink: 0;
2187
+ }
2188
+ .data-subtab {
2189
+ padding: 4px 10px;
2190
+ background: var(--sim-bg-alt);
2191
+ border: 1px solid var(--sim-border);
2192
+ border-radius: 2px;
2193
+ color: var(--sim-text-dim);
2194
+ cursor: pointer;
2195
+ font: inherit;
2196
+ font-size: 9px;
2197
+ font-weight: bold;
2198
+ text-transform: uppercase;
2199
+ letter-spacing: 0.5px;
2200
+ }
2201
+ .data-subtab:hover {
2202
+ color: var(--sim-text);
2203
+ background: var(--sim-border);
2204
+ }
2205
+ .data-subtab.active {
2206
+ color: var(--sim-panel);
2207
+ background: var(--sim-accent);
2208
+ border-color: var(--sim-accent);
2209
+ }
2210
+ .data-subtab-content {
2211
+ display: none;
2212
+ flex: 1;
2213
+ overflow-y: auto;
2214
+ overflow-x: hidden;
2215
+ }
2216
+ .data-subtab-content.active {
2217
+ display: flex;
2218
+ flex-direction: column;
2219
+ }
2220
+ /* History tab styles */
2221
+ .history-header {
2222
+ display: flex;
2223
+ justify-content: space-between;
2224
+ align-items: center;
2225
+ margin-bottom: 6px;
2226
+ flex-shrink: 0;
2227
+ }
2228
+ .history-list {
2229
+ display: flex;
2230
+ flex-direction: column;
2231
+ gap: 4px;
2232
+ flex: 1;
2233
+ overflow-y: auto;
2234
+ }
2235
+ .history-item {
2236
+ padding: 6px;
2237
+ background: var(--sim-bg);
2238
+ border: 1px solid var(--sim-border);
2239
+ border-radius: 2px;
2240
+ display: flex;
2241
+ flex-direction: row;
2242
+ gap: 8px;
2243
+ }
2244
+ .history-item:hover {
2245
+ border-color: var(--sim-border-light);
2246
+ }
2247
+ .history-item-thumb {
2248
+ width: 80px;
2249
+ height: 80px;
2250
+ flex-shrink: 0;
2251
+ background: var(--history-thumb-bg, var(--sim-bg-alt));
2252
+ border: 1px solid var(--sim-border);
2253
+ border-radius: 2px;
2254
+ display: flex;
2255
+ align-items: center;
2256
+ justify-content: center;
2257
+ overflow: hidden;
2258
+ }
2259
+ .history-item-thumb svg {
2260
+ width: 100%;
2261
+ height: 100%;
2262
+ }
2263
+ .history-item-thumb:empty {
2264
+ display: none;
2265
+ }
2266
+ .history-item-content {
2267
+ flex: 1;
2268
+ min-width: 0;
2269
+ display: flex;
2270
+ flex-direction: column;
2271
+ gap: 4px;
2272
+ }
2273
+ .history-item-header {
2274
+ display: flex;
2275
+ align-items: center;
2276
+ gap: 6px;
2277
+ }
2278
+ .history-item-num {
2279
+ color: var(--sim-accent);
2280
+ font-weight: bold;
2281
+ font-size: 9px;
2282
+ }
2283
+ .history-item-time {
2284
+ color: var(--sim-text-dim);
2285
+ font-size: 9px;
2286
+ flex: 1;
2287
+ }
2288
+ .history-item-preview {
2289
+ font-size: 9px;
2290
+ color: var(--sim-text);
2291
+ word-break: break-all;
2292
+ line-height: 1.3;
2293
+ background: var(--sim-bg-alt);
2294
+ padding: 3px 4px;
2295
+ border-radius: 2px;
2296
+ flex: 1;
2297
+ overflow: hidden;
2298
+ }
2299
+ /* Saves tab styles */
2300
+ .save-new {
2301
+ display: flex;
2302
+ gap: 4px;
2303
+ margin-bottom: 8px;
2304
+ flex-shrink: 0;
2305
+ }
2306
+ .save-new .simulator-input {
2307
+ flex: 1;
2308
+ }
2309
+ .saves-list {
2310
+ display: flex;
2311
+ flex-direction: column;
2312
+ gap: 4px;
2313
+ flex: 1;
2314
+ overflow-y: auto;
2315
+ }
2316
+ .save-item {
2317
+ padding: 6px;
2318
+ background: var(--sim-bg);
2319
+ border: 1px solid var(--sim-border);
2320
+ border-radius: 2px;
2321
+ }
2322
+ .save-item:hover {
2323
+ border-color: var(--sim-border-light);
2324
+ }
2325
+ .save-item-header {
2326
+ display: flex;
2327
+ justify-content: space-between;
2328
+ align-items: center;
2329
+ margin-bottom: 4px;
2330
+ }
2331
+ .save-item-name {
2332
+ color: var(--sim-text);
2333
+ font-weight: bold;
2334
+ font-size: 10px;
2335
+ }
2336
+ .save-item-time {
2337
+ color: var(--sim-text-dim);
2338
+ font-size: 9px;
2339
+ }
2340
+ .save-item-actions {
2341
+ display: flex;
2342
+ gap: 4px;
2343
+ }
2344
+ /* Features view styles */
2345
+ .features-view-container {
2346
+ display: flex;
2347
+ flex-direction: column;
2348
+ height: 100%;
2349
+ overflow: hidden;
2350
+ }
2351
+ .features-slug-input {
2352
+ display: flex;
2353
+ gap: 4px;
2354
+ margin-bottom: 8px;
2355
+ }
2356
+ .features-slug-input .simulator-input {
2357
+ flex: 1;
2358
+ }
2359
+ .features-content {
2360
+ flex: 1;
2361
+ overflow-y: auto;
2362
+ }
2363
+ .features-loading {
2364
+ color: var(--sim-text-dim);
2365
+ font-size: 10px;
2366
+ text-align: center;
2367
+ padding: 20px;
2368
+ }
2369
+ .features-error {
2370
+ color: var(--sim-error);
2371
+ font-size: 10px;
2372
+ padding: 8px;
2373
+ background: rgba(248, 113, 113, 0.1);
2374
+ border: 1px solid var(--sim-error);
2375
+ border-radius: 2px;
2376
+ }
2377
+ .features-empty {
2378
+ color: var(--sim-text-dim);
2379
+ font-size: 10px;
2380
+ text-align: center;
2381
+ padding: 20px;
2382
+ }
2383
+ .features-auth-required {
2384
+ color: var(--sim-text-dim);
2385
+ font-size: 10px;
2386
+ padding: 12px;
2387
+ background: var(--sim-bg);
2388
+ border: 1px solid var(--sim-border);
2389
+ border-radius: 2px;
2390
+ line-height: 1.5;
2391
+ }
2392
+ .features-auth-required p {
2393
+ margin: 0 0 8px 0;
2394
+ }
2395
+ .features-auth-required p:last-child {
2396
+ margin-bottom: 0;
2397
+ }
2398
+ .features-game-name {
2399
+ color: var(--sim-accent);
2400
+ font-size: 11px;
2401
+ font-weight: bold;
2402
+ margin-bottom: 8px;
2403
+ padding-bottom: 4px;
2404
+ border-bottom: 1px solid var(--sim-border);
2405
+ }
2406
+ .feature-group {
2407
+ margin-bottom: 12px;
2408
+ }
2409
+ .feature-group-title {
2410
+ color: var(--sim-text);
2411
+ font-size: 10px;
2412
+ font-weight: bold;
2413
+ text-transform: uppercase;
2414
+ letter-spacing: 0.5px;
2415
+ margin-bottom: 6px;
2416
+ padding-bottom: 2px;
2417
+ border-bottom: 1px solid var(--sim-border);
2418
+ }
2419
+ .feature-group-items {
2420
+ display: flex;
2421
+ flex-direction: column;
2422
+ gap: 2px;
2423
+ }
2424
+ .feature-item {
2425
+ display: flex;
2426
+ align-items: center;
2427
+ gap: 8px;
2428
+ padding: 4px 6px;
2429
+ background: var(--sim-bg);
2430
+ border: 1px solid var(--sim-border);
2431
+ border-radius: 2px;
2432
+ cursor: pointer;
2433
+ transition: all 0.15s ease;
2434
+ }
2435
+ .feature-item:hover {
2436
+ border-color: var(--sim-border-light);
2437
+ background: var(--sim-bg-alt);
2438
+ }
2439
+ .feature-item.updating {
2440
+ opacity: 0.5;
2441
+ pointer-events: none;
2442
+ }
2443
+ .feature-status {
2444
+ font-size: 14px;
2445
+ width: 18px;
2446
+ text-align: center;
2447
+ flex-shrink: 0;
2448
+ }
2449
+ .feature-item.enabled .feature-status {
2450
+ color: var(--sim-success);
2451
+ }
2452
+ .feature-item.disabled .feature-status {
2453
+ color: var(--sim-error);
2454
+ opacity: 0.5;
2455
+ }
2456
+ .feature-title {
2457
+ font-size: 10px;
2458
+ color: var(--sim-text);
2459
+ flex: 1;
2460
+ }
2461
+ .feature-item.disabled .feature-title {
2462
+ color: var(--sim-text-dim);
2463
+ }
2464
+ /* Checkpoints view styles */
2465
+ .checkpoints-view-container {
2466
+ display: flex;
2467
+ flex-direction: column;
2468
+ height: 100%;
2469
+ overflow: hidden;
2470
+ }
2471
+ .checkpoints-header {
2472
+ display: flex;
2473
+ justify-content: space-between;
2474
+ align-items: center;
2475
+ margin-bottom: 6px;
2476
+ flex-shrink: 0;
2477
+ }
2478
+ .checkpoints-list {
2479
+ display: flex;
2480
+ flex-direction: column;
2481
+ gap: 4px;
2482
+ flex: 1;
2483
+ overflow-y: auto;
2484
+ }
2485
+ .checkpoint-item {
2486
+ padding: 6px;
2487
+ background: var(--sim-bg);
2488
+ border: 1px solid var(--sim-border);
2489
+ border-left: 3px solid var(--sim-accent);
2490
+ border-radius: 2px;
2491
+ }
2492
+ .checkpoint-item:hover {
2493
+ border-color: var(--sim-border-light);
2494
+ border-left-color: var(--sim-accent);
2495
+ }
2496
+ .checkpoint-header {
2497
+ display: flex;
2498
+ justify-content: space-between;
2499
+ align-items: center;
2500
+ }
2501
+ .checkpoint-item .simulator-deeds {
2502
+ margin-top: 4px;
2503
+ }
2504
+ .checkpoint-name {
2505
+ color: var(--sim-accent);
2506
+ font-weight: bold;
2507
+ font-size: 10px;
2508
+ }
2509
+ .checkpoint-time {
2510
+ color: var(--sim-text-dim);
2511
+ font-size: 9px;
2512
+ }
2513
+ </style>
2514
+ <div id="simulator-panel" class="${g.isCollapsed ? "collapsed" : ""}">
2515
+ <div id="simulator-header">
2516
+ <span id="simulator-title">PUZZMO SIMULATOR</span>
2517
+ <span class="header-sep">|</span>
2518
+ <div id="simulator-timer">--:--</div>
2519
+ <span class="header-sep">|</span>
2520
+ <div id="simulator-header-controls">
2521
+ <button id="simulator-header-pause" class="header-icon-btn" title="Pause" disabled>${_.pause}</button>
2522
+ <button id="simulator-header-retry" class="header-icon-btn" title="Retry" disabled>${_.retry}</button>
2523
+ </div>
2524
+ <span class="header-sep">|</span>
2525
+ <div id="simulator-header-status">
2526
+ <span id="simulator-header-indicator" class="waiting"></span>
2527
+ <span id="simulator-header-status-text">Waiting...</span>
2528
+ </div>
2529
+ <span class="header-spacer"></span>
2530
+ <button id="simulator-header-settings" class="header-icon-btn" title="Settings">${_.cog}</button>
2531
+ <button id="simulator-toggle" class="header-icon-btn" title="Minimize">${_.minimize}</button>
2532
+ </div>
2533
+ <div id="simulator-body">
2534
+ <div id="simulator-tabs">
2535
+ ${m.filter((e) => e.id !== "auth").map((e) => `<button class="simulator-tab" data-tab="${e.id}">${e.label}<span class="simulator-tab-badge" data-badge="${e.id}"></span></button>`).join("")}
2536
+ </div>
2537
+ <div id="simulator-content" class="hidden">
2538
+ ${m.map((e) => `<div id="simulator-tab-${e.id}" class="simulator-tab-content">${e.render()}</div>`).join("")}
2539
+ </div>
2540
+ </div>
2541
+ </div>
2542
+ `, document.body.appendChild(y);
2543
+ let b = y.querySelector("#simulator-panel"), x = y.querySelector("#simulator-header"), S = y.querySelector("#simulator-header-indicator"), ie = y.querySelector("#simulator-header-status-text"), C = y.querySelector("#simulator-header-pause"), w = y.querySelector("#simulator-header-retry"), T = y.querySelector("#simulator-header-settings"), E = y.querySelector("#simulator-toggle"), D = y.querySelector("#simulator-timer"), O = y.querySelector("#simulator-tabs"), k = y.querySelector("#simulator-content"), A = (e) => y.querySelector(e), j = (e) => {
2544
+ C.innerHTML = e ? _.play : _.pause, C.title = e ? "Resume" : "Pause";
2545
+ }, M = (e, t) => {
2546
+ let n = A("#simulator-status .text"), r = A("#simulator-status .indicator");
2547
+ n && (n.textContent = e), r && (r.className = `indicator ${t}`), S.className = t, ie.textContent = e;
2548
+ }, N = (e, t) => {
2549
+ t && t !== "0" ? D.innerHTML = `${e}<span class="penalty">+${t}</span>` : D.textContent = e;
2550
+ }, P = (e) => {
2551
+ var t;
2552
+ g.activeTab = e, k.classList.remove("hidden"), d(e), O.querySelectorAll(".simulator-tab").forEach((t) => {
2553
+ t.classList.toggle("active", t.getAttribute("data-tab") === e);
2554
+ }), y.querySelectorAll(".simulator-tab-content").forEach((t) => {
2555
+ t.classList.toggle("active", t.id === `simulator-tab-${e}`);
2556
+ }), T.classList.toggle("active", e === "auth");
2557
+ let n = m.find((t) => t.id === e);
2558
+ n == null || (t = n.onActivate) == null || t.call(n, V);
2559
+ }, F = (e) => {
2560
+ g.isCollapsed = e, b.classList.toggle("collapsed", e), u(e), e ? (k.classList.add("hidden"), O.querySelectorAll(".simulator-tab").forEach((e) => e.classList.remove("active"))) : P(g.activeTab);
2561
+ }, I = () => {
2562
+ p.updatePreview(V);
2563
+ }, L = function() {
2564
+ var t = e(function* () {
2565
+ if (g.puzzleData) return g.puzzleData;
2566
+ try {
2567
+ let e = yield fetch(a);
2568
+ if (!e.ok) throw Error(`Failed to load puzzle from ${a}`);
2569
+ g.puzzleData = yield e.json(), console.log("Simulator: Puzzle loaded", g.puzzleData), g.originalPuzzle = JSON.stringify(g.puzzleData, null, 2);
2570
+ let t = A("#simulator-puzzle");
2571
+ return t && (t.value = g.originalPuzzle), g.activeTab === "thumb" && I(), g.puzzleData;
2572
+ } catch (e) {
2573
+ throw console.error("Simulator: Failed to load puzzle", e), e;
2574
+ }
2575
+ });
2576
+ return function() {
2577
+ return t.apply(this, arguments);
2578
+ };
2579
+ }(), R = ee((e) => {
2580
+ f.addLogEntry(e, V);
2581
+ }), z = (e, t) => {
2582
+ te(e, t, R);
2583
+ }, B = (e, t) => {
2584
+ let n = y.querySelector(`[data-badge="${e}"]`);
2585
+ n && (n.textContent = t && t > 0 ? String(t) : "");
2586
+ }, V = {
2587
+ state: g,
2588
+ getElement: A,
2589
+ sendToGame: z,
2590
+ logMessage: R.log,
2591
+ loadPuzzle: L,
2592
+ updateStatus: M,
2593
+ updateTimer: N,
2594
+ setCollapsed: F,
2595
+ switchTab: P,
2596
+ updateThumbnail: I,
2597
+ updateBadge: B,
2598
+ fixtures: s,
2599
+ fixtureCategories: c,
2600
+ gameSlug: (i = t.slug) == null ? null : i
2601
+ };
2602
+ console.log("[Simulator] Context created with gameSlug:", V.gameSlug), m.forEach((e) => e.bind(V)), O.querySelectorAll(".simulator-tab").forEach((e) => {
2603
+ e.addEventListener("click", () => {
2604
+ let t = e.getAttribute("data-tab");
2605
+ P(t), B(t, 0);
2606
+ });
2607
+ }), E.addEventListener("click", (e) => {
2608
+ e.stopPropagation(), F(!0);
2609
+ }), C.addEventListener("click", (e) => {
2610
+ e.stopPropagation(), g.isPaused ? (z("RESUME_GAME", {}), g.isPaused = !1, j(!1), M("Running", "ready")) : (z("PAUSE_GAME", {}), g.isPaused = !0, j(!0), M("Paused", "paused"));
2611
+ let t = A("#simulator-pause");
2612
+ t && (t.textContent = g.isPaused ? "Resume" : "Pause");
2613
+ }), w.addEventListener("click", (e) => {
2614
+ e.stopPropagation(), z("RETRY_PUZZLE", {}), g.hasStarted = !1, g.isPaused = !1, j(!1), C.disabled = !0, M("Ready to retry", "ready");
2615
+ let t = A("#simulator-pause"), n = A("#simulator-start");
2616
+ t && (t.disabled = !0, t.textContent = "Pause"), n && (n.textContent = "Start");
2617
+ }), T.addEventListener("click", (e) => {
2618
+ e.stopPropagation(), g.isCollapsed && F(!1), P("auth");
2619
+ }), x.addEventListener("click", (e) => {
2620
+ g.isCollapsed && e.target !== E && F(!1);
2621
+ }), g.isCollapsed || P(g.activeTab);
2622
+ let H = new URLSearchParams(window.location.search);
2623
+ (H.has("code") || H.has("error")) && (F(!1), P("auth"));
2624
+ let U = (e) => ({
2625
+ userState: {
2626
+ gameSettings: {},
2627
+ id: "simulator-user",
2628
+ nakamaLogin: "simulator",
2629
+ ownerID: "simulator-owner"
2630
+ },
2631
+ currentUser: null,
2632
+ startOrFindGameplay: { gamePlayed: {
2633
+ additionalTimeAddedSecs: 0,
2634
+ boardState: g.currentInputStr,
2635
+ cheatsUsed: 0,
2636
+ combinedTimeSecs: 0,
2637
+ completed: !1,
2638
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2639
+ elapsedTimeSecs: 0,
2640
+ hintsUsed: 0,
2641
+ id: `simulator-gameplay-${Date.now()}`,
2642
+ metric1: 0,
2643
+ metric2: 0,
2644
+ metric3: 0,
2645
+ metric4: 0,
2646
+ metricStrings: [],
2647
+ ownerID: "simulator-owner",
2648
+ pointsAwarded: 0,
2649
+ resetsUsed: 0,
2650
+ slug: "simulator-game",
2651
+ viewerOwnsPuzzle: !0,
2652
+ puzzle: {
2653
+ id: "simulator-puzzle",
2654
+ name: "Proto Jig Puzzle",
2655
+ puzzle: JSON.stringify(e),
2656
+ seriesNumber: 1,
2657
+ game: {
2658
+ assetsPath: "./assets/",
2659
+ assetsSha: "",
2660
+ displayName: "Proto Game",
2661
+ exposedGlobalFunction: "startGame",
2662
+ jsPath: "",
2663
+ slug: "proto-game"
2664
+ }
2665
+ }
2666
+ } },
2667
+ theme: g.selectedTheme,
2668
+ hostFlags: [],
2669
+ hostContext: [],
2670
+ appRuntimeContract: "1.0"
2671
+ }), W = function() {
2672
+ var t = e(function* () {
2673
+ M("Loading puzzle...", "waiting");
2674
+ try {
2675
+ let e = U(yield L());
2676
+ M("Sending READY_DATA...", "waiting"), z("READY_DATA", e), M("Waiting for game to load...", "waiting");
2677
+ } catch (e) {
2678
+ M(`Error: ${e}`, "paused");
2679
+ }
2680
+ });
2681
+ return function() {
2682
+ return t.apply(this, arguments);
2683
+ };
2684
+ }(), G = () => {
2685
+ console.log("Simulator: Game loaded, ready to start"), w.disabled = !1, m.forEach((e) => {
2686
+ var t;
2687
+ return (t = e.onMessage) == null ? void 0 : t.call(e, "READY_GAME_LOADED", void 0, V);
2688
+ }), o && !g.hasStarted && setTimeout(() => {
2689
+ let e = A("#simulator-start");
2690
+ e == null || e.click(), C.disabled = !1, g.hasStarted = !0, M("Running", "ready");
2691
+ }, 100);
2692
+ };
2693
+ return ne((e, t) => {
2694
+ var n, r;
2695
+ if (e === "READY") {
2696
+ console.log("Simulator: Received READY from game"), W();
2697
+ return;
2698
+ }
2699
+ if (e === "INITIALIZE_SETTINGS") {
2700
+ console.log("Simulator: Game initialized settings", t);
2701
+ return;
2702
+ }
2703
+ if (e === "READY_GAME_LOADED") {
2704
+ G();
2705
+ return;
2706
+ }
2707
+ if (e === "TIMER_TICK") {
2708
+ if (t != null && t.display) {
2709
+ let [e, n] = t.display;
2710
+ N(e, n);
2711
+ }
2712
+ return;
2713
+ }
2714
+ if (e === "TIMER_SYNC") return;
2715
+ if (e === "SHOW_GAME_COMPLETE_SCREEN") {
2716
+ console.log("Simulator: Show completion screen", t);
2717
+ return;
2718
+ }
2719
+ if (e === "SIDEBAR_UPDATE") {
2720
+ console.log("Simulator: Sidebar update", t);
2721
+ return;
2722
+ }
2723
+ m.forEach((n) => {
2724
+ var r;
2725
+ return (r = n.onMessage) == null ? void 0 : r.call(n, e, t, V);
2726
+ });
2727
+ let i = (n = t == null || (r = t.input) == null ? void 0 : r.boardState) == null ? t == null ? void 0 : t.boardState : n;
2728
+ e === "UPLOAD_NEW_GAME_STATE" && i && (g.currentInputStr = i, g.activeTab === "thumb" && I(), console.log("Simulator: Game state uploaded", t)), e === "GAME_COMPLETED" && (console.log("Simulator: Game completed!", t), C.disabled = !0, g.hasStarted = !1, M("Completed!", "ready"));
2729
+ }, R), console.log("Simulator initialized"), $ = {
2730
+ updateFixtures: (e) => {
2731
+ s = v(e), c = Array.from(s.keys()).sort(), V.fixtures = s, V.fixtureCategories = c;
2732
+ let t = localStorage.getItem("simulator-fixture-category");
2733
+ if (!g.selectedCategory || !c.includes(g.selectedCategory)) {
2734
+ var n;
2735
+ g.selectedCategory = t && c.includes(t) ? t : (n = c[0]) == null ? null : n;
2736
+ }
2737
+ let r = m.find((e) => e.id === "ctrl");
2738
+ r == null || r.bind(V), console.log("Simulator: Fixtures updated", {
2739
+ categories: c,
2740
+ selectedCategory: g.selectedCategory
2741
+ });
2742
+ },
2743
+ sendToGame: z,
2744
+ loadPuzzle: L
2745
+ }, $;
2746
+ }
2747
+ export { Fe as t };
2748
+
2749
+ //# sourceMappingURL=createSimulator-9IxV0l3_.js.map