@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,1428 @@
1
+ const e=require(`./objectSpread2-C4RR_HMd.cjs`),t=[{name:`Puzzmo (light)`,type:`light`,key:`#FFAAAC`,keyFG:`#000000`,keyStrong:`#F7868B`,keyLight:`#FFD2D3`,g_key:`#FFAAAC`,subBrand:`#FFC000`,subBrandFG:`#000000`,player:`#5DBAFC`,playerFG:`#000000`,playerLight:`#9EDDFF`,alt1:`#98B389`,alt2:`#FAC16C`,alt3:`#D298FF`,fg:`#000000`,error:`#FF3C3C`,alwaysDark:`#1B1D29`,alwaysLight:`#FFFFFF`,g_bg:`#FFFFFF`,g_bgAlt:`#EBEBEB`,g_bgDark:`#D6D6D6`,g_textDark:`#1B1B28`,g_textLight:`#FFFFFF`,g_blank:`#000000`,g_unsolved:`#C2C2C2`,g_outline:`#1B1D29`,a_bg:`#F2F2F2`,a_bgAlt:`#ECECEC`,a_puzmo:`#FFC000`,a_headerText:`#000000`,a_table:`#F9F9F9`,a_tableAlt:`#F6F4F4`,a_inlineTag:`#D9D9D9`,a_anchor:`#1F97EE`,a_infoBG:`#FFFFFF`},{name:`Puzzmo (dark)`,type:`dark`,key:`#FFAAAC`,keyFG:`#000000`,keyStrong:`#F7868B`,keyLight:`#FFD2D3`,g_key:`#FFAAAC`,player:`#5DBAFC`,playerFG:`#000000`,playerLight:`#9EDDFF`,subBrand:`#FFC000`,subBrandFG:`#000000`,alt1:`#98B389`,alt2:`#FAC16C`,alt3:`#D298FF`,error:`#FF3C3C`,fg:`#ECECEC`,alwaysDark:`#1B1D29`,alwaysLight:`#FFFFFF`,g_bg:`#374351`,g_bgAlt:`#333D49`,g_bgDark:`#2C2F33`,g_textDark:`#F2F2F2`,g_textLight:`#20180E`,g_blank:`#000000`,g_unsolved:`#747474`,g_outline:`#646464`,a_bg:`#141620`,a_bgAlt:`#202433`,a_puzmo:`#FFC000`,a_headerText:`#A1BAD4`,a_table:`#303246`,a_tableAlt:`#393b52`,a_inlineTag:`#ECECEC`,a_anchor:`#1F97EE`,a_infoBG:`#282C3A`},{name:`Foshay`,type:`light`,key:`#98B389`,keyFG:`#313540`,keyStrong:`#87BD69`,keyLight:`#809B77`,g_key:`#98B389`,player:`#3EC0E5`,subBrand:`#FFC000`,subBrandFG:`#000000`,playerFG:`#292B35`,playerLight:`#A8B5D6`,alt1:`#D87DA4`,alt2:`#E3A54F`,alt3:`#D298FF`,error:`#FF3C3C`,fg:`#292B35`,alwaysDark:`#292B35`,alwaysLight:`#D1DBF2`,g_bg:`#949EBA`,g_bgAlt:`#8891AB`,g_bgDark:`#7B839B`,g_textDark:`#292B35`,g_textLight:`#FFFFFF`,g_blank:`#292B35`,g_unsolved:`#B6B7BA`,g_outline:`#676F83`,a_bg:`#828CA3`,a_bgAlt:`#7F889F`,a_puzmo:`#FFC000`,a_headerText:`#292B35`,a_table:`#7A8399`,a_tableAlt:`#767E94`,a_inlineTag:`#ECECEC`,a_anchor:`#56C9E9`,a_infoBG:`#767F95`},{name:`Bright white`,type:`light`,key:`#67ced2`,keyFG:`#000000`,keyStrong:`#26a0a5`,keyLight:`#ade6e9`,g_key:`#67ced2`,subBrand:`#FFC000`,subBrandFG:`#000000`,player:`#5DBAFC`,playerFG:`#000000`,playerLight:`#9EDDFF`,alt1:`#d26767`,alt2:`#fac16c`,alt3:`#7580bd`,fg:`#000000`,error:`#FF3C3C`,alwaysDark:`#111111`,alwaysLight:`#FFFFFF`,g_bg:`#f6f6f6`,g_bgAlt:`#F4F4F4`,g_bgDark:`#D6D6D6`,g_textDark:`#1B1B28`,g_textLight:`#FFFFFF`,g_blank:`#000000`,g_unsolved:`#C2C2C2`,g_outline:`#1B1D29`,a_bg:`#FFFFFF`,a_bgAlt:`#f8fbfc`,a_puzmo:`#FFC000`,a_headerText:`#000000`,a_table:`#EDEDED`,a_tableAlt:`#DBDBDB`,a_inlineTag:`#D9D9D9`,a_anchor:`#1F97EE`,a_infoBG:`#f6f6f6`},{name:`Submersible`,type:`dark`,key:`#CD6DC6`,keyFG:`#031698`,keyStrong:`#FF7ABC`,keyLight:`#B467CB`,g_key:`#CD6DC6`,subBrand:`#FFC000`,subBrandFG:`#000000`,player:`#4AB1D1`,playerFG:`#071D47`,playerLight:`#3C99D7`,alt1:`#8BA964`,alt2:`#C69A58`,alt3:`#7644B5`,fg:`#FFEBFF`,error:`#FF3C3C`,alwaysDark:`#031698`,alwaysLight:`#FFEBFF`,g_bg:`#043BED`,g_bgAlt:`#0A31CC`,g_bgDark:`#0E2DA8`,g_textDark:`#031698`,g_textLight:`#FFEBFF`,g_blank:`#031698`,g_unsolved:`#3662F1`,g_outline:`#031698`,a_bg:`#043BED`,a_bgAlt:`#0A31CC`,a_puzmo:`#FFC000`,a_headerText:`#FFEBFF`,a_table:`#043BED`,a_tableAlt:`#0A31CC`,a_inlineTag:`#FF7ABC`,a_anchor:`#FF7ABC`,a_infoBG:`#0A31CC`},{name:`Hot Dog (beta)`,type:`light`,key:`#FFFF00`,keyFG:`#000000`,keyStrong:`#FFE600`,keyLight:`#FFEC44`,g_key:`#FFFF00`,subBrand:`#FFC000`,subBrandFG:`#000000`,player:`#FF7A00`,playerFG:`#000000`,playerLight:`#FFA450`,alt1:`#3ABC5E`,alt2:`#5C3ABC`,alt3:`#BC3AAF`,fg:`#000000`,error:`#FF3C3C`,alwaysDark:`#1B1D29`,alwaysLight:`#FFFFFF`,g_bg:`#EBFF00`,g_bgAlt:`#EBEBEB`,g_bgDark:`#D6D6D6`,g_textDark:`#1B1B28`,g_textLight:`#FFFFFF`,g_blank:`#000000`,g_unsolved:`#C2C2C2`,g_outline:`#1B1D29`,a_bg:`#FF0000`,a_bgAlt:`#E50000`,a_puzmo:`#FFC000`,a_headerText:`#FFFFFF`,a_table:`#E50000`,a_tableAlt:`#FF2525`,a_inlineTag:`#000000`,a_anchor:`#000000`,a_infoBG:`#C6C6C6`},{name:`Outlook Hayesy (beta)`,type:`light`,key:`#DAB98C`,keyFG:`#000000`,keyStrong:`#B99368`,keyLight:`#DAB98C`,subBrand:`#FFC000`,subBrandFG:`#000000`,g_key:`#DAB98C`,player:`#5DBAFC`,playerFG:`#000000`,playerLight:`#9EDDFF`,alt1:`#5EC386`,alt2:`#5E93C3`,alt3:`#C35E5E`,fg:`#000000`,error:`#FF3C3C`,alwaysDark:`#5E390F`,alwaysLight:`#FFF3E4`,g_bg:`#FFFFFF`,g_bgAlt:`#EBEBEB`,g_bgDark:`#D6D6D6`,g_textDark:`#1B1B28`,g_textLight:`#FFFFFF`,g_blank:`#000000`,g_unsolved:`#C2C2C2`,g_outline:`#1B1D29`,a_bg:`#FEF5E8`,a_bgAlt:`#ffffff`,a_puzmo:`#FAC7CE`,a_headerText:`#000000`,a_table:`#FAE8D3`,a_tableAlt:`#EED7BC`,a_inlineTag:`#D9D9D9`,a_anchor:`#B99368`,a_infoBG:`#FFFFFF`},{name:`Console (beta)`,type:`dark`,key:`#957df9`,keyFG:`#000000`,keyStrong:`#590FF5`,keyLight:`#590FF5`,subBrand:`#FFC000`,subBrandFG:`#000000`,g_key:`#FFFF00`,player:`#ffffff`,playerFG:`#000000`,playerLight:`#9EDDFF`,alt1:`#590ff5`,alt2:`#00e200`,alt3:`#ff8a02`,fg:`#00e200`,error:`#FF3C3C`,alwaysDark:`#1B1D29`,alwaysLight:`#00e200`,g_bg:`#101428`,g_bgAlt:`#101428`,g_bgDark:`#00e200`,g_textDark:`#00e200`,g_textLight:`#590ff5`,g_blank:`#00e200`,g_unsolved:`#0000ff`,g_outline:`#00e200`,a_bg:`#000000`,a_bgAlt:`#112211`,a_puzmo:`#ffffff`,a_headerText:`#00e200`,a_table:`#000000`,a_tableAlt:`#002200`,a_inlineTag:`#D9D9D9`,a_anchor:`#957df9`,a_infoBG:`#001900`}];var n={collapsed:`simulator-collapsed`,tab:`simulator-tab`,theme:`simulator-theme`,fixtureCategory:`simulator-fixture-category`,fixturePuzzle:`simulator-fixture-puzzle`,renderHost:`simulator-render-host`,renderContext:`simulator-render-context`};function r(){let e=localStorage.getItem(n.theme);if(e){let n=t.find(t=>t.name===e);if(n)return n}return t[0]}function i(e){var t;let r=localStorage.getItem(n.tab);return r&&e.includes(r)?r:(t=e[0])==null?`ctrl`:t}function a(e){let t=localStorage.getItem(n.collapsed);return t===null?e:t===`true`}function o(){let e=localStorage.getItem(n.renderHost);return e&&[`game`,`app`,`opengraph`].includes(e)?e:`game`}function s(){let e=localStorage.getItem(n.renderContext);if(e&&[`preview`,`share`,`completed`,`timeline`].includes(e))return e}function c(e,t,c){var l,u;let d=localStorage.getItem(n.fixtureCategory),f=localStorage.getItem(n.fixturePuzzle);return{isCollapsed:a((l=e.collapsed)==null?!0:l),isPaused:!1,hasStarted:!1,activeTab:i(c),puzzleData:null,originalPuzzle:``,currentInputStr:``,completionData:null,selectedTheme:r(),selectedCategory:d&&t.includes(d)?d:(u=t[0])==null?null:u,selectedPuzzle:f==null?null:f,renderHost:o(),renderContext:s()}}function l(e){localStorage.setItem(n.collapsed,String(e))}function u(e){localStorage.setItem(n.tab,e)}function d(e){localStorage.setItem(n.theme,e)}function f(e){localStorage.setItem(n.fixtureCategory,e)}function p(e){localStorage.setItem(n.fixturePuzzle,e)}function m(){localStorage.removeItem(n.fixturePuzzle)}function h(e){e?localStorage.setItem(n.renderHost,e):localStorage.removeItem(n.renderHost)}function g(e){e?localStorage.setItem(n.renderContext,e):localStorage.removeItem(n.renderContext)}function ee(e){let t=[];return{log(n,r,i){let a={type:n,data:r,time:new Date().toLocaleTimeString(`en-US`,{hour12:!1,hour:`2-digit`,minute:`2-digit`,second:`2-digit`}),direction:i};t.push(a),t.length>100&&t.shift(),e==null||e(a)},clear(){t.length=0},getLog(){return t}}}function te(e,t,n){console.log(`Simulator sending:`,e,t),n==null||n.log(e,t,`out`),window.postMessage({type:e,data:t},`*`)}function ne(e,t){let n=n=>{var r,i,a;if(!(!(n==null||(r=n.data)==null)&&r.type))return;let o=n.data.type,s=(i=(a=n.data.data)==null?n.data.json:a)==null?{}:i;[`TIMER_TICK`,`TIMER_SYNC`].includes(o)||t==null||t.log(o,s,`in`),e(o,s)};return window.addEventListener(`message`,n),()=>window.removeEventListener(`message`,n)}function _(e){let t=new Map;console.log(`Simulator: Parsing fixtures`,Object.keys(e));for(let[o,s]of Object.entries(e)){var n,r,i,a;let e=o.split(`/`),c=(n=(r=e.pop())==null?void 0:r.replace(`.json`,``))==null?``:n,l=(i=e.pop())==null?`default`:i;t.has(l)||t.set(l,new Map);let u=(a=s.default)==null?s:a;t.get(l).set(c,u)}return t.forEach((e,n)=>{let r=new Map(Array.from(e.entries()).sort((e,t)=>{var n,r,i,a;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)}));t.set(n,r)}),t}function v(e,t){return e.length===0?``:`
2
+ <div class="simulator-fixtures">
3
+ <div class="simulator-field">
4
+ <label class="simulator-label">Category</label>
5
+ <select class="simulator-select" id="simulator-fixture-category">
6
+ ${e.map(e=>`<option value="${e}" ${e===t?`selected`:``}>${e}</option>`).join(``)}
7
+ </select>
8
+ </div>
9
+ <div class="simulator-field">
10
+ <label class="simulator-label">Puzzle</label>
11
+ <select class="simulator-select" id="simulator-fixture-puzzle"></select>
12
+ </div>
13
+ </div>
14
+ `}function y(e,t,n,r){let i=t.get(n);if(!i)return null;let a=Array.from(i.keys()),o=r;if(!r||!i.has(r)){var s;o=(s=a[0])==null?null:s}return e.innerHTML=a.map(e=>`<option value="${e}" ${e===o?`selected`:``}>${e}</option>`).join(``),o}function b(e,t,n){var r,i;return!t||!n||(r=(i=e.get(t))==null?void 0:i.get(n))==null?null:r}function re(){return{id:`ctrl`,label:`Ctrl`,render(){return`
15
+ <div id="simulator-fixtures-container"></div>
16
+ <div id="simulator-status">
17
+ <span class="indicator waiting"></span>
18
+ <span class="text">Waiting for READY...</span>
19
+ </div>
20
+ <div class="simulator-row">
21
+ <button class="simulator-btn primary" id="simulator-start" disabled>Start</button>
22
+ <button class="simulator-btn" id="simulator-pause" disabled>Pause</button>
23
+ </div>
24
+ <div class="simulator-row">
25
+ <button class="simulator-btn danger" id="simulator-retry" disabled>Retry</button>
26
+ </div>
27
+ `},bind(e){let t=e.getElement(`#simulator-start`),n=e.getElement(`#simulator-pause`),r=e.getElement(`#simulator-retry`),i=e.getElement(`#simulator-fixtures-container`);if(console.log(`Simulator: CtrlView.bind called`,{hasFixtures:!!e.fixtures,categories:e.fixtureCategories,selectedCategory:e.state.selectedCategory,selectedPuzzle:e.state.selectedPuzzle}),e.fixtures&&e.fixtureCategories.length>0&&i){i.innerHTML=v(e.fixtureCategories,e.state.selectedCategory);let t=e.getElement(`#simulator-fixture-category`),n=e.getElement(`#simulator-fixture-puzzle`);if(t&&n&&e.state.selectedCategory){e.state.selectedPuzzle=y(n,e.fixtures,e.state.selectedCategory,e.state.selectedPuzzle);let r=b(e.fixtures,e.state.selectedCategory,e.state.selectedPuzzle);console.log(`Simulator: Loading fixture puzzle`,{category:e.state.selectedCategory,puzzle:e.state.selectedPuzzle,hasPuzzleData:!!r}),r&&(e.state.puzzleData=r,e.state.originalPuzzle=JSON.stringify(r,null,2),e.state.selectedCategory&&f(e.state.selectedCategory),e.state.selectedPuzzle&&p(e.state.selectedPuzzle)),t.addEventListener(`change`,()=>{console.log(`Simulator: Category changed, reloading...`,t.value),f(t.value),m(),window.location.reload()}),n.addEventListener(`change`,()=>{console.log(`Simulator: Puzzle changed, reloading...`,n.value),p(n.value),window.location.reload()})}}t==null||t.addEventListener(`click`,()=>{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`))}),n==null||n.addEventListener(`click`,()=>{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`))}),r==null||r.addEventListener(`click`,()=>{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`)})},onMessage(e,t,n){let r=n.getElement(`#simulator-start`),i=n.getElement(`#simulator-pause`),a=n.getElement(`#simulator-retry`);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`))}}}var x=`simulator-saved-states`;function S(){let e=globalThis;for(let t of Object.keys(e))if(t.endsWith(`Thumbnail`)&&typeof e[t]==`function`)return{name:t,fn:e[t]};return null}function C(e,t){let n=S();if(!n)return``;try{let r=e.state.puzzleData?JSON.stringify(e.state.puzzleData):``,i={viewerIsOwner:!0,theme:e.state.selectedTheme,strict:!0,renderHost:`game`};return n.fn(r,t,i)}catch(e){return``}}var w=[];function T(e,t=8){let n=14*t+8+4;e.style.height=`auto`;let r=Math.min(Math.max(e.scrollHeight,40),n);e.style.height=`${r}px`}function ie(){let e=``,t=``;return{id:`data`,label:`Data`,render(){return`
28
+ <div class="data-view-container">
29
+ <div class="data-subtabs">
30
+ <button class="data-subtab active" data-subtab="edit">Edit</button>
31
+ <button class="data-subtab" data-subtab="history">History</button>
32
+ <button class="data-subtab" data-subtab="saves">Saves</button>
33
+ </div>
34
+
35
+ <div class="data-subtab-content active" id="data-subtab-edit">
36
+ <div class="simulator-field">
37
+ <label class="simulator-label">Puzzle String</label>
38
+ <textarea class="simulator-textarea auto-resize" id="simulator-puzzle" placeholder="Loading..."></textarea>
39
+ <div class="simulator-row">
40
+ <button class="simulator-btn subtle" id="simulator-puzzle-reset">Reset</button>
41
+ <button class="simulator-btn primary" id="simulator-puzzle-apply" disabled>Apply</button>
42
+ </div>
43
+ </div>
44
+ <div class="simulator-divider"></div>
45
+ <div class="simulator-field">
46
+ <label class="simulator-label">Input String</label>
47
+ <textarea class="simulator-textarea auto-resize" id="simulator-input" placeholder="No input yet..."></textarea>
48
+ <div class="simulator-row">
49
+ <button class="simulator-btn subtle" id="simulator-input-reset">Reset</button>
50
+ <button class="simulator-btn primary" id="simulator-input-apply" disabled>Apply</button>
51
+ </div>
52
+ </div>
53
+ </div>
54
+
55
+ <div class="data-subtab-content" id="data-subtab-history">
56
+ <div class="history-header">
57
+ <span class="simulator-label">Input String Timeline</span>
58
+ <button class="simulator-btn tiny" id="simulator-history-clear">Clear</button>
59
+ </div>
60
+ <div class="history-list" id="simulator-history-list">
61
+ <div class="simulator-empty">No history yet</div>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="data-subtab-content" id="data-subtab-saves">
66
+ <div class="save-new">
67
+ <input type="text" class="simulator-input" id="simulator-save-name" placeholder="Save name..." />
68
+ <button class="simulator-btn primary" id="simulator-save-btn">Save</button>
69
+ </div>
70
+ <div class="simulator-divider"></div>
71
+ <div class="saves-list" id="simulator-saves-list">
72
+ <div class="simulator-empty">No saved states</div>
73
+ </div>
74
+ </div>
75
+ </div>
76
+ `},bind(n){let r=n.getElement(`.data-subtabs`);r==null||r.querySelectorAll(`.data-subtab`).forEach(e=>{e.addEventListener(`click`,()=>{let t=e.getAttribute(`data-subtab`);if(!t)return;r.querySelectorAll(`.data-subtab`).forEach(e=>e.classList.remove(`active`)),e.classList.add(`active`);let i=n.getElement(`.data-view-container`);i==null||i.querySelectorAll(`.data-subtab-content`).forEach(e=>{e.classList.toggle(`active`,e.id===`data-subtab-${t}`)}),t===`edit`?A(n):t===`history`?D(n):t===`saves`&&O(n)})});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`);setTimeout(()=>{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))},0),i==null||i.addEventListener(`input`,()=>{T(i);let t=i.value!==e;s&&(s.disabled=!t)}),a==null||a.addEventListener(`input`,()=>{T(a);let e=a.value!==t;l&&(l.disabled=!e)}),o==null||o.addEventListener(`click`,()=>{i&&(i.value=n.state.originalPuzzle,e=n.state.originalPuzzle,T(i),s&&(s.disabled=!0))}),s==null||s.addEventListener(`click`,()=>{if(i)try{let t=JSON.parse(i.value);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}catch(e){console.error(`Simulator: Invalid puzzle JSON`,e),n.updateStatus(`Invalid JSON`,`paused`)}}),c==null||c.addEventListener(`click`,()=>{a&&(a.value=t,T(a),l&&(l.disabled=!0))}),l==null||l.addEventListener(`click`,()=>{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)});let f=n.getElement(`#simulator-history-clear`);f==null||f.addEventListener(`click`,()=>{w=[],D(n)});let p=n.getElement(`#simulator-save-name`),m=n.getElement(`#simulator-save-btn`);m==null||m.addEventListener(`click`,()=>{if(!p||!p.value.trim())return;let e=E(),t={name:p.value.trim(),puzzleStr:n.state.originalPuzzle,inputStr:n.state.currentInputStr,timestamp:Date.now()};e.push(t),localStorage.setItem(x,JSON.stringify(e)),p.value=``,O(n)}),O(n)},onActivate(n){e=n.state.originalPuzzle,t=n.state.currentInputStr,A(n),D(n)},onMessage(e,n,r){var i,a;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;if(e===`UPLOAD_NEW_GAME_STATE`&&c){if(r.state.currentInputStr=c,w.length===0||w[w.length-1].value!==c){w.push({value:c,timestamp:Date.now()}),w.length>100&&(w=w.slice(-100));let e=r.getElement(`#data-subtab-history`);e!=null&&e.classList.contains(`active`)&&D(r)}o&&(o.value=r.state.currentInputStr,t=r.state.currentInputStr,T(o),s&&(s.disabled=!0))}}}}function E(){try{let e=localStorage.getItem(x);return e?JSON.parse(e):[]}catch(e){return[]}}function D(e){let t=e.getElement(`#simulator-history-list`);if(t){if(t.style.setProperty(`--history-thumb-bg`,e.state.selectedTheme.a_bg),w.length===0){t.innerHTML=`<div class="simulator-empty">No history yet</div>`;return}t.innerHTML=[...w].reverse().map((t,n)=>{let r=w.length-1-n,i=new Date(t.timestamp).toLocaleTimeString(),a=t.value.length>60?t.value.slice(0,60)+`...`:t.value;return`
77
+ <div class="history-item" data-history-idx="${r}">
78
+ <div class="history-item-thumb">${C(e,t.value)}</div>
79
+ <div class="history-item-content">
80
+ <div class="history-item-header">
81
+ <span class="history-item-num">#${r+1}</span>
82
+ <span class="history-item-time">${i}</span>
83
+ <button class="simulator-btn tiny history-restore-btn" data-history-idx="${r}">Restore</button>
84
+ </div>
85
+ <div class="history-item-preview">${k(a)}</div>
86
+ </div>
87
+ </div>
88
+ `}).join(``),t.querySelectorAll(`.history-restore-btn`).forEach(t=>{t.addEventListener(`click`,t=>{let n=parseInt(t.target.getAttribute(`data-history-idx`)||`0`),r=w[n];if(r){e.state.currentInputStr=r.value;let t=e.getElement(`#simulator-input`);t&&(t.value=r.value,T(t)),e.updateStatus(`Input restored from history`,`ready`);let n=e.getElement(`.data-subtab[data-subtab="edit"]`);n==null||n.click()}})})}}function O(e){let t=e.getElement(`#simulator-saves-list`);if(!t)return;let n=E();if(n.length===0){t.innerHTML=`<div class="simulator-empty">No saved states</div>`;return}t.innerHTML=[...n].reverse().map((e,t)=>{let r=n.length-1-t,i=new Date(e.timestamp).toLocaleDateString(),a=new Date(e.timestamp).toLocaleTimeString();return`
89
+ <div class="save-item">
90
+ <div class="save-item-header">
91
+ <span class="save-item-name">${k(e.name)}</span>
92
+ <span class="save-item-time">${i} ${a}</span>
93
+ </div>
94
+ <div class="save-item-actions">
95
+ <button class="simulator-btn tiny save-load-btn" data-save-idx="${r}">Load</button>
96
+ <button class="simulator-btn tiny danger save-delete-btn" data-save-idx="${r}">Delete</button>
97
+ </div>
98
+ </div>
99
+ `}).join(``),t.querySelectorAll(`.save-load-btn`).forEach(t=>{t.addEventListener(`click`,t=>{let r=n[parseInt(t.target.getAttribute(`data-save-idx`)||`0`)];if(r){try{e.state.puzzleData=JSON.parse(r.puzzleStr),e.state.originalPuzzle=r.puzzleStr}catch(t){e.state.originalPuzzle=r.puzzleStr}e.state.currentInputStr=r.inputStr;let t=e.getElement(`#simulator-puzzle`),n=e.getElement(`#simulator-input`);t&&(t.value=r.puzzleStr,T(t)),n&&(n.value=r.inputStr,T(n)),e.updateStatus(`Loaded: ${r.name}`,`ready`);let i=e.getElement(`.data-subtab[data-subtab="edit"]`);i==null||i.click()}})}),t.querySelectorAll(`.save-delete-btn`).forEach(t=>{t.addEventListener(`click`,t=>{let r=parseInt(t.target.getAttribute(`data-save-idx`)||`0`),i=n.filter((e,t)=>t!==r);localStorage.setItem(x,JSON.stringify(i)),O(e)})})}function k(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`)}function A(e){let t=e.getElement(`#simulator-puzzle`),n=e.getElement(`#simulator-input`),r=e.getElement(`#simulator-puzzle-apply`),i=e.getElement(`#simulator-input-apply`);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))}function j(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`)}function ae(){let e=0;return{id:`msgs`,label:`Msgs`,render(){return`
100
+ <div class="msgs-view-container">
101
+ <div class="msgs-header">
102
+ <span class="simulator-label">Message Log</span>
103
+ <button class="simulator-btn tiny" id="simulator-msgs-clear">Clear</button>
104
+ </div>
105
+ <div id="simulator-msgs-log"></div>
106
+ </div>
107
+ `},bind(t){let n=t.getElement(`#simulator-msgs-clear`);n==null||n.addEventListener(`click`,()=>{let n=t.getElement(`#simulator-msgs-log`);n&&(n.innerHTML=``),e=0,t.updateBadge(`msgs`,0)})},addLogEntry(t,n){let r=n.getElement(`#simulator-msgs-log`);if(!r)return;e++,n.updateBadge(`msgs`,e);let i=document.createElement(`div`);i.className=`simulator-msg ${t.direction}`;let a=t.data===void 0?``:JSON.stringify(t.data,null,2);i.innerHTML=`
108
+ <div class="simulator-msg-header">
109
+ <span class="simulator-msg-type">${t.direction===`out`?`→`:`←`} ${t.type}</span>
110
+ <span class="simulator-msg-time">${t.time}</span>
111
+ </div>
112
+ ${a?`<div class="simulator-msg-data">${j(a)}</div>`:``}
113
+ `;let o=i.querySelector(`.simulator-msg-data`);for(o&&o.addEventListener(`click`,()=>{r.querySelectorAll(`.simulator-msg.expanded`).forEach(e=>{e!==i&&e.classList.remove(`expanded`)}),i.classList.toggle(`expanded`)}),r.insertBefore(i,r.firstChild);r.children.length>50;)r.removeChild(r.lastChild)}}}function oe(){return{id:`done`,label:`Done`,render(){return`
114
+ <div id="simulator-done-empty" class="simulator-empty">Game not completed yet</div>
115
+ <div id="simulator-done-content" style="display:none;">
116
+ <div class="simulator-field">
117
+ <label class="simulator-label">Completion Text</label>
118
+ <div id="simulator-done-text" class="simulator-value"></div>
119
+ </div>
120
+ <div class="simulator-divider"></div>
121
+ <div class="simulator-field">
122
+ <label class="simulator-label">Board State</label>
123
+ <textarea class="simulator-textarea" id="simulator-done-input" rows="2" readonly></textarea>
124
+ </div>
125
+ <div class="simulator-divider"></div>
126
+ <div class="simulator-field">
127
+ <label class="simulator-label">Deeds</label>
128
+ <div id="simulator-done-deeds" class="simulator-deeds"></div>
129
+ </div>
130
+ <div class="simulator-divider"></div>
131
+ <div class="simulator-field">
132
+ <label class="simulator-label">Raw Data</label>
133
+ <textarea class="simulator-textarea" id="simulator-done-raw" rows="4" readonly></textarea>
134
+ </div>
135
+ </div>
136
+ `},bind(e){},onMessage(e,t,n){var r,i;if(e!==`GAME_COMPLETED`)return;n.state.completionData=t;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`);a&&(a.style.display=`none`),o&&(o.style.display=`block`);let d=((r=t.input)==null?void 0:r.completionText)||t.completionText||`(no completion text)`;s&&(s.textContent=d);let f=((i=t.input)==null?void 0:i.boardState)||t.boardState||n.state.currentInputStr||``;if(c&&(c.value=f),l){var p;l.innerHTML=``;let e=((p=t.config)==null?void 0:p.deeds)||t.deeds;e&&Array.isArray(e)?e.forEach(e=>{let t=document.createElement(`div`);t.className=`simulator-deed`,t.innerHTML=`
137
+ <span class="simulator-deed-name">${e.id}</span>
138
+ <span class="simulator-deed-value">${e.value}</span>
139
+ `,l.appendChild(t)}):l.innerHTML=`<div class="simulator-empty">No deeds</div>`}u&&(u.value=JSON.stringify(t,null,2)),n.setCollapsed(!1),n.switchTab(`done`)}}}function se(){let e=[],t=()=>new Date().toLocaleTimeString(`en-US`,{hour12:!1}),n=e=>{let{checkpointName:t,augConfig:n,time:r}=e,i=n==null?void 0:n.deeds;return`
140
+ <div class="checkpoint-item">
141
+ <div class="checkpoint-header">
142
+ <span class="checkpoint-name">${t}</span>
143
+ <span class="checkpoint-time">${r}</span>
144
+ </div>
145
+ ${i&&i.length>0?`<div class="simulator-deeds">
146
+ ${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(``)}
147
+ </div>`:``}
148
+ </div>
149
+ `},r=()=>e.length===0?`<div class="simulator-empty">No checkpoints received yet</div>`:e.map(e=>n(e)).join(``);return{id:`checkpoints`,label:`Chkpt`,render(){return`
150
+ <div class="checkpoints-view-container">
151
+ <div class="checkpoints-header">
152
+ <span class="simulator-label">Checkpoints</span>
153
+ <button class="simulator-btn subtle small" id="simulator-checkpoints-clear">Clear</button>
154
+ </div>
155
+ <div id="simulator-checkpoints-list" class="checkpoints-list">
156
+ ${r()}
157
+ </div>
158
+ </div>
159
+ `},bind(t){let n=t.getElement(`#simulator-checkpoints-clear`),i=t.getElement(`#simulator-checkpoints-list`);n==null||n.addEventListener(`click`,()=>{e=[],i&&(i.innerHTML=r()),t.updateBadge(`checkpoints`,0)})},onMessage(n,i,a){if(n!==`HIT_CHECKPOINT`)return;let o={checkpointName:i.checkpointName,augConfig:i.augConfig,time:t()};e.push(o),a.updateBadge(`checkpoints`,e.length);let s=a.getElement(`#simulator-checkpoints-list`);s&&(s.innerHTML=r(),s.scrollTop=s.scrollHeight)}}}function M(){let e=globalThis;for(let t of Object.keys(e))if(t.endsWith(`Thumbnail`)&&typeof e[t]==`function`)return{name:t,fn:e[t]};return null}function ce(){return{id:`thumb`,label:`Thumb`,render(){return`
160
+ <div class="thumb-view-container">
161
+ <div class="thumb-header">
162
+ <span class="simulator-label">Thumbnail Preview</span>
163
+ <button class="simulator-btn tiny" id="simulator-thumb-refresh">Refresh</button>
164
+ </div>
165
+ <div id="simulator-thumb-preview">
166
+ <span class="simulator-empty">No thumbnail function found</span>
167
+ </div>
168
+ <div id="simulator-thumb-fn"></div>
169
+ <div class="simulator-divider"></div>
170
+ <div class="simulator-field">
171
+ <label class="simulator-label">Render Host</label>
172
+ <select class="simulator-select" id="simulator-render-host-select">
173
+ <option value="game">game</option>
174
+ <option value="app">app</option>
175
+ <option value="opengraph">opengraph</option>
176
+ </select>
177
+ </div>
178
+ <div class="simulator-field" id="simulator-render-context-field" style="display: none;">
179
+ <label class="simulator-label">Render Context</label>
180
+ <select class="simulator-select" id="simulator-render-context-select">
181
+ <option value="preview">preview</option>
182
+ <option value="share">share</option>
183
+ <option value="completed">completed</option>
184
+ <option value="timeline">timeline</option>
185
+ </select>
186
+ </div>
187
+ </div>
188
+ `},bind(e){let t=e.getElement(`#simulator-thumb-refresh`);t==null||t.addEventListener(`click`,()=>e.updateThumbnail());let n=e.getElement(`#simulator-render-host-select`),r=e.getElement(`#simulator-render-context-select`),i=e.getElement(`#simulator-render-context-field`),a=()=>{i&&(i.style.display=e.state.renderHost===`opengraph`?`block`:`none`)};n&&(e.state.renderHost||(e.state.renderHost=`game`,h(e.state.renderHost)),n.value=e.state.renderHost||`game`,n.addEventListener(`change`,()=>{e.state.renderHost=n.value,h(e.state.renderHost),a(),e.updateThumbnail()})),r&&(e.state.renderContext||(e.state.renderContext=`preview`,g(e.state.renderContext)),r.value=e.state.renderContext||`preview`,r.addEventListener(`change`,()=>{e.state.renderContext=r.value,g(e.state.renderContext),e.updateThumbnail()})),a()},onActivate(e){setTimeout(()=>e.updateThumbnail(),0)},updatePreview:e=>{let t=e.getElement(`#simulator-thumb-preview`),n=e.getElement(`#simulator-thumb-fn`);t==null||t.style.setProperty(`--sim-thumb-bg`,e.state.selectedTheme.g_bg);let r=M();if(!r){t&&(t.innerHTML=`<span class="simulator-empty">No thumbnail function found</span>`),n&&(n.textContent=``);return}n&&(n.textContent=`Using: ${r.name}()`);try{let n=e.state.puzzleData?JSON.stringify(e.state.puzzleData):``,i={viewerIsOwner:!0,theme:e.state.selectedTheme,strict:!0,renderHost:e.state.renderHost,renderContext:e.state.renderContext},a=r.fn(n,e.state.currentInputStr,i);t&&(t.innerHTML=a)}catch(e){console.error(`Simulator: Thumbnail error`,e),t&&(t.innerHTML=`<span class="simulator-empty">Error: ${e}</span>`)}}}}function N(e){let t=[e.key,e.subBrand,e.player,e.alt1,e.alt2,e.alt3].map(e=>`<div class="simulator-theme-preview-cell" style="background: ${e}"></div>`).join(``);return`<div class="simulator-theme-preview" style="background: ${e.g_bg}">${t}</div>`}function le(){return{id:`theme`,label:`Theme`,render(){return`
189
+ <div class="theme-view-container">
190
+ <div class="theme-header">
191
+ <span class="simulator-label">Select Theme</span>
192
+ </div>
193
+ <div id="simulator-themes" class="simulator-themes"></div>
194
+ </div>
195
+ `},bind(e){let n=e.getElement(`#simulator-themes`);n&&t.forEach(t=>{let r=document.createElement(`div`);r.className=`simulator-theme-item${t.name===e.state.selectedTheme.name?` selected`:``}`,r.innerHTML=`
196
+ ${N(t)}
197
+ <div class="simulator-theme-name">${t.name}</div>
198
+ <div class="simulator-theme-type">${t.type}</div>
199
+ `,r.addEventListener(`click`,()=>{console.log(`Simulator: Theme changed, reloading...`,t.name),d(t.name),window.location.reload()}),n.appendChild(r)})}}}var P=`puzzmo_sim_api_mode`,F=`http://localhost:8911`,I=`https://api.puzzmo.com`,L=()=>localStorage.getItem(P)===`dev`?`dev`:`prod`,R=e=>{localStorage.setItem(P,e)},z=null,B=function(){var t=e.n(function*(){if(z!==null)return z;try{let e=new AbortController,t=setTimeout(()=>e.abort(),1e3),n=yield fetch(`${F}/healthz`,{signal:e.signal});return clearTimeout(t),z=n.ok,z}catch(e){return z=!1,!1}});return function(){return t.apply(this,arguments)}}(),V=()=>({apiURL:L()===`dev`?F:I,clientID:`protosdk:oauthclient`,redirectUri:`${window.location.origin}/oauth/callback`}),H=()=>{let e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,e=>e.toString(16).padStart(2,`0`)).join(``)},U=`puzzmo_sim_oauth_token`,W=`puzzmo_sim_oauth_refresh_token`,G=e=>localStorage.setItem(U,e),K=e=>localStorage.setItem(W,e),q=()=>{let e=localStorage.getItem(U);return console.log(`[AuthView] getAccessToken:`,{TOKEN_KEY:U,token:e?`${e.substring(0,20)}...`:null}),e},J=()=>localStorage.getItem(W),Y=()=>{localStorage.removeItem(U),localStorage.removeItem(W)},ue=()=>{let e=V(),t=H();sessionStorage.setItem(`oauth_state`,t),sessionStorage.setItem(`oauth_return_url`,window.location.href);let n=new URL(`${e.apiURL}/oauth/auth`);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()},de=e=>{try{let t=e.split(`.`);if(t.length!==3)return!0;let n=JSON.parse(atob(t[1])).exp;return n?Date.now()>=n*1e3-300*1e3:!0}catch(e){return!0}},fe=function(){var t=e.n(function*(){let e=J();if(!e)return console.log(`[AuthView] No refresh token available`),!1;let t=V();try{let n=new URLSearchParams({grant_type:`refresh_token`,refresh_token:e,client_id:t.clientID}),r=yield fetch(`${t.apiURL}/oauth/token`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:n.toString()});if(!r.ok)return console.error(`[AuthView] Failed to refresh token:`,r.statusText),!1;let i=yield r.json(),a=i.access_token||i.accessToken;if(!a)return console.error(`[AuthView] No access token in refresh response`),!1;G(a);let o=i.refresh_token||i.refreshToken;return o&&K(o),console.log(`[AuthView] Successfully refreshed access token`),!0}catch(e){return console.error(`[AuthView] Error refreshing token:`,e),!1}});return function(){return t.apply(this,arguments)}}(),pe=function(){var t=e.n(function*(e,t){let n=V(),r=sessionStorage.getItem(`oauth_state`);if(!r||r!==t)return console.error(`OAuth state mismatch - possible CSRF attack`),null;sessionStorage.removeItem(`oauth_state`);try{let t=new URLSearchParams({grant_type:`authorization_code`,code:e,client_id:n.clientID,redirect_uri:n.redirectUri}),r=yield fetch(`${n.apiURL}/oauth/token`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:t.toString()});return r.ok?yield r.json():(console.error(`Failed to exchange code for token:`,r.statusText),null)}catch(e){return console.error(`Error exchanging code for token:`,e),null}});return function(e,n){return t.apply(this,arguments)}}(),me=function(){var t=e.n(function*(e,t={}){let n=V(),r=q();if(!r)throw Error(`Not authenticated`);if(de(r))if(console.log(`[AuthView] Access token expired, attempting refresh...`),yield fe()){if(r=q(),!r)throw Error(`Token refresh succeeded but no token available`)}else throw Y(),Error(`Session expired. Please log in again.`);let i=yield fetch(`${n.apiURL}/graphql`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${r}`,"auth-provider":`custom`},body:JSON.stringify({query:e,variables:t})});if(!i.ok)throw Error(`API request failed: ${i.statusText}`);return i.json()});return function(e){return t.apply(this,arguments)}}(),he=e=>{try{console.log(`[AuthView] decodeJWT input:`,e);let t=e.split(`.`);if(console.log(`[AuthView] JWT parts:`,t.length),t.length!==3)return null;let n=JSON.parse(atob(t[1]));return console.log(`[AuthView] JWT payload:`,n),n}catch(e){return console.error(`[AuthView] decodeJWT error:`,e),null}};function ge(){let t=!1;return{id:`auth`,label:`Auth`,render(){let e=q(),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>`;if(t){let t=he(e),n=t!=null&&t.exp?new Date(t.exp*1e3).toLocaleString():`Unknown`,a=!!J(),o=a?he(J()):null,s=o!=null&&o.exp?new Date(o.exp*1e3).toLocaleString():null;return console.log({decoded:t}),`
200
+ <div class="simulator-section">
201
+ <div class="simulator-section-title auth-title-row">
202
+ <span>Puzzmo Authentication</span>
203
+ ${i}
204
+ <button class="simulator-btn danger tiny" id="auth-logout">Logout</button>
205
+ </div>
206
+ <div id="auth-status" class="auth-status authenticated">
207
+ <span class="indicator ready"></span>
208
+ <span>Authenticated</span>
209
+ </div>
210
+ <div id="auth-user-info" class="auth-user-info">
211
+ <div>User ID: <code>${(t==null?void 0:t.userID)||(t==null?void 0:t.sub)||`Unknown`}</code></div>
212
+ <div>API: <code>${r}</code></div>
213
+ <div>Access expires: <code>${n}</code></div>
214
+ ${a?`<div>Refresh expires: <code>${s||`Unknown`}</code></div>`:`<div class="auth-warning">No refresh token</div>`}
215
+ </div>
216
+ ${a?`<button class="simulator-btn secondary tiny" id="auth-refresh">Refresh Now</button>`:``}
217
+ </div>
218
+ <div class="simulator-section">
219
+ <div class="simulator-section-title">Test API Request</div>
220
+ <div class="simulator-row">
221
+ <button class="simulator-btn primary" id="auth-test-api">Fetch Current User</button>
222
+ </div>
223
+ <div id="auth-api-result" class="auth-api-result"></div>
224
+ </div>
225
+ `}return`
226
+ <div class="simulator-section">
227
+ <div class="simulator-section-title auth-title-row">
228
+ <span>Puzzmo Authentication</span>
229
+ ${i}
230
+ </div>
231
+ <div id="auth-status" class="auth-status">
232
+ <span class="indicator waiting"></span>
233
+ <span>Not authenticated</span>
234
+ </div>
235
+ <p class="auth-description">
236
+ Login with your Puzzmo account to make authenticated API requests.
237
+ ${n===`dev`?`<br><strong>Using local dev server:</strong> ${F}`:``}
238
+ </p>
239
+ <div class="simulator-row">
240
+ <button class="simulator-btn primary" id="auth-login">Login with Puzzmo</button>
241
+ </div>
242
+ <div id="auth-error" class="auth-error"></div>
243
+ </div>
244
+ `},bind(n){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`);t?z&&c&&(c.style.display=``,L()===`dev`&&c.classList.add(`active`)):(t=!0,B().then(e=>{e&&c&&(c.style.display=``,L()===`dev`&&c.classList.add(`active`))})),c==null||c.addEventListener(`click`,()=>{R(L()===`dev`?`prod`:`dev`),Y(),window.location.reload()}),r==null||r.addEventListener(`click`,()=>{ue()}),i==null||i.addEventListener(`click`,()=>{Y(),window.location.reload()}),a==null||a.addEventListener(`click`,e.n(function*(){a.disabled=!0,a.textContent=`Refreshing...`,(yield fe())?window.location.reload():(a.textContent=`Refresh Failed`,a.disabled=!1)})),o==null||o.addEventListener(`click`,e.n(function*(){if(s){s.innerHTML=`<div class="loading">Loading...</div>`;try{let t=yield me(`
245
+ query {
246
+ currentUser {
247
+ id
248
+ username
249
+ usernameID
250
+ name
251
+ }
252
+ }
253
+ `);if(t.errors){var e;s.innerHTML=`<div class="error">Error: ${((e=t.errors[0])==null?void 0:e.message)||`Unknown error`}</div>`}else s.innerHTML=`<pre>${JSON.stringify(t.data,null,2)}</pre>`}catch(e){s.innerHTML=`<div class="error">Error: ${e instanceof Error?e.message:`Unknown error`}</div>`}}}))},onActivate(t){return e.n(function*(){let e=new URLSearchParams(window.location.search),n=e.get(`code`),r=e.get(`state`),i=e.get(`error`);if(i){let e=t.getElement(`#auth-error`);e&&(e.innerHTML=`<div class="error">OAuth error: ${i}</div>`),window.history.replaceState({},``,window.location.pathname);return}if(n&&r){let e=t.getElement(`#auth-status`);e&&(e.innerHTML=`<span class="indicator waiting"></span><span>Exchanging code...</span>`);let i=yield pe(n,r);if(window.history.replaceState({},``,window.location.pathname),i){let e=i.access_token||i.accessToken;if(e){G(e);let t=i.refresh_token||i.refreshToken;t&&K(t)}window.location.reload()}else{let e=t.getElement(`#auth-error`);e&&(e.innerHTML=`<div class="error">Failed to exchange code for token</div>`)}}})()}}}var _e=`puzzmo_sim_api_mode`,ve=`http://localhost:8911`,ye=`https://api.puzzmo.com`,X=`puzzmo_sim_oauth_token`,Z=`puzzmo_sim_oauth_refresh_token`,be=()=>localStorage.getItem(_e)===`dev`?`dev`:`prod`,Q=()=>localStorage.getItem(X),xe=()=>localStorage.getItem(Z),Se=e=>localStorage.setItem(X,e),Ce=e=>localStorage.setItem(Z,e),we=()=>{localStorage.removeItem(X),localStorage.removeItem(Z)},Te=e=>{try{let t=e.split(`.`);if(t.length!==3)return!0;let n=JSON.parse(atob(t[1])).exp;return n?Date.now()>=n*1e3-300*1e3:!0}catch(e){return!0}},Ee=function(){var t=e.n(function*(){let e=xe();if(!e)return!1;let t=be()===`dev`?ve:ye;try{let n=new URLSearchParams({grant_type:`refresh_token`,refresh_token:e,client_id:`protosdk:oauthclient`}),r=yield fetch(`${t}/oauth/token`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:n.toString()});if(!r.ok)return!1;let i=yield r.json(),a=i.access_token||i.accessToken;if(!a)return!1;Se(a);let o=i.refresh_token||i.refreshToken;return o&&Ce(o),!0}catch(e){return!1}});return function(){return t.apply(this,arguments)}}(),De=function(){var t=e.n(function*(e,t={}){let n=be()===`dev`?ve:ye,r=Q();if(!r)throw Error(`Not authenticated`);if(Te(r))if(yield Ee()){if(r=Q(),!r)throw Error(`Token refresh succeeded but no token available`)}else throw we(),Error(`Session expired. Please log in again.`);let i=yield fetch(`${n}/graphql`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${r}`,"auth-provider":`custom`},body:JSON.stringify({query:e,variables:t})});if(!i.ok)throw Error(`API request failed: ${i.statusText}`);return i.json()});return function(e){return t.apply(this,arguments)}}(),Oe=`
254
+ query GameFeaturesQuery($slug: ID!) {
255
+ game(id: $slug) {
256
+ id
257
+ slug
258
+ displayName
259
+ featuresArr
260
+ gameFeatures {
261
+ slug
262
+ title
263
+ features {
264
+ featureID
265
+ title
266
+ isEnabled
267
+ }
268
+ }
269
+ }
270
+ }
271
+ `,ke=`
272
+ mutation ToggleFeatureMutation($gameSlug: ID!, $input: UpdateGameInput!) {
273
+ updateGame(id: $gameSlug, input: $input) {
274
+ id
275
+ featuresArr
276
+ gameFeatures {
277
+ slug
278
+ title
279
+ features {
280
+ featureID
281
+ title
282
+ isEnabled
283
+ }
284
+ }
285
+ }
286
+ }
287
+ `,Ae=(e,t)=>{let n=t-1,r=Math.floor(n/31),i=n%31,a=[...e];for(;a.length<=r;)a.push(0);return a[r]=a[r]^1<<i,a};const je=()=>!!Q();function Me(){let t=null,n=!1,r=null,i=function(){var i=e.n(function*(e){n=!0,r=null;try{var i;let n=yield De(Oe,{slug:e});if(n.errors){var a;r=((a=n.errors[0])==null?void 0:a.message)||`Unknown error`,t=null}else (i=n.data)!=null&&i.game?t=n.data.game:(r=`Game not found`,t=null)}catch(e){r=e instanceof Error?e.message:`Unknown error`,t=null}finally{n=!1}});return function(e){return i.apply(this,arguments)}}(),a=function(){var n=e.n(function*(n){if(!t)return;let r=Ae(t.featuresArr,n);try{var i;let n=yield De(ke,{gameSlug:t.slug,input:{featuresArr:r}});if(n.errors){var a;console.error(`Failed to toggle feature:`,(a=n.errors[0])==null?void 0:a.message)}else (i=n.data)!=null&&i.updateGame&&(t=e.t(e.t({},t),{},{featuresArr:n.data.updateGame.featuresArr,gameFeatures:n.data.updateGame.gameFeatures}))}catch(e){console.error(`Failed to toggle feature:`,e)}});return function(e){return n.apply(this,arguments)}}(),o=()=>{if(n)return`<div class="features-loading">Loading features...</div>`;if(r)return`<div class="features-error">${r}</div>`;if(!t)return`<div class="features-empty">Enter your game slug above to load features</div>`;let e=t.gameFeatures.map(e=>{let t=e.features.map(e=>{let t=e.isEnabled?`enabled`:`disabled`,n=e.isEnabled?`✓`:`✗`;return`
288
+ <div class="feature-item ${t}" data-feature-id="${e.featureID}">
289
+ <span class="feature-status">${n}</span>
290
+ <span class="feature-title">${e.title}</span>
291
+ </div>
292
+ `}).join(``);return`
293
+ <div class="feature-group">
294
+ <div class="feature-group-title">${e.title}</div>
295
+ <div class="feature-group-items">${t}</div>
296
+ </div>
297
+ `}).join(``);return`
298
+ <div class="features-game-name">${t.displayName}</div>
299
+ ${e}
300
+ `};return{id:`features`,label:`Features`,render(){return je()?`
301
+ <div class="features-view-container">
302
+ <div class="simulator-section">
303
+ <div class="simulator-section-title">Game Features</div>
304
+ <div class="features-slug-input">
305
+ <input type="text" class="simulator-input" id="features-game-slug" placeholder="Game slug (e.g. crossword)" />
306
+ <button class="simulator-btn primary" id="features-load-btn">Load</button>
307
+ </div>
308
+ </div>
309
+ <div class="simulator-divider"></div>
310
+ <div id="features-content" class="features-content">
311
+ ${o()}
312
+ </div>
313
+ </div>
314
+ `:`
315
+ <div class="features-view-container">
316
+ <div class="simulator-section">
317
+ <div class="simulator-section-title">Game Features</div>
318
+ <div class="features-auth-required">
319
+ <p>You must be logged in to view and edit game features.</p>
320
+ <p>Go to the <strong>Auth</strong> tab to log in with your Puzzmo account.</p>
321
+ </div>
322
+ </div>
323
+ </div>
324
+ `},bind(n){let r=n.getElement(`#features-load-btn`),s=n.getElement(`#features-game-slug`),c=n.getElement(`#features-content`),l=()=>{c&&(c.innerHTML=o(),u())},u=()=>{var t;let r=(t=n.getElement(`#features-content`))==null?void 0:t.querySelectorAll(`.feature-item`);r==null||r.forEach(t=>{t.addEventListener(`click`,e.n(function*(){let e=parseInt(t.getAttribute(`data-feature-id`)||`0`);e>0&&(t.classList.add(`updating`),yield a(e),l())}))})},d=function(){var t=e.n(function*(e){e&&(r&&(r.disabled=!0,r.textContent=`Loading...`),yield i(e),l(),r&&(r.disabled=!1,r.textContent=`Load`))});return function(e){return t.apply(this,arguments)}}();r==null||r.addEventListener(`click`,e.n(function*(){let e=s==null?void 0:s.value.trim();e&&(yield d(e))})),s==null||s.addEventListener(`keypress`,e=>{e.key===`Enter`&&(r==null||r.click())}),console.log(`[FeaturesView] bind called, ctx.gameSlug:`,n.gameSlug,`slugInput:`,s),n.gameSlug&&s&&(s.value=n.gameSlug,je()&&!t&&d(n.gameSlug)),u()},onActivate(e){let t=e.getElement(`#simulator-tab-features`);t&&(t.innerHTML=this.render(),this.bind(e))}}}var Ne=`./sample-puzzle.json`,$=null;function Pe(t={}){var n,r,i;if(console.log(`[Simulator] createSimulator called with config:`,{slug:t.slug,hasFixtures:!!t.fixtures}),$)return t.fixtures&&(console.log(`[Simulator] Instance already exists, updating fixtures`),$.updateFixtures(t.fixtures)),$;let a=(n=t.puzzlePath)==null?Ne:n,o=(r=t.autoStart)==null?!0:r,s=t.fixtures?_(t.fixtures):null,d=s?Array.from(s.keys()).sort():[],f=ae(),p=ce(),m=[re(),ie(),f,oe(),se(),p,le(),ge(),Me()],h=m.map(e=>e.id),g=c(t,d,h),v={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>`,play:`<svg width="10" height="10" viewBox="0 0 10 10" fill="currentColor"><polygon points="2,1 9,5 2,9"/></svg>`,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>`,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>`,minimize:`<svg width="10" height="10" viewBox="0 0 10 10" fill="currentColor"><rect x="1" y="4" width="8" height="2"/></svg>`,expand:`<svg width="8" height="8" viewBox="0 0 8 8" fill="currentColor"><polygon points="1,1 7,4 1,7"/></svg>`},y=document.createElement(`div`);y.id=`simulator`,y.innerHTML=`
325
+ <style>
326
+ :root {
327
+ --sim-bg: #1a1a2e;
328
+ --sim-bg-alt: #16213e;
329
+ --sim-panel: #0f0f1a;
330
+ --sim-border: #3a3a5c;
331
+ --sim-border-light: #5a5a8c;
332
+ --sim-accent: #ffd700;
333
+ --sim-accent-hover: #ffed4a;
334
+ --sim-text: #e8e8e8;
335
+ --sim-text-dim: #888899;
336
+ --sim-success: #4ade80;
337
+ --sim-error: #f87171;
338
+ --sim-warning: #fbbf24;
339
+ --sim-blue: #60a5fa;
340
+ }
341
+ #simulator {
342
+ position: fixed;
343
+ bottom: 4px;
344
+ left: 4px;
345
+ z-index: 999999;
346
+ font: 11px/1.4 "Menlo", "Monaco", "Consolas", monospace;
347
+ user-select: none;
348
+ }
349
+ #simulator-panel {
350
+ background: var(--sim-panel);
351
+ border: 2px solid var(--sim-border);
352
+ border-radius: 4px;
353
+ color: var(--sim-text);
354
+ width: 420px;
355
+ box-shadow: 4px 4px 0 rgba(0,0,0,0.5);
356
+ }
357
+ #simulator-panel.collapsed {
358
+ width: auto;
359
+ }
360
+ #simulator-header {
361
+ display: flex;
362
+ align-items: center;
363
+ padding: 4px 8px;
364
+ background: var(--sim-bg);
365
+ border-bottom: 2px solid var(--sim-border);
366
+ gap: 0;
367
+ }
368
+ #simulator-panel.collapsed #simulator-header {
369
+ border-bottom: none;
370
+ cursor: pointer;
371
+ }
372
+ #simulator-panel.collapsed #simulator-header:hover {
373
+ background: var(--sim-bg-alt);
374
+ }
375
+ .header-sep {
376
+ color: var(--sim-border-light);
377
+ margin: 0 8px;
378
+ opacity: 0.6;
379
+ }
380
+ .header-spacer {
381
+ flex: 1;
382
+ }
383
+ #simulator-title {
384
+ color: var(--sim-accent);
385
+ text-transform: uppercase;
386
+ letter-spacing: 1px;
387
+ font-size: 10px;
388
+ font-weight: bold;
389
+ }
390
+ #simulator-header-controls {
391
+ display: flex;
392
+ gap: 2px;
393
+ }
394
+ .header-icon-btn {
395
+ width: 20px;
396
+ height: 20px;
397
+ display: flex;
398
+ align-items: center;
399
+ justify-content: center;
400
+ background: transparent;
401
+ border: none;
402
+ border-radius: 2px;
403
+ color: var(--sim-text);
404
+ cursor: pointer;
405
+ padding: 0;
406
+ }
407
+ .header-icon-btn:hover:not(:disabled) {
408
+ background: var(--sim-border);
409
+ color: var(--sim-accent);
410
+ }
411
+ .header-icon-btn:disabled {
412
+ opacity: 0.3;
413
+ cursor: not-allowed;
414
+ }
415
+ .header-icon-btn.active {
416
+ background: var(--sim-accent);
417
+ color: var(--sim-panel);
418
+ }
419
+ #simulator-header-status {
420
+ display: flex;
421
+ align-items: center;
422
+ gap: 4px;
423
+ font-size: 9px;
424
+ color: var(--sim-text-dim);
425
+ }
426
+ #simulator-header-indicator {
427
+ width: 6px;
428
+ height: 6px;
429
+ border-radius: 50%;
430
+ background: var(--sim-text-dim);
431
+ flex-shrink: 0;
432
+ }
433
+ #simulator-header-indicator.ready {
434
+ background: var(--sim-success);
435
+ box-shadow: 0 0 4px var(--sim-success);
436
+ }
437
+ #simulator-header-indicator.waiting {
438
+ background: var(--sim-warning);
439
+ box-shadow: 0 0 4px var(--sim-warning);
440
+ }
441
+ #simulator-header-indicator.paused {
442
+ background: var(--sim-error);
443
+ box-shadow: 0 0 4px var(--sim-error);
444
+ }
445
+ #simulator-timer {
446
+ font-size: 11px;
447
+ color: var(--sim-text);
448
+ font-family: "Menlo", monospace;
449
+ font-weight: bold;
450
+ font-variant-numeric: tabular-nums;
451
+ min-width: 38px;
452
+ }
453
+ #simulator-timer .penalty {
454
+ color: var(--sim-error);
455
+ margin-left: 2px;
456
+ }
457
+ /* Collapsed state - show minimal bar */
458
+ #simulator-panel.collapsed .header-sep,
459
+ #simulator-panel.collapsed #simulator-header-controls,
460
+ #simulator-panel.collapsed #simulator-header-status,
461
+ #simulator-panel.collapsed #simulator-header-settings,
462
+ #simulator-panel.collapsed #simulator-toggle {
463
+ display: none;
464
+ }
465
+ #simulator-panel.collapsed #simulator-title {
466
+ cursor: pointer;
467
+ }
468
+ #simulator-panel.collapsed #simulator-timer {
469
+ margin-left: 8px;
470
+ }
471
+ #simulator-body {
472
+ display: flex;
473
+ flex-direction: row;
474
+ }
475
+ #simulator-panel.collapsed #simulator-body {
476
+ display: none;
477
+ }
478
+ #simulator-tabs {
479
+ display: flex;
480
+ flex-direction: column;
481
+ background: var(--sim-bg);
482
+ padding: 4px;
483
+ gap: 2px;
484
+ border-right: 2px solid var(--sim-border);
485
+ }
486
+ .simulator-tab {
487
+ padding: 2px 3px;
488
+ background: var(--sim-bg-alt);
489
+ border: 2px solid var(--sim-border);
490
+ border-radius: 2px;
491
+ color: var(--sim-text-dim);
492
+ cursor: pointer;
493
+ font: inherit;
494
+ text-transform: uppercase;
495
+ font-size: 9px;
496
+ font-weight: bold;
497
+ letter-spacing: 0.5px;
498
+ min-height: 0;
499
+ }
500
+ .simulator-tab:hover {
501
+ color: var(--sim-text);
502
+ background: var(--sim-border);
503
+ }
504
+ .simulator-tab.active {
505
+ color: var(--sim-panel);
506
+ background: var(--sim-accent);
507
+ border-color: var(--sim-accent);
508
+ }
509
+ .simulator-tab {
510
+ position: relative;
511
+ }
512
+ .simulator-tab-badge {
513
+ position: absolute;
514
+ top: -4px;
515
+ right: -4px;
516
+ min-width: 14px;
517
+ height: 14px;
518
+ padding: 0 3px;
519
+ background: var(--sim-blue);
520
+ color: #fff;
521
+ font-size: 8px;
522
+ font-weight: bold;
523
+ border-radius: 7px;
524
+ display: flex;
525
+ align-items: center;
526
+ justify-content: center;
527
+ box-shadow: 0 1px 2px rgba(0,0,0,0.3);
528
+ line-height: 1;
529
+ text-align: center;
530
+ box-sizing: border-box;
531
+ }
532
+ .simulator-tab-badge:empty {
533
+ display: none;
534
+ }
535
+ #simulator-content {
536
+ padding: 6px;
537
+ background: var(--sim-panel);
538
+ height: 500px;
539
+ flex: 1;
540
+ overflow-y: auto;
541
+ }
542
+ #simulator-content.hidden {
543
+ display: none;
544
+ }
545
+ #simulator-content::-webkit-scrollbar {
546
+ width: 8px;
547
+ }
548
+ #simulator-content::-webkit-scrollbar-track {
549
+ background: var(--sim-bg);
550
+ }
551
+ #simulator-content::-webkit-scrollbar-thumb {
552
+ background: var(--sim-border);
553
+ border-radius: 2px;
554
+ }
555
+ .simulator-btn {
556
+ padding: 4px 8px;
557
+ background: var(--sim-bg-alt);
558
+ border: 2px solid var(--sim-border);
559
+ border-radius: 2px;
560
+ color: var(--sim-text);
561
+ font: inherit;
562
+ font-size: 10px;
563
+ font-weight: bold;
564
+ text-transform: uppercase;
565
+ letter-spacing: 1px;
566
+ cursor: pointer;
567
+ }
568
+ .simulator-btn:hover {
569
+ background: var(--sim-border);
570
+ border-color: var(--sim-border-light);
571
+ }
572
+ .simulator-btn:active {
573
+ transform: translate(1px, 1px);
574
+ }
575
+ .simulator-btn.primary {
576
+ background: var(--sim-accent);
577
+ border-color: var(--sim-accent);
578
+ color: var(--sim-panel);
579
+ }
580
+ .simulator-btn.primary:hover {
581
+ background: var(--sim-accent-hover);
582
+ border-color: var(--sim-accent-hover);
583
+ }
584
+ .simulator-btn.danger {
585
+ background: var(--sim-error);
586
+ border-color: var(--sim-error);
587
+ color: #fff;
588
+ }
589
+ .simulator-btn.danger:hover {
590
+ background: #ef4444;
591
+ border-color: #ef4444;
592
+ }
593
+ .simulator-btn:disabled {
594
+ opacity: 0.4;
595
+ cursor: not-allowed;
596
+ transform: none;
597
+ }
598
+ .simulator-btn.subtle {
599
+ background: transparent;
600
+ border-color: transparent;
601
+ color: var(--sim-text-dim);
602
+ }
603
+ .simulator-btn.subtle:hover:not(:disabled) {
604
+ background: var(--sim-bg-alt);
605
+ border-color: var(--sim-border);
606
+ color: var(--sim-text);
607
+ }
608
+ #simulator-status {
609
+ font-size: 10px;
610
+ color: var(--sim-text-dim);
611
+ padding: 4px 0 6px;
612
+ display: flex;
613
+ align-items: center;
614
+ gap: 6px;
615
+ }
616
+ #simulator-status .indicator {
617
+ width: 8px;
618
+ height: 8px;
619
+ border-radius: 2px;
620
+ background: var(--sim-text-dim);
621
+ }
622
+ #simulator-status .indicator.ready {
623
+ background: var(--sim-success);
624
+ box-shadow: 0 0 6px var(--sim-success);
625
+ }
626
+ #simulator-status .indicator.waiting {
627
+ background: var(--sim-warning);
628
+ box-shadow: 0 0 6px var(--sim-warning);
629
+ }
630
+ #simulator-status .indicator.paused {
631
+ background: var(--sim-error);
632
+ box-shadow: 0 0 6px var(--sim-error);
633
+ }
634
+ .simulator-row {
635
+ display: flex;
636
+ gap: 4px;
637
+ margin-top: 4px;
638
+ }
639
+ .simulator-row .simulator-btn {
640
+ flex: 1;
641
+ }
642
+ .simulator-divider {
643
+ height: 2px;
644
+ background: var(--sim-border);
645
+ margin: 8px 0;
646
+ }
647
+ .simulator-field {
648
+ margin-bottom: 6px;
649
+ }
650
+ .simulator-select {
651
+ width: 100%;
652
+ padding: 4px 6px;
653
+ background: var(--sim-bg);
654
+ border: 2px solid var(--sim-border);
655
+ border-radius: 2px;
656
+ color: var(--sim-text);
657
+ font: inherit;
658
+ font-size: 10px;
659
+ cursor: pointer;
660
+ }
661
+ .simulator-select:focus {
662
+ outline: none;
663
+ border-color: var(--sim-accent);
664
+ }
665
+ .simulator-select option {
666
+ background: var(--sim-bg);
667
+ color: var(--sim-text);
668
+ }
669
+ .simulator-fixtures {
670
+ margin-bottom: 8px;
671
+ padding-bottom: 8px;
672
+ border-bottom: 2px solid var(--sim-border);
673
+ }
674
+ .simulator-label {
675
+ display: block;
676
+ color: var(--sim-accent);
677
+ text-transform: uppercase;
678
+ font-size: 9px;
679
+ font-weight: bold;
680
+ letter-spacing: 1px;
681
+ margin-bottom: 4px;
682
+ }
683
+ .simulator-textarea {
684
+ width: 100%;
685
+ min-height: 40px;
686
+ background: var(--sim-bg);
687
+ border: 2px solid var(--sim-border);
688
+ border-radius: 2px;
689
+ color: var(--sim-text);
690
+ font: 10px/1.4 "Menlo", monospace;
691
+ padding: 4px;
692
+ resize: none;
693
+ box-sizing: border-box;
694
+ overflow-y: auto;
695
+ }
696
+ .simulator-textarea.auto-resize {
697
+ resize: none;
698
+ overflow-y: auto;
699
+ }
700
+ .simulator-textarea:focus {
701
+ outline: none;
702
+ border-color: var(--sim-accent);
703
+ }
704
+ .simulator-input {
705
+ width: 100%;
706
+ background: var(--sim-bg);
707
+ border: 2px solid var(--sim-border);
708
+ border-radius: 2px;
709
+ color: var(--sim-text);
710
+ font: 10px/1.4 "Menlo", monospace;
711
+ padding: 4px 6px;
712
+ box-sizing: border-box;
713
+ }
714
+ .simulator-input:focus {
715
+ outline: none;
716
+ border-color: var(--sim-accent);
717
+ }
718
+ .simulator-input::placeholder {
719
+ color: var(--sim-text-dim);
720
+ }
721
+ .simulator-tab-content {
722
+ display: none;
723
+ }
724
+ .simulator-tab-content.active {
725
+ display: block;
726
+ }
727
+ .msgs-view-container {
728
+ display: flex;
729
+ flex-direction: column;
730
+ height: 100%;
731
+ overflow: hidden;
732
+ }
733
+ .msgs-header {
734
+ display: flex;
735
+ justify-content: space-between;
736
+ align-items: center;
737
+ margin-bottom: 6px;
738
+ flex-shrink: 0;
739
+ }
740
+ #simulator-msgs-log {
741
+ display: flex;
742
+ flex-direction: column;
743
+ gap: 2px;
744
+ flex: 1;
745
+ overflow-y: auto;
746
+ }
747
+ .simulator-msg {
748
+ padding: 3px 4px;
749
+ background: var(--sim-bg);
750
+ border: 1px solid var(--sim-border);
751
+ border-radius: 2px;
752
+ font-size: 10px;
753
+ }
754
+ .simulator-msg.out {
755
+ border-left: 2px solid var(--sim-accent);
756
+ }
757
+ .simulator-msg.in {
758
+ border-left: 2px solid var(--sim-blue);
759
+ }
760
+ .simulator-msg-header {
761
+ display: flex;
762
+ justify-content: space-between;
763
+ align-items: center;
764
+ margin-bottom: 2px;
765
+ }
766
+ .simulator-msg-type {
767
+ font-weight: bold;
768
+ color: var(--sim-text);
769
+ }
770
+ .simulator-msg.out .simulator-msg-type {
771
+ color: var(--sim-accent);
772
+ }
773
+ .simulator-msg.in .simulator-msg-type {
774
+ color: var(--sim-blue);
775
+ }
776
+ .simulator-msg-time {
777
+ color: var(--sim-text-dim);
778
+ font-size: 9px;
779
+ }
780
+ .simulator-msg-data {
781
+ color: var(--sim-text-dim);
782
+ font-size: 9px;
783
+ white-space: pre-wrap;
784
+ word-break: break-all;
785
+ max-height: 60px;
786
+ overflow: hidden;
787
+ cursor: pointer;
788
+ border-radius: 2px;
789
+ padding: 2px 4px;
790
+ background: var(--sim-bg-alt);
791
+ }
792
+ .simulator-msg-data:hover {
793
+ background: var(--sim-border);
794
+ }
795
+ .simulator-msg.expanded {
796
+ flex: 1;
797
+ display: flex;
798
+ flex-direction: column;
799
+ }
800
+ .simulator-msg.expanded .simulator-msg-data {
801
+ max-height: none;
802
+ flex: 1;
803
+ overflow-y: auto;
804
+ }
805
+ .simulator-empty {
806
+ color: var(--sim-text-dim);
807
+ font-size: 10px;
808
+ text-align: center;
809
+ padding: 20px;
810
+ }
811
+ .simulator-value {
812
+ color: var(--sim-text);
813
+ font-size: 10px;
814
+ padding: 4px;
815
+ background: var(--sim-bg);
816
+ border: 1px solid var(--sim-border);
817
+ border-radius: 2px;
818
+ }
819
+ .simulator-deeds {
820
+ display: flex;
821
+ flex-direction: column;
822
+ gap: 2px;
823
+ }
824
+ .simulator-deed {
825
+ display: flex;
826
+ justify-content: space-between;
827
+ padding: 3px 4px;
828
+ background: var(--sim-bg);
829
+ border: 1px solid var(--sim-border);
830
+ border-radius: 2px;
831
+ font-size: 10px;
832
+ }
833
+ .simulator-deed-name {
834
+ color: var(--sim-text);
835
+ }
836
+ .simulator-deed-value {
837
+ color: var(--sim-accent);
838
+ font-weight: bold;
839
+ }
840
+ .thumb-view-container {
841
+ display: flex;
842
+ flex-direction: column;
843
+ height: 100%;
844
+ overflow: hidden;
845
+ }
846
+ .thumb-header {
847
+ display: flex;
848
+ justify-content: space-between;
849
+ align-items: center;
850
+ margin-bottom: 6px;
851
+ flex-shrink: 0;
852
+ }
853
+ #simulator-thumb-preview {
854
+ background: var(--sim-thumb-bg, transparent);
855
+ border: 2px solid var(--sim-border);
856
+ border-radius: 2px;
857
+ padding: 8px;
858
+ display: flex;
859
+ align-items: center;
860
+ justify-content: center;
861
+ aspect-ratio: 1;
862
+ width: 100%;
863
+ box-sizing: border-box;
864
+ }
865
+ #simulator-thumb-preview svg {
866
+ width: 100%;
867
+ height: 100%;
868
+ max-width: 100%;
869
+ max-height: 100%;
870
+ }
871
+ #simulator-thumb-fn {
872
+ font-size: 10px;
873
+ color: var(--sim-text-dim);
874
+ margin-top: 4px;
875
+ }
876
+ .theme-view-container {
877
+ display: flex;
878
+ flex-direction: column;
879
+ height: 100%;
880
+ overflow: hidden;
881
+ }
882
+ .theme-header {
883
+ display: flex;
884
+ justify-content: space-between;
885
+ align-items: center;
886
+ margin-bottom: 6px;
887
+ flex-shrink: 0;
888
+ }
889
+ .simulator-themes {
890
+ display: flex;
891
+ flex-direction: column;
892
+ gap: 4px;
893
+ flex: 1;
894
+ overflow-y: auto;
895
+ }
896
+ .simulator-theme-item {
897
+ display: flex;
898
+ align-items: center;
899
+ gap: 8px;
900
+ padding: 4px;
901
+ background: var(--sim-bg);
902
+ border: 2px solid var(--sim-border);
903
+ border-radius: 2px;
904
+ cursor: pointer;
905
+ }
906
+ .simulator-theme-item:hover {
907
+ border-color: var(--sim-border-light);
908
+ }
909
+ .simulator-theme-item.selected {
910
+ border-color: var(--sim-accent);
911
+ background: var(--sim-bg-alt);
912
+ }
913
+ .simulator-theme-preview {
914
+ width: 48px;
915
+ height: 32px;
916
+ display: grid;
917
+ grid-template-columns: repeat(3, 1fr);
918
+ grid-template-rows: repeat(2, 1fr);
919
+ gap: 1px;
920
+ border-radius: 2px;
921
+ overflow: hidden;
922
+ flex-shrink: 0;
923
+ }
924
+ .simulator-theme-preview-cell {
925
+ width: 100%;
926
+ height: 100%;
927
+ }
928
+ .simulator-theme-name {
929
+ font-size: 10px;
930
+ color: var(--sim-text);
931
+ flex: 1;
932
+ }
933
+ .simulator-theme-type {
934
+ font-size: 9px;
935
+ color: var(--sim-text-dim);
936
+ text-transform: uppercase;
937
+ }
938
+ /* Auth tab styles */
939
+ .simulator-section {
940
+ margin-bottom: 12px;
941
+ }
942
+ .simulator-section-title {
943
+ color: var(--sim-accent);
944
+ text-transform: uppercase;
945
+ font-size: 10px;
946
+ font-weight: bold;
947
+ letter-spacing: 1px;
948
+ margin-bottom: 6px;
949
+ padding-bottom: 4px;
950
+ border-bottom: 1px solid var(--sim-border);
951
+ }
952
+ .auth-header-row {
953
+ display: flex;
954
+ align-items: center;
955
+ justify-content: space-between;
956
+ margin-bottom: 6px;
957
+ }
958
+ .auth-status {
959
+ display: flex;
960
+ align-items: center;
961
+ gap: 6px;
962
+ font-size: 10px;
963
+ color: var(--sim-text-dim);
964
+ padding: 4px 0;
965
+ }
966
+ .auth-status.authenticated {
967
+ color: var(--sim-success);
968
+ }
969
+ .simulator-btn.small {
970
+ padding: 2px 6px;
971
+ font-size: 9px;
972
+ }
973
+ .simulator-btn.tiny {
974
+ padding: 3px 2px;
975
+ font-size: 8px;
976
+ border-width: 1px;
977
+ line-height: 1;
978
+ min-height: 0;
979
+ height: auto;
980
+ }
981
+ .auth-title-row {
982
+ display: flex;
983
+ align-items: center;
984
+ gap: 6px;
985
+ }
986
+ .auth-title-row > span:first-child {
987
+ flex: 1;
988
+ }
989
+ .auth-title-row .simulator-btn.active {
990
+ background: var(--sim-accent);
991
+ color: black;
992
+ }
993
+ .auth-description {
994
+ font-size: 10px;
995
+ color: var(--sim-text-dim);
996
+ margin: 6px 0;
997
+ line-height: 1.4;
998
+ }
999
+ .auth-user-info {
1000
+ font-size: 10px;
1001
+ color: var(--sim-text-dim);
1002
+ padding: 6px;
1003
+ background: var(--sim-bg);
1004
+ border: 1px solid var(--sim-border);
1005
+ border-radius: 2px;
1006
+ margin-bottom: 8px;
1007
+ }
1008
+ .auth-user-info div {
1009
+ margin-bottom: 4px;
1010
+ }
1011
+ .auth-user-info div:last-child {
1012
+ margin-bottom: 0;
1013
+ }
1014
+ .auth-user-info code {
1015
+ color: var(--sim-text);
1016
+ background: var(--sim-bg-alt);
1017
+ padding: 1px 4px;
1018
+ border-radius: 2px;
1019
+ }
1020
+ .auth-warning {
1021
+ color: var(--sim-warning);
1022
+ font-style: italic;
1023
+ }
1024
+ .auth-error {
1025
+ margin-top: 8px;
1026
+ }
1027
+ .auth-error .error,
1028
+ .auth-api-result .error {
1029
+ color: var(--sim-error);
1030
+ font-size: 10px;
1031
+ padding: 6px;
1032
+ background: rgba(248, 113, 113, 0.1);
1033
+ border: 1px solid var(--sim-error);
1034
+ border-radius: 2px;
1035
+ }
1036
+ .auth-api-result {
1037
+ margin-top: 8px;
1038
+ }
1039
+ .auth-api-result pre {
1040
+ font-size: 9px;
1041
+ color: var(--sim-text);
1042
+ background: var(--sim-bg);
1043
+ border: 1px solid var(--sim-border);
1044
+ border-radius: 2px;
1045
+ padding: 6px;
1046
+ margin: 0;
1047
+ white-space: pre-wrap;
1048
+ word-break: break-all;
1049
+ max-height: 150px;
1050
+ overflow-y: auto;
1051
+ }
1052
+ .auth-api-result .loading {
1053
+ font-size: 10px;
1054
+ color: var(--sim-text-dim);
1055
+ padding: 6px;
1056
+ background: var(--sim-bg);
1057
+ border: 1px solid var(--sim-border);
1058
+ border-radius: 2px;
1059
+ }
1060
+ /* Data view styles */
1061
+ .data-view-container {
1062
+ display: flex;
1063
+ flex-direction: column;
1064
+ height: 100%;
1065
+ overflow: hidden;
1066
+ }
1067
+ .data-subtabs {
1068
+ display: flex;
1069
+ gap: 2px;
1070
+ margin-bottom: 8px;
1071
+ flex-shrink: 0;
1072
+ }
1073
+ .data-subtab {
1074
+ padding: 4px 10px;
1075
+ background: var(--sim-bg-alt);
1076
+ border: 1px solid var(--sim-border);
1077
+ border-radius: 2px;
1078
+ color: var(--sim-text-dim);
1079
+ cursor: pointer;
1080
+ font: inherit;
1081
+ font-size: 9px;
1082
+ font-weight: bold;
1083
+ text-transform: uppercase;
1084
+ letter-spacing: 0.5px;
1085
+ }
1086
+ .data-subtab:hover {
1087
+ color: var(--sim-text);
1088
+ background: var(--sim-border);
1089
+ }
1090
+ .data-subtab.active {
1091
+ color: var(--sim-panel);
1092
+ background: var(--sim-accent);
1093
+ border-color: var(--sim-accent);
1094
+ }
1095
+ .data-subtab-content {
1096
+ display: none;
1097
+ flex: 1;
1098
+ overflow-y: auto;
1099
+ overflow-x: hidden;
1100
+ }
1101
+ .data-subtab-content.active {
1102
+ display: flex;
1103
+ flex-direction: column;
1104
+ }
1105
+ /* History tab styles */
1106
+ .history-header {
1107
+ display: flex;
1108
+ justify-content: space-between;
1109
+ align-items: center;
1110
+ margin-bottom: 6px;
1111
+ flex-shrink: 0;
1112
+ }
1113
+ .history-list {
1114
+ display: flex;
1115
+ flex-direction: column;
1116
+ gap: 4px;
1117
+ flex: 1;
1118
+ overflow-y: auto;
1119
+ }
1120
+ .history-item {
1121
+ padding: 6px;
1122
+ background: var(--sim-bg);
1123
+ border: 1px solid var(--sim-border);
1124
+ border-radius: 2px;
1125
+ display: flex;
1126
+ flex-direction: row;
1127
+ gap: 8px;
1128
+ }
1129
+ .history-item:hover {
1130
+ border-color: var(--sim-border-light);
1131
+ }
1132
+ .history-item-thumb {
1133
+ width: 80px;
1134
+ height: 80px;
1135
+ flex-shrink: 0;
1136
+ background: var(--history-thumb-bg, var(--sim-bg-alt));
1137
+ border: 1px solid var(--sim-border);
1138
+ border-radius: 2px;
1139
+ display: flex;
1140
+ align-items: center;
1141
+ justify-content: center;
1142
+ overflow: hidden;
1143
+ }
1144
+ .history-item-thumb svg {
1145
+ width: 100%;
1146
+ height: 100%;
1147
+ }
1148
+ .history-item-thumb:empty {
1149
+ display: none;
1150
+ }
1151
+ .history-item-content {
1152
+ flex: 1;
1153
+ min-width: 0;
1154
+ display: flex;
1155
+ flex-direction: column;
1156
+ gap: 4px;
1157
+ }
1158
+ .history-item-header {
1159
+ display: flex;
1160
+ align-items: center;
1161
+ gap: 6px;
1162
+ }
1163
+ .history-item-num {
1164
+ color: var(--sim-accent);
1165
+ font-weight: bold;
1166
+ font-size: 9px;
1167
+ }
1168
+ .history-item-time {
1169
+ color: var(--sim-text-dim);
1170
+ font-size: 9px;
1171
+ flex: 1;
1172
+ }
1173
+ .history-item-preview {
1174
+ font-size: 9px;
1175
+ color: var(--sim-text);
1176
+ word-break: break-all;
1177
+ line-height: 1.3;
1178
+ background: var(--sim-bg-alt);
1179
+ padding: 3px 4px;
1180
+ border-radius: 2px;
1181
+ flex: 1;
1182
+ overflow: hidden;
1183
+ }
1184
+ /* Saves tab styles */
1185
+ .save-new {
1186
+ display: flex;
1187
+ gap: 4px;
1188
+ margin-bottom: 8px;
1189
+ flex-shrink: 0;
1190
+ }
1191
+ .save-new .simulator-input {
1192
+ flex: 1;
1193
+ }
1194
+ .saves-list {
1195
+ display: flex;
1196
+ flex-direction: column;
1197
+ gap: 4px;
1198
+ flex: 1;
1199
+ overflow-y: auto;
1200
+ }
1201
+ .save-item {
1202
+ padding: 6px;
1203
+ background: var(--sim-bg);
1204
+ border: 1px solid var(--sim-border);
1205
+ border-radius: 2px;
1206
+ }
1207
+ .save-item:hover {
1208
+ border-color: var(--sim-border-light);
1209
+ }
1210
+ .save-item-header {
1211
+ display: flex;
1212
+ justify-content: space-between;
1213
+ align-items: center;
1214
+ margin-bottom: 4px;
1215
+ }
1216
+ .save-item-name {
1217
+ color: var(--sim-text);
1218
+ font-weight: bold;
1219
+ font-size: 10px;
1220
+ }
1221
+ .save-item-time {
1222
+ color: var(--sim-text-dim);
1223
+ font-size: 9px;
1224
+ }
1225
+ .save-item-actions {
1226
+ display: flex;
1227
+ gap: 4px;
1228
+ }
1229
+ /* Features view styles */
1230
+ .features-view-container {
1231
+ display: flex;
1232
+ flex-direction: column;
1233
+ height: 100%;
1234
+ overflow: hidden;
1235
+ }
1236
+ .features-slug-input {
1237
+ display: flex;
1238
+ gap: 4px;
1239
+ margin-bottom: 8px;
1240
+ }
1241
+ .features-slug-input .simulator-input {
1242
+ flex: 1;
1243
+ }
1244
+ .features-content {
1245
+ flex: 1;
1246
+ overflow-y: auto;
1247
+ }
1248
+ .features-loading {
1249
+ color: var(--sim-text-dim);
1250
+ font-size: 10px;
1251
+ text-align: center;
1252
+ padding: 20px;
1253
+ }
1254
+ .features-error {
1255
+ color: var(--sim-error);
1256
+ font-size: 10px;
1257
+ padding: 8px;
1258
+ background: rgba(248, 113, 113, 0.1);
1259
+ border: 1px solid var(--sim-error);
1260
+ border-radius: 2px;
1261
+ }
1262
+ .features-empty {
1263
+ color: var(--sim-text-dim);
1264
+ font-size: 10px;
1265
+ text-align: center;
1266
+ padding: 20px;
1267
+ }
1268
+ .features-auth-required {
1269
+ color: var(--sim-text-dim);
1270
+ font-size: 10px;
1271
+ padding: 12px;
1272
+ background: var(--sim-bg);
1273
+ border: 1px solid var(--sim-border);
1274
+ border-radius: 2px;
1275
+ line-height: 1.5;
1276
+ }
1277
+ .features-auth-required p {
1278
+ margin: 0 0 8px 0;
1279
+ }
1280
+ .features-auth-required p:last-child {
1281
+ margin-bottom: 0;
1282
+ }
1283
+ .features-game-name {
1284
+ color: var(--sim-accent);
1285
+ font-size: 11px;
1286
+ font-weight: bold;
1287
+ margin-bottom: 8px;
1288
+ padding-bottom: 4px;
1289
+ border-bottom: 1px solid var(--sim-border);
1290
+ }
1291
+ .feature-group {
1292
+ margin-bottom: 12px;
1293
+ }
1294
+ .feature-group-title {
1295
+ color: var(--sim-text);
1296
+ font-size: 10px;
1297
+ font-weight: bold;
1298
+ text-transform: uppercase;
1299
+ letter-spacing: 0.5px;
1300
+ margin-bottom: 6px;
1301
+ padding-bottom: 2px;
1302
+ border-bottom: 1px solid var(--sim-border);
1303
+ }
1304
+ .feature-group-items {
1305
+ display: flex;
1306
+ flex-direction: column;
1307
+ gap: 2px;
1308
+ }
1309
+ .feature-item {
1310
+ display: flex;
1311
+ align-items: center;
1312
+ gap: 8px;
1313
+ padding: 4px 6px;
1314
+ background: var(--sim-bg);
1315
+ border: 1px solid var(--sim-border);
1316
+ border-radius: 2px;
1317
+ cursor: pointer;
1318
+ transition: all 0.15s ease;
1319
+ }
1320
+ .feature-item:hover {
1321
+ border-color: var(--sim-border-light);
1322
+ background: var(--sim-bg-alt);
1323
+ }
1324
+ .feature-item.updating {
1325
+ opacity: 0.5;
1326
+ pointer-events: none;
1327
+ }
1328
+ .feature-status {
1329
+ font-size: 14px;
1330
+ width: 18px;
1331
+ text-align: center;
1332
+ flex-shrink: 0;
1333
+ }
1334
+ .feature-item.enabled .feature-status {
1335
+ color: var(--sim-success);
1336
+ }
1337
+ .feature-item.disabled .feature-status {
1338
+ color: var(--sim-error);
1339
+ opacity: 0.5;
1340
+ }
1341
+ .feature-title {
1342
+ font-size: 10px;
1343
+ color: var(--sim-text);
1344
+ flex: 1;
1345
+ }
1346
+ .feature-item.disabled .feature-title {
1347
+ color: var(--sim-text-dim);
1348
+ }
1349
+ /* Checkpoints view styles */
1350
+ .checkpoints-view-container {
1351
+ display: flex;
1352
+ flex-direction: column;
1353
+ height: 100%;
1354
+ overflow: hidden;
1355
+ }
1356
+ .checkpoints-header {
1357
+ display: flex;
1358
+ justify-content: space-between;
1359
+ align-items: center;
1360
+ margin-bottom: 6px;
1361
+ flex-shrink: 0;
1362
+ }
1363
+ .checkpoints-list {
1364
+ display: flex;
1365
+ flex-direction: column;
1366
+ gap: 4px;
1367
+ flex: 1;
1368
+ overflow-y: auto;
1369
+ }
1370
+ .checkpoint-item {
1371
+ padding: 6px;
1372
+ background: var(--sim-bg);
1373
+ border: 1px solid var(--sim-border);
1374
+ border-left: 3px solid var(--sim-accent);
1375
+ border-radius: 2px;
1376
+ }
1377
+ .checkpoint-item:hover {
1378
+ border-color: var(--sim-border-light);
1379
+ border-left-color: var(--sim-accent);
1380
+ }
1381
+ .checkpoint-header {
1382
+ display: flex;
1383
+ justify-content: space-between;
1384
+ align-items: center;
1385
+ }
1386
+ .checkpoint-item .simulator-deeds {
1387
+ margin-top: 4px;
1388
+ }
1389
+ .checkpoint-name {
1390
+ color: var(--sim-accent);
1391
+ font-weight: bold;
1392
+ font-size: 10px;
1393
+ }
1394
+ .checkpoint-time {
1395
+ color: var(--sim-text-dim);
1396
+ font-size: 9px;
1397
+ }
1398
+ </style>
1399
+ <div id="simulator-panel" class="${g.isCollapsed?`collapsed`:``}">
1400
+ <div id="simulator-header">
1401
+ <span id="simulator-title">PUZZMO SIMULATOR</span>
1402
+ <span class="header-sep">|</span>
1403
+ <div id="simulator-timer">--:--</div>
1404
+ <span class="header-sep">|</span>
1405
+ <div id="simulator-header-controls">
1406
+ <button id="simulator-header-pause" class="header-icon-btn" title="Pause" disabled>${v.pause}</button>
1407
+ <button id="simulator-header-retry" class="header-icon-btn" title="Retry" disabled>${v.retry}</button>
1408
+ </div>
1409
+ <span class="header-sep">|</span>
1410
+ <div id="simulator-header-status">
1411
+ <span id="simulator-header-indicator" class="waiting"></span>
1412
+ <span id="simulator-header-status-text">Waiting...</span>
1413
+ </div>
1414
+ <span class="header-spacer"></span>
1415
+ <button id="simulator-header-settings" class="header-icon-btn" title="Settings">${v.cog}</button>
1416
+ <button id="simulator-toggle" class="header-icon-btn" title="Minimize">${v.minimize}</button>
1417
+ </div>
1418
+ <div id="simulator-body">
1419
+ <div id="simulator-tabs">
1420
+ ${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(``)}
1421
+ </div>
1422
+ <div id="simulator-content" class="hidden">
1423
+ ${m.map(e=>`<div id="simulator-tab-${e.id}" class="simulator-tab-content">${e.render()}</div>`).join(``)}
1424
+ </div>
1425
+ </div>
1426
+ </div>
1427
+ `,document.body.appendChild(y);let b=y.querySelector(`#simulator-panel`),x=y.querySelector(`#simulator-header`),S=y.querySelector(`#simulator-header-indicator`),C=y.querySelector(`#simulator-header-status-text`),w=y.querySelector(`#simulator-header-pause`),T=y.querySelector(`#simulator-header-retry`),E=y.querySelector(`#simulator-header-settings`),D=y.querySelector(`#simulator-toggle`),O=y.querySelector(`#simulator-timer`),k=y.querySelector(`#simulator-tabs`),A=y.querySelector(`#simulator-content`),j=e=>y.querySelector(e),M=e=>{w.innerHTML=e?v.play:v.pause,w.title=e?`Resume`:`Pause`},N=(e,t)=>{let n=j(`#simulator-status .text`),r=j(`#simulator-status .indicator`);n&&(n.textContent=e),r&&(r.className=`indicator ${t}`),S.className=t,C.textContent=e},P=(e,t)=>{t&&t!==`0`?O.innerHTML=`${e}<span class="penalty">+${t}</span>`:O.textContent=e},F=e=>{var t;g.activeTab=e,A.classList.remove(`hidden`),u(e),k.querySelectorAll(`.simulator-tab`).forEach(t=>{t.classList.toggle(`active`,t.getAttribute(`data-tab`)===e)}),y.querySelectorAll(`.simulator-tab-content`).forEach(t=>{t.classList.toggle(`active`,t.id===`simulator-tab-${e}`)}),E.classList.toggle(`active`,e===`auth`);let n=m.find(t=>t.id===e);n==null||(t=n.onActivate)==null||t.call(n,H)},I=e=>{g.isCollapsed=e,b.classList.toggle(`collapsed`,e),l(e),e?(A.classList.add(`hidden`),k.querySelectorAll(`.simulator-tab`).forEach(e=>e.classList.remove(`active`))):F(g.activeTab)},L=()=>{p.updatePreview(H)},R=function(){var t=e.n(function*(){if(g.puzzleData)return g.puzzleData;try{let e=yield fetch(a);if(!e.ok)throw Error(`Failed to load puzzle from ${a}`);g.puzzleData=yield e.json(),console.log(`Simulator: Puzzle loaded`,g.puzzleData),g.originalPuzzle=JSON.stringify(g.puzzleData,null,2);let t=j(`#simulator-puzzle`);return t&&(t.value=g.originalPuzzle),g.activeTab===`thumb`&&L(),g.puzzleData}catch(e){throw console.error(`Simulator: Failed to load puzzle`,e),e}});return function(){return t.apply(this,arguments)}}(),z=ee(e=>{f.addLogEntry(e,H)}),B=(e,t)=>{te(e,t,z)},V=(e,t)=>{let n=y.querySelector(`[data-badge="${e}"]`);n&&(n.textContent=t&&t>0?String(t):``)},H={state:g,getElement:j,sendToGame:B,logMessage:z.log,loadPuzzle:R,updateStatus:N,updateTimer:P,setCollapsed:I,switchTab:F,updateThumbnail:L,updateBadge:V,fixtures:s,fixtureCategories:d,gameSlug:(i=t.slug)==null?null:i};console.log(`[Simulator] Context created with gameSlug:`,H.gameSlug),m.forEach(e=>e.bind(H)),k.querySelectorAll(`.simulator-tab`).forEach(e=>{e.addEventListener(`click`,()=>{let t=e.getAttribute(`data-tab`);F(t),V(t,0)})}),D.addEventListener(`click`,e=>{e.stopPropagation(),I(!0)}),w.addEventListener(`click`,e=>{e.stopPropagation(),g.isPaused?(B(`RESUME_GAME`,{}),g.isPaused=!1,M(!1),N(`Running`,`ready`)):(B(`PAUSE_GAME`,{}),g.isPaused=!0,M(!0),N(`Paused`,`paused`));let t=j(`#simulator-pause`);t&&(t.textContent=g.isPaused?`Resume`:`Pause`)}),T.addEventListener(`click`,e=>{e.stopPropagation(),B(`RETRY_PUZZLE`,{}),g.hasStarted=!1,g.isPaused=!1,M(!1),w.disabled=!0,N(`Ready to retry`,`ready`);let t=j(`#simulator-pause`),n=j(`#simulator-start`);t&&(t.disabled=!0,t.textContent=`Pause`),n&&(n.textContent=`Start`)}),E.addEventListener(`click`,e=>{e.stopPropagation(),g.isCollapsed&&I(!1),F(`auth`)}),x.addEventListener(`click`,e=>{g.isCollapsed&&e.target!==D&&I(!1)}),g.isCollapsed||F(g.activeTab);let U=new URLSearchParams(window.location.search);(U.has(`code`)||U.has(`error`))&&(I(!1),F(`auth`));let W=e=>({userState:{gameSettings:{},id:`simulator-user`,nakamaLogin:`simulator`,ownerID:`simulator-owner`},currentUser:null,startOrFindGameplay:{gamePlayed:{additionalTimeAddedSecs:0,boardState:g.currentInputStr,cheatsUsed:0,combinedTimeSecs:0,completed:!1,createdAt:new Date().toISOString(),elapsedTimeSecs:0,hintsUsed:0,id:`simulator-gameplay-${Date.now()}`,metric1:0,metric2:0,metric3:0,metric4:0,metricStrings:[],ownerID:`simulator-owner`,pointsAwarded:0,resetsUsed:0,slug:`simulator-game`,viewerOwnsPuzzle:!0,puzzle:{id:`simulator-puzzle`,name:`Proto Jig Puzzle`,puzzle:JSON.stringify(e),seriesNumber:1,game:{assetsPath:`./assets/`,assetsSha:``,displayName:`Proto Game`,exposedGlobalFunction:`startGame`,jsPath:``,slug:`proto-game`}}}},theme:g.selectedTheme,hostFlags:[],hostContext:[],appRuntimeContract:`1.0`}),G=function(){var t=e.n(function*(){N(`Loading puzzle...`,`waiting`);try{let e=W(yield R());N(`Sending READY_DATA...`,`waiting`),B(`READY_DATA`,e),N(`Waiting for game to load...`,`waiting`)}catch(e){N(`Error: ${e}`,`paused`)}});return function(){return t.apply(this,arguments)}}(),K=()=>{console.log(`Simulator: Game loaded, ready to start`),T.disabled=!1,m.forEach(e=>{var t;return(t=e.onMessage)==null?void 0:t.call(e,`READY_GAME_LOADED`,void 0,H)}),o&&!g.hasStarted&&setTimeout(()=>{let e=j(`#simulator-start`);e==null||e.click(),w.disabled=!1,g.hasStarted=!0,N(`Running`,`ready`)},100)};return ne((e,t)=>{var n,r;if(e===`READY`){console.log(`Simulator: Received READY from game`),G();return}if(e===`INITIALIZE_SETTINGS`){console.log(`Simulator: Game initialized settings`,t);return}if(e===`READY_GAME_LOADED`){K();return}if(e===`TIMER_TICK`){if(t!=null&&t.display){let[e,n]=t.display;P(e,n)}return}if(e===`TIMER_SYNC`)return;if(e===`SHOW_GAME_COMPLETE_SCREEN`){console.log(`Simulator: Show completion screen`,t);return}if(e===`SIDEBAR_UPDATE`){console.log(`Simulator: Sidebar update`,t);return}m.forEach(n=>{var r;return(r=n.onMessage)==null?void 0:r.call(n,e,t,H)});let i=(n=t==null||(r=t.input)==null?void 0:r.boardState)==null?t==null?void 0:t.boardState:n;e===`UPLOAD_NEW_GAME_STATE`&&i&&(g.currentInputStr=i,g.activeTab===`thumb`&&L(),console.log(`Simulator: Game state uploaded`,t)),e===`GAME_COMPLETED`&&(console.log(`Simulator: Game completed!`,t),w.disabled=!0,g.hasStarted=!1,N(`Completed!`,`ready`))},z),console.log(`Simulator initialized`),$={updateFixtures:e=>{s=_(e),d=Array.from(s.keys()).sort(),H.fixtures=s,H.fixtureCategories=d;let t=localStorage.getItem(`simulator-fixture-category`);if(!g.selectedCategory||!d.includes(g.selectedCategory)){var n;g.selectedCategory=t&&d.includes(t)?t:(n=d[0])==null?null:n}let r=m.find(e=>e.id===`ctrl`);r==null||r.bind(H),console.log(`Simulator: Fixtures updated`,{categories:d,selectedCategory:g.selectedCategory})},sendToGame:B,loadPuzzle:R},$}Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return Pe}});
1428
+ //# sourceMappingURL=createSimulator-DxhvbnJB.cjs.map