web-a2e 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/.clangd +5 -0
  2. package/.mcp.json +12 -0
  3. package/CLAUDE.md +362 -0
  4. package/CMakeLists.txt +774 -0
  5. package/LICENSE +21 -0
  6. package/README.md +392 -0
  7. package/build-wasm/generated/roms.cpp +2447 -0
  8. package/docker-compose.staging.yml +9 -0
  9. package/docs/basic-rom-disassembly.md +6663 -0
  10. package/docs/softswitch-comparison.md +273 -0
  11. package/docs/thunderclock-debug.md +89 -0
  12. package/examples/cube.bas +72 -0
  13. package/examples/hello.s +55 -0
  14. package/examples/scroll.s +140 -0
  15. package/package.json +18 -0
  16. package/public/assets/apple-logo-old.png +0 -0
  17. package/public/assets/apple-logo.png +0 -0
  18. package/public/assets/drive-closed-light-on.png +0 -0
  19. package/public/assets/drive-closed.png +0 -0
  20. package/public/assets/drive-open-light-on.png +0 -0
  21. package/public/assets/drive-open.png +0 -0
  22. package/public/audio-worklet.js +82 -0
  23. package/public/disks/Apple DOS 3.3 January 1983.dsk +0 -0
  24. package/public/disks/ProDOS 2.4.3.po +0 -0
  25. package/public/disks/h32mb.2mg +0 -0
  26. package/public/disks/library.json +26 -0
  27. package/public/docs/llms/llm-assembler.txt +90 -0
  28. package/public/docs/llms/llm-basic-program.txt +256 -0
  29. package/public/docs/llms/llm-disk-drives.txt +72 -0
  30. package/public/docs/llms/llm-file-explorer.txt +50 -0
  31. package/public/docs/llms/llm-hard-drives.txt +80 -0
  32. package/public/docs/llms/llm-main.txt +51 -0
  33. package/public/docs/llms/llm-slot-configuration.txt +66 -0
  34. package/public/icons/icon-192.svg +4 -0
  35. package/public/icons/icon-512.svg +4 -0
  36. package/public/index.html +661 -0
  37. package/public/llms.txt +49 -0
  38. package/public/manifest.json +29 -0
  39. package/public/shaders/burnin.glsl +22 -0
  40. package/public/shaders/crt.glsl +706 -0
  41. package/public/shaders/edge.glsl +109 -0
  42. package/public/shaders/vertex.glsl +8 -0
  43. package/public/sw.js +186 -0
  44. package/roms/341-0027.bin +0 -0
  45. package/roms/341-0160-A-US-UK.bin +0 -0
  46. package/roms/341-0160-A.bin +0 -0
  47. package/roms/342-0273-A-US-UK.bin +0 -0
  48. package/roms/342-0349-B-C0-FF.bin +0 -0
  49. package/roms/Apple Mouse Interface Card ROM - 342-0270-C.bin +0 -0
  50. package/roms/Thunderclock Plus ROM.bin +0 -0
  51. package/scripts/generate_roms.sh +69 -0
  52. package/src/bindings/wasm_interface.cpp +1940 -0
  53. package/src/core/assembler/assembler.cpp +1239 -0
  54. package/src/core/assembler/assembler.hpp +115 -0
  55. package/src/core/audio/audio.cpp +160 -0
  56. package/src/core/audio/audio.hpp +81 -0
  57. package/src/core/basic/basic_detokenizer.cpp +436 -0
  58. package/src/core/basic/basic_detokenizer.hpp +41 -0
  59. package/src/core/basic/basic_tokenizer.cpp +286 -0
  60. package/src/core/basic/basic_tokenizer.hpp +26 -0
  61. package/src/core/basic/basic_tokens.hpp +295 -0
  62. package/src/core/cards/disk2_card.cpp +568 -0
  63. package/src/core/cards/disk2_card.hpp +316 -0
  64. package/src/core/cards/expansion_card.hpp +185 -0
  65. package/src/core/cards/mockingboard/ay8910.cpp +616 -0
  66. package/src/core/cards/mockingboard/ay8910.hpp +159 -0
  67. package/src/core/cards/mockingboard/via6522.cpp +530 -0
  68. package/src/core/cards/mockingboard/via6522.hpp +163 -0
  69. package/src/core/cards/mockingboard_card.cpp +312 -0
  70. package/src/core/cards/mockingboard_card.hpp +159 -0
  71. package/src/core/cards/mouse_card.cpp +654 -0
  72. package/src/core/cards/mouse_card.hpp +190 -0
  73. package/src/core/cards/smartport/block_device.cpp +202 -0
  74. package/src/core/cards/smartport/block_device.hpp +60 -0
  75. package/src/core/cards/smartport/smartport_card.cpp +603 -0
  76. package/src/core/cards/smartport/smartport_card.hpp +120 -0
  77. package/src/core/cards/thunderclock_card.cpp +237 -0
  78. package/src/core/cards/thunderclock_card.hpp +122 -0
  79. package/src/core/cpu/cpu6502.cpp +1609 -0
  80. package/src/core/cpu/cpu6502.hpp +203 -0
  81. package/src/core/debug/condition_evaluator.cpp +470 -0
  82. package/src/core/debug/condition_evaluator.hpp +87 -0
  83. package/src/core/disassembler/disassembler.cpp +552 -0
  84. package/src/core/disassembler/disassembler.hpp +171 -0
  85. package/src/core/disk-image/disk_image.hpp +267 -0
  86. package/src/core/disk-image/dsk_disk_image.cpp +827 -0
  87. package/src/core/disk-image/dsk_disk_image.hpp +204 -0
  88. package/src/core/disk-image/gcr_encoding.cpp +147 -0
  89. package/src/core/disk-image/gcr_encoding.hpp +78 -0
  90. package/src/core/disk-image/woz_disk_image.cpp +1049 -0
  91. package/src/core/disk-image/woz_disk_image.hpp +343 -0
  92. package/src/core/emulator.cpp +2126 -0
  93. package/src/core/emulator.hpp +434 -0
  94. package/src/core/filesystem/dos33.cpp +178 -0
  95. package/src/core/filesystem/dos33.hpp +66 -0
  96. package/src/core/filesystem/pascal.cpp +262 -0
  97. package/src/core/filesystem/pascal.hpp +87 -0
  98. package/src/core/filesystem/prodos.cpp +369 -0
  99. package/src/core/filesystem/prodos.hpp +119 -0
  100. package/src/core/input/keyboard.cpp +227 -0
  101. package/src/core/input/keyboard.hpp +111 -0
  102. package/src/core/mmu/mmu.cpp +1387 -0
  103. package/src/core/mmu/mmu.hpp +236 -0
  104. package/src/core/types.hpp +196 -0
  105. package/src/core/video/video.cpp +680 -0
  106. package/src/core/video/video.hpp +156 -0
  107. package/src/css/assembler-editor.css +1617 -0
  108. package/src/css/base.css +470 -0
  109. package/src/css/basic-debugger.css +791 -0
  110. package/src/css/basic-editor.css +792 -0
  111. package/src/css/controls.css +783 -0
  112. package/src/css/cpu-debugger.css +1413 -0
  113. package/src/css/debug-base.css +160 -0
  114. package/src/css/debug-windows.css +6455 -0
  115. package/src/css/disk-drives.css +406 -0
  116. package/src/css/documentation.css +392 -0
  117. package/src/css/file-explorer.css +867 -0
  118. package/src/css/hard-drive.css +180 -0
  119. package/src/css/layout.css +217 -0
  120. package/src/css/memory-windows.css +798 -0
  121. package/src/css/modals.css +510 -0
  122. package/src/css/monitor.css +425 -0
  123. package/src/css/release-notes.css +101 -0
  124. package/src/css/responsive.css +400 -0
  125. package/src/css/rule-builder.css +340 -0
  126. package/src/css/save-states.css +201 -0
  127. package/src/css/settings-windows.css +1231 -0
  128. package/src/css/window-switcher.css +150 -0
  129. package/src/js/agent/agent-manager.js +643 -0
  130. package/src/js/agent/agent-tools.js +293 -0
  131. package/src/js/agent/agent-version-tools.js +131 -0
  132. package/src/js/agent/assembler-tools.js +357 -0
  133. package/src/js/agent/basic-program-tools.js +894 -0
  134. package/src/js/agent/disk-tools.js +417 -0
  135. package/src/js/agent/file-explorer-tools.js +269 -0
  136. package/src/js/agent/index.js +13 -0
  137. package/src/js/agent/main-tools.js +222 -0
  138. package/src/js/agent/slot-tools.js +303 -0
  139. package/src/js/agent/smartport-tools.js +257 -0
  140. package/src/js/agent/window-tools.js +80 -0
  141. package/src/js/audio/audio-driver.js +417 -0
  142. package/src/js/audio/audio-worklet.js +85 -0
  143. package/src/js/audio/index.js +8 -0
  144. package/src/js/config/default-layout.js +34 -0
  145. package/src/js/config/version.js +8 -0
  146. package/src/js/data/apple2-rom-routines.js +577 -0
  147. package/src/js/debug/assembler-editor-window.js +2993 -0
  148. package/src/js/debug/basic-breakpoint-manager.js +529 -0
  149. package/src/js/debug/basic-program-parser.js +436 -0
  150. package/src/js/debug/basic-program-window.js +2594 -0
  151. package/src/js/debug/basic-variable-inspector.js +447 -0
  152. package/src/js/debug/breakpoint-manager.js +472 -0
  153. package/src/js/debug/cpu-debugger-window.js +2396 -0
  154. package/src/js/debug/index.js +22 -0
  155. package/src/js/debug/label-manager.js +238 -0
  156. package/src/js/debug/memory-browser-window.js +416 -0
  157. package/src/js/debug/memory-heat-map-window.js +481 -0
  158. package/src/js/debug/memory-map-window.js +206 -0
  159. package/src/js/debug/mockingboard-window.js +882 -0
  160. package/src/js/debug/mouse-card-window.js +355 -0
  161. package/src/js/debug/rule-builder-window.js +648 -0
  162. package/src/js/debug/soft-switch-window.js +458 -0
  163. package/src/js/debug/stack-viewer-window.js +221 -0
  164. package/src/js/debug/symbols.js +416 -0
  165. package/src/js/debug/trace-panel.js +291 -0
  166. package/src/js/debug/zero-page-watch-window.js +297 -0
  167. package/src/js/disk-manager/disk-drives-window.js +212 -0
  168. package/src/js/disk-manager/disk-operations.js +284 -0
  169. package/src/js/disk-manager/disk-persistence.js +301 -0
  170. package/src/js/disk-manager/disk-surface-renderer.js +388 -0
  171. package/src/js/disk-manager/drive-sounds.js +139 -0
  172. package/src/js/disk-manager/hard-drive-manager.js +481 -0
  173. package/src/js/disk-manager/hard-drive-persistence.js +187 -0
  174. package/src/js/disk-manager/hard-drive-window.js +57 -0
  175. package/src/js/disk-manager/index.js +890 -0
  176. package/src/js/display/display-settings-window.js +383 -0
  177. package/src/js/display/index.js +10 -0
  178. package/src/js/display/screen-window.js +342 -0
  179. package/src/js/display/webgl-renderer.js +705 -0
  180. package/src/js/file-explorer/disassembler.js +574 -0
  181. package/src/js/file-explorer/dos33.js +266 -0
  182. package/src/js/file-explorer/file-viewer.js +359 -0
  183. package/src/js/file-explorer/index.js +1261 -0
  184. package/src/js/file-explorer/prodos.js +549 -0
  185. package/src/js/file-explorer/utils.js +67 -0
  186. package/src/js/help/documentation-window.js +1096 -0
  187. package/src/js/help/index.js +10 -0
  188. package/src/js/help/release-notes-window.js +85 -0
  189. package/src/js/help/release-notes.js +612 -0
  190. package/src/js/input/gamepad-handler.js +176 -0
  191. package/src/js/input/index.js +12 -0
  192. package/src/js/input/input-handler.js +396 -0
  193. package/src/js/input/joystick-window.js +404 -0
  194. package/src/js/input/mouse-handler.js +99 -0
  195. package/src/js/input/text-selection.js +462 -0
  196. package/src/js/main.js +653 -0
  197. package/src/js/state/index.js +15 -0
  198. package/src/js/state/save-states-window.js +393 -0
  199. package/src/js/state/state-manager.js +409 -0
  200. package/src/js/state/state-persistence.js +218 -0
  201. package/src/js/ui/confirm.js +43 -0
  202. package/src/js/ui/disk-drive-positioner.js +347 -0
  203. package/src/js/ui/reminder-controller.js +129 -0
  204. package/src/js/ui/slot-configuration-window.js +560 -0
  205. package/src/js/ui/theme-manager.js +61 -0
  206. package/src/js/ui/toast.js +44 -0
  207. package/src/js/ui/ui-controller.js +897 -0
  208. package/src/js/ui/window-switcher.js +275 -0
  209. package/src/js/utils/basic-autocomplete.js +832 -0
  210. package/src/js/utils/basic-highlighting.js +473 -0
  211. package/src/js/utils/basic-tokenizer.js +153 -0
  212. package/src/js/utils/basic-tokens.js +117 -0
  213. package/src/js/utils/constants.js +28 -0
  214. package/src/js/utils/indexeddb-helper.js +225 -0
  215. package/src/js/utils/merlin-editor-support.js +905 -0
  216. package/src/js/utils/merlin-highlighting.js +551 -0
  217. package/src/js/utils/storage.js +125 -0
  218. package/src/js/utils/string-utils.js +19 -0
  219. package/src/js/utils/wasm-memory.js +54 -0
  220. package/src/js/windows/base-window.js +690 -0
  221. package/src/js/windows/index.js +9 -0
  222. package/src/js/windows/window-manager.js +375 -0
  223. package/tests/catch2/catch.hpp +17976 -0
  224. package/tests/common/basic_program_builder.cpp +119 -0
  225. package/tests/common/basic_program_builder.hpp +209 -0
  226. package/tests/common/disk_image_builder.cpp +444 -0
  227. package/tests/common/disk_image_builder.hpp +141 -0
  228. package/tests/common/test_helpers.hpp +118 -0
  229. package/tests/gcr/gcr-test.cpp +142 -0
  230. package/tests/integration/check-rom.js +70 -0
  231. package/tests/integration/compare-boot.js +239 -0
  232. package/tests/integration/crash-trace.js +102 -0
  233. package/tests/integration/disk-boot-test.js +264 -0
  234. package/tests/integration/memory-crash.js +108 -0
  235. package/tests/integration/nibble-read-test.js +249 -0
  236. package/tests/integration/phase-test.js +159 -0
  237. package/tests/integration/test_emulator.cpp +291 -0
  238. package/tests/integration/test_emulator_basic.cpp +91 -0
  239. package/tests/integration/test_emulator_debug.cpp +344 -0
  240. package/tests/integration/test_emulator_disk.cpp +153 -0
  241. package/tests/integration/test_emulator_state.cpp +163 -0
  242. package/tests/klaus/6502_functional_test.bin +0 -0
  243. package/tests/klaus/65C02_extended_opcodes_test.bin +0 -0
  244. package/tests/klaus/klaus_6502_test.cpp +184 -0
  245. package/tests/klaus/klaus_65c02_test.cpp +197 -0
  246. package/tests/thunderclock/thunderclock_mmu_test.cpp +304 -0
  247. package/tests/thunderclock/thunderclock_test.cpp +550 -0
  248. package/tests/unit/test_assembler.cpp +521 -0
  249. package/tests/unit/test_audio.cpp +196 -0
  250. package/tests/unit/test_ay8910.cpp +311 -0
  251. package/tests/unit/test_basic_detokenizer.cpp +265 -0
  252. package/tests/unit/test_basic_tokenizer.cpp +382 -0
  253. package/tests/unit/test_block_device.cpp +259 -0
  254. package/tests/unit/test_condition_evaluator.cpp +219 -0
  255. package/tests/unit/test_cpu6502.cpp +1301 -0
  256. package/tests/unit/test_cpu_addressing.cpp +361 -0
  257. package/tests/unit/test_cpu_cycle_counts.cpp +409 -0
  258. package/tests/unit/test_cpu_decimal.cpp +166 -0
  259. package/tests/unit/test_cpu_interrupts.cpp +285 -0
  260. package/tests/unit/test_disassembler.cpp +323 -0
  261. package/tests/unit/test_disk2_card.cpp +330 -0
  262. package/tests/unit/test_dos33.cpp +273 -0
  263. package/tests/unit/test_dsk_disk_image.cpp +315 -0
  264. package/tests/unit/test_expansion_card.cpp +178 -0
  265. package/tests/unit/test_gcr_encoding.cpp +232 -0
  266. package/tests/unit/test_keyboard.cpp +262 -0
  267. package/tests/unit/test_mmu.cpp +555 -0
  268. package/tests/unit/test_mmu_slots.cpp +323 -0
  269. package/tests/unit/test_mockingboard.cpp +352 -0
  270. package/tests/unit/test_mouse_card.cpp +386 -0
  271. package/tests/unit/test_pascal.cpp +248 -0
  272. package/tests/unit/test_prodos.cpp +259 -0
  273. package/tests/unit/test_smartport_card.cpp +321 -0
  274. package/tests/unit/test_thunderclock.cpp +354 -0
  275. package/tests/unit/test_via6522.cpp +323 -0
  276. package/tests/unit/test_video.cpp +319 -0
  277. package/tests/unit/test_woz_disk_image.cpp +257 -0
  278. package/vite.config.js +96 -0
  279. package/wiki/AI-Agent.md +372 -0
  280. package/wiki/Architecture-Overview.md +303 -0
  281. package/wiki/Audio-System.md +449 -0
  282. package/wiki/CPU-Emulation.md +477 -0
  283. package/wiki/Debugger.md +516 -0
  284. package/wiki/Disk-Drives.md +161 -0
  285. package/wiki/Disk-System-Internals.md +547 -0
  286. package/wiki/Display-Settings.md +88 -0
  287. package/wiki/Expansion-Slots.md +187 -0
  288. package/wiki/File-Explorer.md +259 -0
  289. package/wiki/Getting-Started.md +156 -0
  290. package/wiki/Home.md +69 -0
  291. package/wiki/Input-Devices.md +183 -0
  292. package/wiki/Keyboard-Shortcuts.md +158 -0
  293. package/wiki/Memory-System.md +364 -0
  294. package/wiki/Save-States.md +172 -0
  295. package/wiki/Video-Rendering.md +658 -0
@@ -0,0 +1,1617 @@
1
+ /* ==========================================================================
2
+ Assembler Editor Window
3
+ ========================================================================== */
4
+
5
+ .asm-editor-content {
6
+ display: flex;
7
+ flex-direction: column;
8
+ height: 100%;
9
+ gap: 0;
10
+ }
11
+
12
+ /* ═══════════════════════════════════════════════════════════════
13
+ TOOLBAR - Clean, organized action bar
14
+ ═══════════════════════════════════════════════════════════════ */
15
+ .asm-toolbar {
16
+ display: flex;
17
+ align-items: center;
18
+ gap: 6px;
19
+ padding: 4px 0 5px;
20
+ flex-shrink: 0;
21
+ border-bottom: 1px solid var(--glass-border-subtle);
22
+ margin-bottom: 6px;
23
+ }
24
+
25
+ .asm-toolbar-group {
26
+ display: flex;
27
+ align-items: center;
28
+ gap: 6px;
29
+ }
30
+
31
+ .asm-toolbar-actions {
32
+ gap: 4px;
33
+ }
34
+
35
+ .asm-toolbar-separator {
36
+ width: 1px;
37
+ height: 16px;
38
+ background: var(--glass-border);
39
+ margin: 0 4px;
40
+ }
41
+
42
+ .asm-toolbar-spacer {
43
+ flex: 1;
44
+ }
45
+
46
+ .asm-toolbar-org {
47
+ gap: 4px;
48
+ }
49
+
50
+ .asm-status-bar {
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: space-between;
54
+ padding: 3px 6px;
55
+ background: var(--input-bg);
56
+ border: 1px solid var(--glass-border-subtle);
57
+ border-radius: 4px;
58
+ margin-bottom: 4px;
59
+ flex-shrink: 0;
60
+ }
61
+
62
+ .asm-org-label {
63
+ font-size: 10px;
64
+ color: var(--text-muted);
65
+ font-family: var(--font-mono);
66
+ font-weight: 500;
67
+ }
68
+
69
+ .asm-org-input {
70
+ width: 64px;
71
+ padding: 5px 8px;
72
+ font-family: var(--font-mono);
73
+ font-size: 11px;
74
+ background: var(--input-bg-dark);
75
+ border: 1px solid var(--control-border);
76
+ border-radius: var(--radius-sm);
77
+ color: var(--text-primary);
78
+ text-align: center;
79
+ transition: all 0.15s;
80
+ }
81
+
82
+ .asm-org-input:focus {
83
+ border-color: var(--editor-focus-border);
84
+ box-shadow: 0 0 0 2px var(--editor-focus-shadow);
85
+ outline: none;
86
+ }
87
+
88
+ .asm-cursor-position {
89
+ font-size: 10px;
90
+ font-family: var(--font-mono);
91
+ color: var(--text-muted);
92
+ white-space: nowrap;
93
+ min-width: 80px;
94
+ }
95
+
96
+ .asm-status {
97
+ font-size: 11px;
98
+ font-family: var(--font-mono);
99
+ font-weight: 500;
100
+ color: var(--text-muted);
101
+ white-space: nowrap;
102
+ padding: 3px 10px;
103
+ border-radius: var(--radius-sm);
104
+ background: var(--glass-bg-header);
105
+ border: 1px solid var(--glass-border-subtle);
106
+ transition: all 0.2s;
107
+ }
108
+
109
+ .asm-status:empty {
110
+ display: none;
111
+ }
112
+
113
+ .asm-status-ok {
114
+ color: var(--accent-green);
115
+ background: var(--accent-green-bg);
116
+ border-color: var(--accent-green-border);
117
+ }
118
+
119
+ .asm-status-error {
120
+ color: var(--accent-red, #e03a3e);
121
+ background: var(--accent-red-bg, rgba(224, 58, 62, 0.1));
122
+ border-color: var(--accent-red-border, rgba(224, 58, 62, 0.3));
123
+ }
124
+
125
+ /* Split container - editor pane above, output pane below */
126
+ .asm-split-container {
127
+ flex: 1;
128
+ display: flex;
129
+ flex-direction: column;
130
+ min-height: 0;
131
+ overflow: hidden;
132
+ }
133
+
134
+ .asm-editor-pane {
135
+ flex: 0 0 65%;
136
+ display: flex;
137
+ flex-direction: column;
138
+ min-height: 0;
139
+ overflow: hidden;
140
+ }
141
+
142
+ .asm-output-pane {
143
+ flex: 0 0 35%;
144
+ display: flex;
145
+ flex-direction: column;
146
+ min-height: 0;
147
+ overflow: hidden;
148
+ }
149
+
150
+ /* Splitters */
151
+ .asm-splitter {
152
+ flex-shrink: 0;
153
+ display: flex;
154
+ align-items: center;
155
+ justify-content: center;
156
+ background: var(--glass-bg-header);
157
+ z-index: 2;
158
+ }
159
+
160
+ .asm-splitter-h {
161
+ height: 6px;
162
+ cursor: row-resize;
163
+ border-top: 1px solid var(--glass-border-subtle);
164
+ border-bottom: 1px solid var(--glass-border-subtle);
165
+ }
166
+
167
+ .asm-splitter-v {
168
+ width: 6px;
169
+ cursor: col-resize;
170
+ border-left: 1px solid var(--glass-border-subtle);
171
+ border-right: 1px solid var(--glass-border-subtle);
172
+ }
173
+
174
+ .asm-splitter-handle {
175
+ border-radius: 1px;
176
+ }
177
+
178
+ .asm-splitter-h .asm-splitter-handle {
179
+ width: 32px;
180
+ height: 2px;
181
+ background: var(--glass-border);
182
+ }
183
+
184
+ .asm-splitter-v .asm-splitter-handle {
185
+ width: 2px;
186
+ height: 32px;
187
+ background: var(--glass-border);
188
+ }
189
+
190
+ .asm-splitter:hover .asm-splitter-handle {
191
+ background: var(--accent-green-border);
192
+ }
193
+
194
+ /* Output panels - side by side */
195
+ .asm-output-panels {
196
+ display: flex;
197
+ flex-direction: row;
198
+ height: 100%;
199
+ min-height: 0;
200
+ }
201
+
202
+ /* ═══════════════════════════════════════════════════════════════
203
+ OUTPUT PANELS - Symbols and Hex Output
204
+ ═══════════════════════════════════════════════════════════════ */
205
+ .asm-panel {
206
+ flex: 1 1 50%;
207
+ display: flex;
208
+ flex-direction: column;
209
+ min-width: 0;
210
+ min-height: 0;
211
+ overflow: hidden;
212
+ }
213
+
214
+ .asm-panel-header {
215
+ flex-shrink: 0;
216
+ display: flex;
217
+ align-items: center;
218
+ justify-content: space-between;
219
+ padding: 4px 10px;
220
+ font-family: var(--font-sans);
221
+ font-size: 10px;
222
+ font-weight: 600;
223
+ color: var(--text-muted);
224
+ background: var(--glass-bg-header);
225
+ border-bottom: 1px solid var(--glass-border-subtle);
226
+ text-transform: uppercase;
227
+ letter-spacing: 0.5px;
228
+ }
229
+
230
+ .asm-panel-title {
231
+ display: flex;
232
+ align-items: center;
233
+ gap: 6px;
234
+ }
235
+
236
+ .asm-panel-count {
237
+ font-size: 9px;
238
+ font-weight: 500;
239
+ padding: 1px 6px;
240
+ border-radius: 8px;
241
+ background: var(--accent-green-bg);
242
+ color: var(--accent-green);
243
+ }
244
+
245
+ .asm-panel-count:empty {
246
+ display: none;
247
+ }
248
+
249
+ .asm-panel-content {
250
+ flex: 1;
251
+ overflow: auto;
252
+ background: var(--editor-bg);
253
+ }
254
+
255
+ .asm-panel-empty {
256
+ display: flex;
257
+ flex-direction: column;
258
+ align-items: center;
259
+ justify-content: center;
260
+ padding: 20px 12px;
261
+ height: 100%;
262
+ font-family: var(--font-sans);
263
+ text-align: center;
264
+ opacity: 0.6;
265
+ }
266
+
267
+ .asm-empty-icon {
268
+ font-family: var(--font-mono);
269
+ font-size: 20px;
270
+ color: var(--text-tertiary);
271
+ margin-bottom: 6px;
272
+ opacity: 0.5;
273
+ }
274
+
275
+ .asm-empty-text {
276
+ font-size: 11px;
277
+ color: var(--text-muted);
278
+ }
279
+
280
+ .asm-panel-error .asm-empty-icon {
281
+ color: var(--accent-red, #e03a3e);
282
+ opacity: 0.7;
283
+ }
284
+
285
+ .asm-panel-error .asm-empty-text {
286
+ color: var(--accent-red, #e03a3e);
287
+ opacity: 0.8;
288
+ }
289
+
290
+ /* ─────────────────────────────────────────────────────────────────
291
+ Symbol List - Grouped by type (Labels / Equates)
292
+ ───────────────────────────────────────────────────────────────── */
293
+ .asm-symbol-list {
294
+ padding: 4px 0;
295
+ }
296
+
297
+ .asm-symbol-group {
298
+ margin-bottom: 8px;
299
+ }
300
+
301
+ .asm-symbol-group:last-child {
302
+ margin-bottom: 0;
303
+ }
304
+
305
+ .asm-symbol-group-header {
306
+ padding: 4px 10px;
307
+ font-family: var(--font-sans);
308
+ font-size: 9px;
309
+ font-weight: 600;
310
+ text-transform: uppercase;
311
+ letter-spacing: 0.5px;
312
+ color: var(--text-tertiary);
313
+ background: var(--glass-bg);
314
+ border-bottom: 1px solid var(--glass-border-subtle);
315
+ }
316
+
317
+ .asm-symbol-row {
318
+ display: flex;
319
+ justify-content: space-between;
320
+ align-items: center;
321
+ padding: 3px 10px;
322
+ font-family: var(--font-mono);
323
+ font-size: 11px;
324
+ border-bottom: 1px solid var(--glass-border-subtle);
325
+ transition: background 0.1s;
326
+ }
327
+
328
+ .asm-symbol-row:last-child {
329
+ border-bottom: none;
330
+ }
331
+
332
+ .asm-symbol-row:hover {
333
+ background: var(--overlay-white-04, rgba(255, 255, 255, 0.04));
334
+ }
335
+
336
+ .asm-sym-name {
337
+ font-weight: 500;
338
+ }
339
+
340
+ .asm-sym-global {
341
+ color: var(--syntax-label, #d2a8ff);
342
+ }
343
+
344
+ .asm-sym-local {
345
+ color: var(--syntax-local, #ffa657);
346
+ }
347
+
348
+ .asm-sym-equ {
349
+ color: var(--syntax-data, #79c0ff);
350
+ }
351
+
352
+ .asm-sym-value {
353
+ color: var(--syntax-branch, #61bb46);
354
+ font-weight: 400;
355
+ }
356
+
357
+ /* ─────────────────────────────────────────────────────────────────
358
+ Hex Output - Machine code display with address, bytes, ASCII
359
+ ───────────────────────────────────────────────────────────────── */
360
+ .asm-hex-header {
361
+ display: flex;
362
+ justify-content: space-between;
363
+ align-items: center;
364
+ padding: 4px 10px;
365
+ font-family: var(--font-mono);
366
+ font-size: 10px;
367
+ background: var(--glass-bg);
368
+ border-bottom: 1px solid var(--glass-border-subtle);
369
+ }
370
+
371
+ .asm-hex-range {
372
+ color: var(--syntax-branch, #61bb46);
373
+ font-weight: 500;
374
+ }
375
+
376
+ .asm-hex-size {
377
+ color: var(--text-muted);
378
+ }
379
+
380
+ .asm-hex-dump {
381
+ font-family: var(--font-mono);
382
+ font-size: 11px;
383
+ line-height: 1.5;
384
+ padding: 4px 0;
385
+ }
386
+
387
+ .asm-hex-row {
388
+ display: flex;
389
+ align-items: center;
390
+ padding: 1px 8px;
391
+ white-space: pre;
392
+ transition: background 0.1s;
393
+ }
394
+
395
+ .asm-hex-row:hover {
396
+ background: var(--overlay-white-04, rgba(255, 255, 255, 0.04));
397
+ }
398
+
399
+ .asm-hex-addr {
400
+ color: var(--syntax-branch, #61bb46);
401
+ font-weight: 500;
402
+ flex-shrink: 0;
403
+ }
404
+
405
+ .asm-hex-sep {
406
+ color: var(--glass-border);
407
+ padding: 0 6px;
408
+ flex-shrink: 0;
409
+ }
410
+
411
+ .asm-hex-bytes {
412
+ color: var(--text-secondary);
413
+ flex-shrink: 0;
414
+ letter-spacing: 0.5px;
415
+ }
416
+
417
+ .asm-hex-ascii {
418
+ color: var(--syntax-load, #fdb827);
419
+ font-weight: 500;
420
+ letter-spacing: 1px;
421
+ opacity: 0.8;
422
+ }
423
+
424
+ /* Panel content scrollbars */
425
+ .asm-panel-content::-webkit-scrollbar {
426
+ width: 6px;
427
+ height: 6px;
428
+ }
429
+
430
+ .asm-panel-content::-webkit-scrollbar-track {
431
+ background: transparent;
432
+ }
433
+
434
+ .asm-panel-content::-webkit-scrollbar-thumb {
435
+ background: var(--glass-border);
436
+ border-radius: 3px;
437
+ }
438
+
439
+ .asm-panel-content::-webkit-scrollbar-thumb:hover {
440
+ background: var(--accent-green-border);
441
+ }
442
+
443
+ /* ═══════════════════════════════════════════════════════════════
444
+ EDITOR WRAPPER - Main code editing area with gutter
445
+ ═══════════════════════════════════════════════════════════════ */
446
+ .asm-editor-wrapper {
447
+ display: flex;
448
+ flex: 1;
449
+ min-height: 0;
450
+ border: 1px solid var(--glass-border);
451
+ border-radius: var(--radius-sm);
452
+ overflow: hidden;
453
+ transition: border-color 0.15s, box-shadow 0.15s;
454
+ }
455
+
456
+ .asm-editor-wrapper:focus-within {
457
+ border-color: var(--editor-focus-border);
458
+ box-shadow: 0 0 0 2px var(--editor-focus-shadow);
459
+ }
460
+
461
+ /* ─────────────────────────────────────────────────────────────────
462
+ Gutter Column - Line numbers, cycles, and bytes
463
+ ───────────────────────────────────────────────────────────────── */
464
+ .asm-gutter-column {
465
+ display: flex;
466
+ flex-direction: column;
467
+ flex-shrink: 0;
468
+ min-height: 0;
469
+ background: var(--glass-bg-header);
470
+ border-right: 1px solid var(--glass-border);
471
+ }
472
+
473
+ .asm-gutter-header {
474
+ flex-shrink: 0;
475
+ display: flex;
476
+ align-items: center;
477
+ height: 18px;
478
+ padding: 0 4px;
479
+ font-family: var(--font-mono);
480
+ font-size: 8px;
481
+ font-weight: 600;
482
+ text-transform: uppercase;
483
+ letter-spacing: 0.5px;
484
+ color: var(--text-tertiary);
485
+ background: var(--glass-bg);
486
+ border-bottom: 1px solid var(--glass-border-subtle);
487
+ user-select: none;
488
+ }
489
+
490
+ .asm-gutter-header-ln {
491
+ width: 28px;
492
+ text-align: right;
493
+ padding-right: 6px;
494
+ }
495
+
496
+ .asm-gutter-header-cyc {
497
+ width: 24px;
498
+ text-align: center;
499
+ color: var(--syntax-flag, #009ddc);
500
+ }
501
+
502
+ .asm-gutter-header-bytes {
503
+ width: 64px;
504
+ text-align: center;
505
+ color: var(--syntax-math, #f5821f);
506
+ }
507
+
508
+ .asm-gutter-content {
509
+ flex: 1 1 0;
510
+ min-height: 0;
511
+ padding: 8px 0; /* Match textarea padding top/bottom */
512
+ /* Use identical font specification as textarea for exact line height match */
513
+ font: 400 12px/1.4 ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
514
+ overflow-y: scroll;
515
+ overflow-x: hidden;
516
+ user-select: none;
517
+ scrollbar-width: none;
518
+ -ms-overflow-style: none;
519
+ background: var(--glass-bg-header);
520
+ }
521
+
522
+ .asm-gutter-content::-webkit-scrollbar {
523
+ display: none;
524
+ }
525
+
526
+ .asm-gutter-line {
527
+ display: flex;
528
+ align-items: center;
529
+ position: relative;
530
+ /* Don't set fixed height - let line-height from parent control it */
531
+ padding: 0 4px;
532
+ white-space: nowrap;
533
+ }
534
+
535
+ .asm-gutter-line:hover {
536
+ background: var(--overlay-white-04, rgba(255, 255, 255, 0.04));
537
+ }
538
+
539
+ .asm-gutter-ln {
540
+ flex-shrink: 0;
541
+ width: 24px;
542
+ text-align: right;
543
+ padding-right: 4px;
544
+ color: var(--text-tertiary);
545
+ opacity: 0.6;
546
+ }
547
+
548
+ .asm-gutter-cyc {
549
+ flex-shrink: 0;
550
+ width: 20px;
551
+ text-align: center;
552
+ color: var(--syntax-flag, #009ddc);
553
+ font-weight: 500;
554
+ }
555
+
556
+ .asm-gutter-bytes {
557
+ flex-shrink: 0;
558
+ width: 72px;
559
+ text-align: left;
560
+ padding-left: 4px;
561
+ color: var(--syntax-math, #f5821f);
562
+ font-size: 10px;
563
+ letter-spacing: 0;
564
+ overflow: hidden;
565
+ text-overflow: ellipsis;
566
+ }
567
+
568
+ .asm-gutter-error {
569
+ background: var(--accent-red-bg, rgba(224, 58, 62, 0.12));
570
+ }
571
+
572
+ .asm-gutter-error .asm-gutter-ln {
573
+ color: var(--accent-red, #e03a3e);
574
+ opacity: 1;
575
+ }
576
+
577
+ /* Breakpoint column in gutter */
578
+ .asm-gutter-header-bp {
579
+ width: 14px;
580
+ flex-shrink: 0;
581
+ }
582
+
583
+ .asm-gutter-bp-dot,
584
+ .asm-gutter-bp-space {
585
+ display: inline-block;
586
+ position: relative;
587
+ width: 14px;
588
+ height: 100%;
589
+ flex-shrink: 0;
590
+ text-align: center;
591
+ vertical-align: middle;
592
+ }
593
+
594
+ .asm-gutter-bp-dot::after {
595
+ content: '';
596
+ position: absolute;
597
+ left: 50%;
598
+ top: 50%;
599
+ transform: translate(-50%, -50%);
600
+ width: 8px;
601
+ height: 8px;
602
+ background: var(--accent-red, #e03a3e);
603
+ border-radius: 50%;
604
+ box-shadow: 0 0 4px rgba(224, 58, 62, 0.6);
605
+ }
606
+
607
+ .asm-gutter-line:hover .asm-gutter-bp-clickable::after {
608
+ content: '';
609
+ position: absolute;
610
+ left: 50%;
611
+ top: 50%;
612
+ transform: translate(-50%, -50%);
613
+ width: 8px;
614
+ height: 8px;
615
+ background: var(--text-tertiary);
616
+ border-radius: 50%;
617
+ opacity: 0.3;
618
+ }
619
+
620
+ .asm-gutter-line {
621
+ cursor: pointer;
622
+ }
623
+
624
+ .asm-gutter-bp {
625
+ background: var(--accent-red-bg, rgba(224, 58, 62, 0.08));
626
+ }
627
+
628
+ /* ─────────────────────────────────────────────────────────────────
629
+ Editor Container - Code area with overlay highlighting
630
+ ───────────────────────────────────────────────────────────────── */
631
+ .asm-editor-container {
632
+ flex: 1;
633
+ display: flex;
634
+ flex-direction: column;
635
+ min-height: 80px;
636
+ background: var(--editor-bg);
637
+ overflow: hidden;
638
+ }
639
+
640
+ .asm-editor-header {
641
+ flex-shrink: 0;
642
+ position: relative;
643
+ display: flex;
644
+ align-items: center;
645
+ height: 18px;
646
+ padding: 0 8px;
647
+ font-family: var(--font-mono);
648
+ font-size: 8px;
649
+ font-weight: 600;
650
+ text-transform: uppercase;
651
+ letter-spacing: 0.5px;
652
+ color: var(--text-tertiary);
653
+ background: var(--glass-bg);
654
+ border-bottom: 1px solid var(--glass-border-subtle);
655
+ user-select: none;
656
+ overflow: hidden;
657
+ }
658
+
659
+ .asm-editor-header-label {
660
+ position: absolute;
661
+ left: 8px;
662
+ color: var(--syntax-label, #d2a8ff);
663
+ opacity: 0.6;
664
+ }
665
+
666
+ .asm-editor-header-opcode {
667
+ position: absolute;
668
+ color: var(--syntax-branch, #61bb46);
669
+ opacity: 0.6;
670
+ }
671
+
672
+ .asm-editor-header-operand {
673
+ position: absolute;
674
+ color: var(--syntax-load, #fdb827);
675
+ opacity: 0.6;
676
+ }
677
+
678
+ .asm-editor-header-comment {
679
+ position: absolute;
680
+ color: var(--syntax-comment, #8b949e);
681
+ opacity: 0.6;
682
+ }
683
+
684
+ .asm-editor-scroll-area {
685
+ flex: 1;
686
+ position: relative;
687
+ min-height: 0;
688
+ overflow: hidden;
689
+ }
690
+
691
+ /* Column guides - vertical lines at Merlin column positions */
692
+ .asm-column-guides {
693
+ position: absolute;
694
+ top: 0;
695
+ left: 0;
696
+ right: 0;
697
+ bottom: 0;
698
+ pointer-events: none;
699
+ z-index: 0;
700
+ overflow: hidden;
701
+ }
702
+
703
+ .asm-column-guide {
704
+ position: absolute;
705
+ top: 0;
706
+ bottom: 0;
707
+ width: 1px;
708
+ background: var(--glass-border-subtle);
709
+ opacity: 0.3;
710
+ }
711
+
712
+ .asm-column-guide[data-col="9"] {
713
+ border-left: 1px dashed var(--syntax-branch, #61bb46);
714
+ opacity: 0.15;
715
+ background: transparent;
716
+ }
717
+
718
+ .asm-column-guide[data-col="14"] {
719
+ border-left: 1px dashed var(--syntax-load, #fdb827);
720
+ opacity: 0.15;
721
+ background: transparent;
722
+ }
723
+
724
+ .asm-column-guide[data-col="25"] {
725
+ border-left: 1px dashed var(--syntax-comment, #8b949e);
726
+ opacity: 0.12;
727
+ background: transparent;
728
+ }
729
+
730
+ /* Current line highlight bar */
731
+ .asm-line-highlight {
732
+ position: absolute;
733
+ left: 0;
734
+ right: 0;
735
+ pointer-events: none;
736
+ background: linear-gradient(90deg,
737
+ var(--accent-green-bg) 0%,
738
+ var(--overlay-white-04, rgba(255, 255, 255, 0.04)) 100%
739
+ );
740
+ border-left: 2px solid var(--accent-green);
741
+ opacity: 0;
742
+ transition: opacity 0.12s;
743
+ z-index: 0;
744
+ }
745
+
746
+ .asm-line-highlight.visible {
747
+ opacity: 1;
748
+ }
749
+
750
+ /* Shared styles for textarea and highlight overlay - MUST be identical */
751
+ .asm-textarea,
752
+ .asm-highlight {
753
+ position: absolute;
754
+ top: 0;
755
+ left: 0;
756
+ width: 100%;
757
+ height: 100%;
758
+ padding: 8px;
759
+ margin: 0;
760
+ border: 0;
761
+ border-radius: 0;
762
+ font: 400 12px/1.4 ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
763
+ letter-spacing: 0;
764
+ word-spacing: 0;
765
+ text-transform: none;
766
+ text-indent: 0;
767
+ text-shadow: none;
768
+ text-align: left;
769
+ text-decoration: none;
770
+ white-space: pre;
771
+ overflow-wrap: normal;
772
+ word-wrap: normal;
773
+ word-break: normal;
774
+ hyphens: none;
775
+ box-sizing: border-box;
776
+ tab-size: 8;
777
+ -moz-tab-size: 8;
778
+ -webkit-font-smoothing: antialiased;
779
+ -moz-osx-font-smoothing: grayscale;
780
+ font-feature-settings: "liga" 0, "calt" 0;
781
+ font-kerning: none;
782
+ font-variant-ligatures: none;
783
+ }
784
+
785
+ /* Highlight layer - shows colored syntax */
786
+ .asm-highlight {
787
+ pointer-events: none;
788
+ overflow: scroll;
789
+ scrollbar-width: none; /* Firefox */
790
+ -ms-overflow-style: none; /* IE/Edge */
791
+ color: var(--text-primary);
792
+ background: transparent;
793
+ z-index: 1;
794
+ /* Reset pre defaults */
795
+ display: block;
796
+ }
797
+
798
+ .asm-highlight::-webkit-scrollbar {
799
+ display: none; /* Chrome/Safari */
800
+ }
801
+
802
+ /* Textarea - transparent text, receives input */
803
+ .asm-textarea {
804
+ color: transparent;
805
+ -webkit-text-fill-color: transparent;
806
+ caret-color: var(--accent-green);
807
+ background: transparent;
808
+ resize: none;
809
+ outline: none;
810
+ z-index: 2;
811
+ overflow: auto;
812
+ }
813
+
814
+ .asm-textarea::placeholder {
815
+ color: var(--editor-placeholder);
816
+ opacity: 0.5;
817
+ white-space: pre;
818
+ font-family: var(--font-mono);
819
+ }
820
+
821
+ /* Error line - just mark the text, no layout changes */
822
+ .asm-error-line {
823
+ /* No styles here - error highlighting is done via overlay */
824
+ }
825
+
826
+ /* Errors overlay - positioned absolutely, scrolls with content */
827
+ .asm-errors-overlay {
828
+ position: absolute;
829
+ top: 0;
830
+ right: 0;
831
+ left: 0;
832
+ pointer-events: none;
833
+ z-index: 10;
834
+ }
835
+
836
+ .asm-error-highlight {
837
+ position: absolute;
838
+ left: 0;
839
+ right: 0;
840
+ background: var(--accent-red-bg, rgba(224, 58, 62, 0.12));
841
+ border-left: 3px solid var(--accent-red, #e03a3e);
842
+ }
843
+
844
+ .asm-error-msg {
845
+ position: absolute;
846
+ right: 8px;
847
+ padding: 2px 8px;
848
+ font-family: var(--font-mono);
849
+ font-size: 10px;
850
+ line-height: 1.4;
851
+ color: var(--accent-red, #e03a3e);
852
+ background: var(--glass-bg, rgba(30, 30, 30, 0.95));
853
+ border: 1px solid var(--accent-red-border, rgba(224, 58, 62, 0.4));
854
+ border-radius: 3px;
855
+ white-space: nowrap;
856
+ z-index: 3;
857
+ transform: translateY(-50%);
858
+ }
859
+
860
+ /* ═══════════════════════════════════════════════════════════════
861
+ TOOLBAR BUTTONS - Action buttons with icons
862
+ ═══════════════════════════════════════════════════════════════ */
863
+ .asm-btn {
864
+ display: inline-flex;
865
+ align-items: center;
866
+ gap: 4px;
867
+ padding: 4px 8px;
868
+ font-family: var(--font-sans);
869
+ font-size: 10px;
870
+ font-weight: 500;
871
+ background: var(--glass-bg-header);
872
+ border: 1px solid var(--control-border);
873
+ border-radius: var(--radius-sm);
874
+ color: var(--text-secondary);
875
+ cursor: pointer;
876
+ transition: all 0.15s;
877
+ white-space: nowrap;
878
+ }
879
+
880
+ .asm-btn-icon {
881
+ font-size: 10px;
882
+ opacity: 0.8;
883
+ }
884
+
885
+ .asm-btn-icon-only {
886
+ padding: 4px 6px;
887
+ min-width: 28px;
888
+ justify-content: center;
889
+ }
890
+
891
+ .asm-btn-icon-only .asm-btn-icon {
892
+ font-size: 12px;
893
+ opacity: 1;
894
+ }
895
+
896
+ .asm-toolbar-file {
897
+ display: flex;
898
+ gap: 2px;
899
+ }
900
+
901
+ .asm-btn:hover {
902
+ background: var(--glass-border);
903
+ color: var(--text-primary);
904
+ }
905
+
906
+ .asm-btn:active {
907
+ transform: scale(0.98);
908
+ }
909
+
910
+ .asm-btn:disabled {
911
+ opacity: 0.4;
912
+ cursor: not-allowed;
913
+ }
914
+
915
+ .asm-btn:disabled:active {
916
+ transform: none;
917
+ }
918
+
919
+ .asm-assemble-btn {
920
+ background: var(--accent-blue-bg, rgba(0, 157, 220, 0.1));
921
+ border-color: var(--accent-blue-border, rgba(0, 157, 220, 0.25));
922
+ color: var(--accent-blue, #009DDC);
923
+ }
924
+
925
+ .asm-assemble-btn:hover {
926
+ background: var(--accent-blue-bg-strong, rgba(0, 157, 220, 0.2));
927
+ border-color: var(--accent-blue-border, rgba(0, 157, 220, 0.4));
928
+ color: var(--accent-blue, #009DDC);
929
+ }
930
+
931
+ .asm-load-btn:hover:not(:disabled) {
932
+ background: var(--accent-green-bg-strong);
933
+ border-color: var(--accent-green-border);
934
+ color: var(--accent-green);
935
+ }
936
+
937
+ .asm-rom-btn {
938
+ background: var(--accent-purple-bg, rgba(150, 61, 151, 0.1));
939
+ border-color: var(--accent-purple-border, rgba(150, 61, 151, 0.25));
940
+ color: var(--accent-purple, #963D97);
941
+ }
942
+
943
+ .asm-rom-btn:hover {
944
+ background: var(--accent-purple-bg-strong, rgba(150, 61, 151, 0.2));
945
+ border-color: var(--accent-purple-border, rgba(150, 61, 151, 0.4));
946
+ color: var(--accent-purple, #963D97);
947
+ }
948
+
949
+ .asm-btn-success {
950
+ background: var(--accent-green-bg-stronger) !important;
951
+ border-color: rgba(63, 185, 80, 0.6) !important;
952
+ color: var(--accent-green) !important;
953
+ animation: asm-load-pulse 0.3s ease-out;
954
+ }
955
+
956
+ @keyframes asm-load-pulse {
957
+ 0% { transform: scale(1); }
958
+ 50% { transform: scale(1.03); }
959
+ 100% { transform: scale(1); }
960
+ }
961
+
962
+ /* ─────────────────────────────────────────────────────────────────
963
+ Column Indicator - Shows current Merlin column
964
+ ───────────────────────────────────────────────────────────────── */
965
+ .asm-column-indicator {
966
+ font-size: 10px;
967
+ font-family: var(--font-mono);
968
+ font-weight: 500;
969
+ white-space: nowrap;
970
+ padding: 3px 8px;
971
+ border-radius: var(--radius-sm);
972
+ background: var(--glass-bg-header);
973
+ border: 1px solid var(--glass-border-subtle);
974
+ transition: all 0.15s;
975
+ min-width: 60px;
976
+ text-align: center;
977
+ }
978
+
979
+ .asm-col-label {
980
+ color: var(--syntax-label, #d2a8ff);
981
+ background: rgba(210, 168, 255, 0.1);
982
+ border-color: rgba(210, 168, 255, 0.25);
983
+ }
984
+
985
+ .asm-col-opcode {
986
+ color: var(--syntax-branch, #61bb46);
987
+ background: rgba(97, 187, 70, 0.1);
988
+ border-color: rgba(97, 187, 70, 0.25);
989
+ }
990
+
991
+ .asm-col-operand {
992
+ color: var(--syntax-load, #fdb827);
993
+ background: rgba(253, 184, 39, 0.1);
994
+ border-color: rgba(253, 184, 39, 0.25);
995
+ }
996
+
997
+ .asm-col-comment {
998
+ color: var(--syntax-comment, #8b949e);
999
+ background: rgba(139, 148, 158, 0.1);
1000
+ border-color: rgba(139, 148, 158, 0.25);
1001
+ }
1002
+
1003
+ /* Assembler autocomplete dropdown */
1004
+ .asm-autocomplete-dropdown {
1005
+ position: absolute;
1006
+ z-index: 1000;
1007
+ display: none;
1008
+ width: 260px;
1009
+ background: rgba(22, 27, 34, 0.98);
1010
+ border: 1px solid var(--accent-green-border);
1011
+ border-radius: var(--radius-sm);
1012
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(0, 0, 0, 0.3);
1013
+ overflow: hidden;
1014
+ }
1015
+
1016
+ .asm-autocomplete-dropdown.visible {
1017
+ display: block;
1018
+ }
1019
+
1020
+ .asm-autocomplete-dropdown .autocomplete-list {
1021
+ max-height: 180px;
1022
+ overflow-y: auto;
1023
+ }
1024
+
1025
+ .asm-autocomplete-dropdown .autocomplete-item {
1026
+ display: flex;
1027
+ justify-content: space-between;
1028
+ align-items: center;
1029
+ padding: 5px 10px;
1030
+ cursor: pointer;
1031
+ border-bottom: 1px solid var(--glass-border-subtle);
1032
+ }
1033
+
1034
+ .asm-autocomplete-dropdown .autocomplete-item:last-child {
1035
+ border-bottom: none;
1036
+ }
1037
+
1038
+ .asm-autocomplete-dropdown .autocomplete-item:hover {
1039
+ background: var(--accent-green-bg);
1040
+ }
1041
+
1042
+ .asm-autocomplete-dropdown .autocomplete-item.selected {
1043
+ background: rgba(63, 185, 80, 0.25);
1044
+ }
1045
+
1046
+ .asm-autocomplete-dropdown .autocomplete-keyword {
1047
+ font-family: var(--font-mono);
1048
+ font-size: 11px;
1049
+ font-weight: 500;
1050
+ }
1051
+
1052
+ .asm-autocomplete-dropdown .autocomplete-keyword .match {
1053
+ color: var(--accent-green);
1054
+ font-weight: 700;
1055
+ }
1056
+
1057
+ .asm-autocomplete-dropdown .autocomplete-category {
1058
+ font-family: var(--font-sans);
1059
+ font-size: 9px;
1060
+ color: var(--text-muted);
1061
+ text-transform: uppercase;
1062
+ letter-spacing: 0.3px;
1063
+ opacity: 0.7;
1064
+ }
1065
+
1066
+ /* Category colours matching syntax highlighting */
1067
+ .asm-autocomplete-dropdown .autocomplete-keyword.mer-branch {
1068
+ color: var(--syntax-branch, #61bb46);
1069
+ }
1070
+
1071
+ .asm-autocomplete-dropdown .autocomplete-keyword.mer-load {
1072
+ color: var(--syntax-load, #fdb827);
1073
+ }
1074
+
1075
+ .asm-autocomplete-dropdown .autocomplete-keyword.mer-math {
1076
+ color: var(--syntax-math, #f5821f);
1077
+ }
1078
+
1079
+ .asm-autocomplete-dropdown .autocomplete-keyword.mer-stack {
1080
+ color: var(--syntax-stack, #963d97);
1081
+ }
1082
+
1083
+ .asm-autocomplete-dropdown .autocomplete-keyword.mer-flag {
1084
+ color: var(--syntax-flag, #009ddc);
1085
+ }
1086
+
1087
+ .asm-autocomplete-dropdown .autocomplete-keyword.mer-directive {
1088
+ color: var(--syntax-keyword, #ff7b72);
1089
+ }
1090
+
1091
+ .asm-autocomplete-dropdown .autocomplete-keyword.mer-macro {
1092
+ color: var(--syntax-data, #79c0ff);
1093
+ }
1094
+
1095
+ .asm-autocomplete-dropdown .autocomplete-keyword.mer-label {
1096
+ color: var(--syntax-label, #d2a8ff);
1097
+ }
1098
+
1099
+ .asm-autocomplete-dropdown .autocomplete-keyword.mer-local {
1100
+ color: var(--syntax-local, #ffa657);
1101
+ }
1102
+
1103
+ .asm-autocomplete-dropdown .autocomplete-hint {
1104
+ padding: 6px 10px;
1105
+ background: rgba(33, 38, 45, 0.8);
1106
+ border-top: 1px solid var(--separator-bg);
1107
+ }
1108
+
1109
+ .asm-autocomplete-dropdown .hint-syntax {
1110
+ font-family: var(--font-mono);
1111
+ font-size: 10px;
1112
+ color: var(--syntax-keyword);
1113
+ margin-bottom: 2px;
1114
+ }
1115
+
1116
+ .asm-autocomplete-dropdown .hint-desc {
1117
+ font-family: var(--font-sans);
1118
+ font-size: 9px;
1119
+ color: var(--text-muted);
1120
+ }
1121
+
1122
+ .asm-autocomplete-dropdown .autocomplete-list::-webkit-scrollbar {
1123
+ width: 6px;
1124
+ }
1125
+
1126
+ .asm-autocomplete-dropdown .autocomplete-list::-webkit-scrollbar-track {
1127
+ background: transparent;
1128
+ }
1129
+
1130
+ .asm-autocomplete-dropdown .autocomplete-list::-webkit-scrollbar-thumb {
1131
+ background: var(--glass-border);
1132
+ border-radius: 3px;
1133
+ }
1134
+
1135
+ .asm-autocomplete-dropdown .autocomplete-list::-webkit-scrollbar-thumb:hover {
1136
+ background: var(--accent-green-border);
1137
+ }
1138
+
1139
+ /* ═══════════════════════════════════════════════════════════════
1140
+ SHORTCUTS BAR - Keyboard hints at bottom of editor
1141
+ ═══════════════════════════════════════════════════════════════ */
1142
+ .asm-shortcuts-bar {
1143
+ display: flex;
1144
+ align-items: center;
1145
+ justify-content: center;
1146
+ gap: 16px;
1147
+ padding: 4px 8px;
1148
+ background: var(--glass-bg);
1149
+ border-top: 1px solid var(--glass-border-subtle);
1150
+ flex-shrink: 0;
1151
+ }
1152
+
1153
+ .asm-shortcut {
1154
+ display: inline-flex;
1155
+ align-items: center;
1156
+ gap: 4px;
1157
+ font-family: var(--font-sans);
1158
+ font-size: 10px;
1159
+ color: var(--text-tertiary);
1160
+ }
1161
+
1162
+ .asm-shortcut kbd {
1163
+ display: inline-block;
1164
+ padding: 1px 5px;
1165
+ font-family: var(--font-mono);
1166
+ font-size: 9px;
1167
+ font-weight: 500;
1168
+ color: var(--text-secondary);
1169
+ background: var(--glass-bg-header);
1170
+ border: 1px solid var(--glass-border);
1171
+ border-radius: 3px;
1172
+ box-shadow: 0 1px 0 var(--glass-border);
1173
+ }
1174
+
1175
+ /* ═══════════════════════════════════════════════════════════════
1176
+ SAVE DIALOG MODAL
1177
+ ═══════════════════════════════════════════════════════════════ */
1178
+ .asm-save-modal {
1179
+ position: absolute;
1180
+ top: 0;
1181
+ left: 0;
1182
+ right: 0;
1183
+ bottom: 0;
1184
+ display: flex;
1185
+ align-items: center;
1186
+ justify-content: center;
1187
+ background: rgba(0, 0, 0, 0.5);
1188
+ backdrop-filter: blur(4px);
1189
+ z-index: 200;
1190
+ }
1191
+
1192
+ .asm-save-modal.hidden {
1193
+ display: none;
1194
+ }
1195
+
1196
+ .asm-save-dialog {
1197
+ width: 320px;
1198
+ background: var(--glass-bg-solid);
1199
+ border: 1px solid var(--glass-border);
1200
+ border-radius: 8px;
1201
+ box-shadow: var(--shadow-lg);
1202
+ overflow: hidden;
1203
+ }
1204
+
1205
+ .asm-save-header {
1206
+ padding: 12px 16px;
1207
+ background: var(--glass-bg-header);
1208
+ border-bottom: 1px solid var(--glass-border-subtle);
1209
+ }
1210
+
1211
+ .asm-save-title {
1212
+ font-family: var(--font-sans);
1213
+ font-size: 13px;
1214
+ font-weight: 600;
1215
+ color: var(--text-primary);
1216
+ }
1217
+
1218
+ .asm-save-content {
1219
+ padding: 16px;
1220
+ }
1221
+
1222
+ .asm-save-label {
1223
+ display: block;
1224
+ font-family: var(--font-sans);
1225
+ font-size: 11px;
1226
+ font-weight: 500;
1227
+ color: var(--text-secondary);
1228
+ margin-bottom: 8px;
1229
+ }
1230
+
1231
+ .asm-save-input-row {
1232
+ display: flex;
1233
+ align-items: center;
1234
+ gap: 4px;
1235
+ }
1236
+
1237
+ .asm-save-input {
1238
+ flex: 1;
1239
+ padding: 8px 12px;
1240
+ font-family: var(--font-mono);
1241
+ font-size: 13px;
1242
+ color: var(--text-primary);
1243
+ background: var(--editor-bg);
1244
+ border: 1px solid var(--glass-border);
1245
+ border-radius: 4px;
1246
+ outline: none;
1247
+ transition: border-color 0.15s, box-shadow 0.15s;
1248
+ }
1249
+
1250
+ .asm-save-input:focus {
1251
+ border-color: var(--accent-blue);
1252
+ box-shadow: 0 0 0 3px var(--accent-blue-bg);
1253
+ }
1254
+
1255
+ .asm-save-ext {
1256
+ font-family: var(--font-mono);
1257
+ font-size: 13px;
1258
+ color: var(--text-tertiary);
1259
+ padding-right: 4px;
1260
+ }
1261
+
1262
+ .asm-save-actions {
1263
+ display: flex;
1264
+ justify-content: flex-end;
1265
+ gap: 8px;
1266
+ padding: 12px 16px;
1267
+ background: var(--glass-bg-header);
1268
+ border-top: 1px solid var(--glass-border-subtle);
1269
+ }
1270
+
1271
+ .asm-save-cancel {
1272
+ background: var(--glass-bg);
1273
+ }
1274
+
1275
+ .asm-save-confirm {
1276
+ background: var(--accent-blue-bg);
1277
+ border-color: var(--accent-blue-border);
1278
+ color: var(--accent-blue);
1279
+ }
1280
+
1281
+ .asm-save-confirm:hover {
1282
+ background: var(--accent-blue-bg-strong);
1283
+ }
1284
+
1285
+ /* ═══════════════════════════════════════════════════════════════
1286
+ ROM ROUTINES PANEL - Reference panel for Apple II ROM calls
1287
+ ═══════════════════════════════════════════════════════════════ */
1288
+ .asm-rom-panel {
1289
+ position: absolute;
1290
+ top: 40px;
1291
+ right: 0;
1292
+ bottom: 24px;
1293
+ width: 320px;
1294
+ display: flex;
1295
+ flex-direction: column;
1296
+ background: var(--glass-bg-solid);
1297
+ border-left: 1px solid var(--glass-border);
1298
+ box-shadow: var(--shadow-lg);
1299
+ z-index: 100;
1300
+ }
1301
+
1302
+ .asm-rom-panel.hidden {
1303
+ display: none;
1304
+ }
1305
+
1306
+ .asm-rom-header {
1307
+ display: flex;
1308
+ align-items: center;
1309
+ justify-content: space-between;
1310
+ padding: 8px 12px;
1311
+ background: var(--glass-bg-header);
1312
+ border-bottom: 1px solid var(--glass-border-subtle);
1313
+ }
1314
+
1315
+ .asm-rom-title {
1316
+ font-family: var(--font-sans);
1317
+ font-size: 12px;
1318
+ font-weight: 600;
1319
+ color: var(--text-primary);
1320
+ }
1321
+
1322
+ .asm-rom-close {
1323
+ width: 20px;
1324
+ height: 20px;
1325
+ padding: 0;
1326
+ border: none;
1327
+ background: transparent;
1328
+ color: var(--text-tertiary);
1329
+ font-size: 16px;
1330
+ line-height: 1;
1331
+ cursor: pointer;
1332
+ border-radius: 3px;
1333
+ }
1334
+
1335
+ .asm-rom-close:hover {
1336
+ background: var(--glass-border);
1337
+ color: var(--text-primary);
1338
+ }
1339
+
1340
+ .asm-rom-search-bar {
1341
+ display: flex;
1342
+ gap: 8px;
1343
+ padding: 8px;
1344
+ background: var(--glass-bg);
1345
+ border-bottom: 1px solid var(--glass-border-subtle);
1346
+ }
1347
+
1348
+ .asm-rom-search {
1349
+ flex: 1;
1350
+ padding: 6px 10px;
1351
+ font-family: var(--font-mono);
1352
+ font-size: 11px;
1353
+ color: var(--text-primary);
1354
+ background: var(--editor-bg);
1355
+ border: 1px solid var(--glass-border);
1356
+ border-radius: 4px;
1357
+ outline: none;
1358
+ }
1359
+
1360
+ .asm-rom-search:focus {
1361
+ border-color: var(--accent-blue);
1362
+ box-shadow: 0 0 0 2px var(--accent-blue-bg);
1363
+ }
1364
+
1365
+ .asm-rom-category {
1366
+ padding: 4px 8px;
1367
+ font-family: var(--font-sans);
1368
+ font-size: 10px;
1369
+ color: var(--text-secondary);
1370
+ background: var(--glass-bg-header);
1371
+ border: 1px solid var(--glass-border);
1372
+ border-radius: 4px;
1373
+ cursor: pointer;
1374
+ }
1375
+
1376
+ .asm-rom-list {
1377
+ flex: 1;
1378
+ overflow-y: auto;
1379
+ padding: 4px;
1380
+ }
1381
+
1382
+ .asm-rom-empty {
1383
+ display: flex;
1384
+ flex-direction: column;
1385
+ align-items: center;
1386
+ justify-content: center;
1387
+ padding: 40px 20px;
1388
+ color: var(--text-tertiary);
1389
+ }
1390
+
1391
+ .asm-rom-empty-icon {
1392
+ font-size: 32px;
1393
+ margin-bottom: 8px;
1394
+ opacity: 0.5;
1395
+ }
1396
+
1397
+ .asm-rom-empty-text {
1398
+ font-size: 12px;
1399
+ }
1400
+
1401
+ .asm-rom-item {
1402
+ padding: 8px 10px;
1403
+ margin-bottom: 4px;
1404
+ background: var(--glass-bg);
1405
+ border: 1px solid transparent;
1406
+ border-radius: 4px;
1407
+ cursor: pointer;
1408
+ transition: all 0.15s ease;
1409
+ }
1410
+
1411
+ .asm-rom-item:hover {
1412
+ background: var(--glass-bg-header);
1413
+ border-color: var(--glass-border);
1414
+ }
1415
+
1416
+ .asm-rom-item-header {
1417
+ display: flex;
1418
+ align-items: center;
1419
+ justify-content: space-between;
1420
+ margin-bottom: 4px;
1421
+ }
1422
+
1423
+ .asm-rom-item-name {
1424
+ font-family: var(--font-mono);
1425
+ font-size: 12px;
1426
+ font-weight: 600;
1427
+ color: var(--accent-blue);
1428
+ }
1429
+
1430
+ .asm-rom-item-addr {
1431
+ font-family: var(--font-mono);
1432
+ font-size: 10px;
1433
+ color: var(--text-tertiary);
1434
+ }
1435
+
1436
+ .asm-rom-item-desc {
1437
+ font-family: var(--font-sans);
1438
+ font-size: 11px;
1439
+ color: var(--text-secondary);
1440
+ line-height: 1.4;
1441
+ margin-bottom: 4px;
1442
+ }
1443
+
1444
+ .asm-rom-item-cat {
1445
+ font-family: var(--font-sans);
1446
+ font-size: 9px;
1447
+ color: var(--text-tertiary);
1448
+ text-transform: uppercase;
1449
+ letter-spacing: 0.5px;
1450
+ }
1451
+
1452
+ /* Detail view */
1453
+ .asm-rom-detail {
1454
+ flex: 1;
1455
+ display: flex;
1456
+ flex-direction: column;
1457
+ overflow: hidden;
1458
+ }
1459
+
1460
+ .asm-rom-detail.hidden {
1461
+ display: none;
1462
+ }
1463
+
1464
+ .asm-rom-detail-header {
1465
+ display: flex;
1466
+ align-items: center;
1467
+ gap: 8px;
1468
+ padding: 8px 12px;
1469
+ background: var(--glass-bg);
1470
+ border-bottom: 1px solid var(--glass-border-subtle);
1471
+ }
1472
+
1473
+ .asm-rom-back {
1474
+ padding: 4px 8px;
1475
+ font-family: var(--font-sans);
1476
+ font-size: 10px;
1477
+ color: var(--text-secondary);
1478
+ background: var(--glass-bg-header);
1479
+ border: 1px solid var(--glass-border);
1480
+ border-radius: 3px;
1481
+ cursor: pointer;
1482
+ }
1483
+
1484
+ .asm-rom-back:hover {
1485
+ background: var(--glass-border);
1486
+ color: var(--text-primary);
1487
+ }
1488
+
1489
+ .asm-rom-detail-name {
1490
+ font-family: var(--font-mono);
1491
+ font-size: 12px;
1492
+ font-weight: 600;
1493
+ color: var(--accent-blue);
1494
+ }
1495
+
1496
+ .asm-rom-detail-content {
1497
+ flex: 1;
1498
+ overflow-y: auto;
1499
+ padding: 12px;
1500
+ }
1501
+
1502
+ .asm-rom-section {
1503
+ margin-bottom: 12px;
1504
+ }
1505
+
1506
+ .asm-rom-section-title {
1507
+ font-family: var(--font-sans);
1508
+ font-size: 9px;
1509
+ font-weight: 600;
1510
+ text-transform: uppercase;
1511
+ letter-spacing: 0.5px;
1512
+ color: var(--text-tertiary);
1513
+ margin-bottom: 4px;
1514
+ }
1515
+
1516
+ .asm-rom-section-content {
1517
+ font-family: var(--font-sans);
1518
+ font-size: 11px;
1519
+ color: var(--text-secondary);
1520
+ line-height: 1.5;
1521
+ }
1522
+
1523
+ .asm-rom-section-inline {
1524
+ display: flex;
1525
+ align-items: center;
1526
+ gap: 8px;
1527
+ }
1528
+
1529
+ .asm-rom-section-label {
1530
+ font-family: var(--font-sans);
1531
+ font-size: 10px;
1532
+ color: var(--text-tertiary);
1533
+ }
1534
+
1535
+ .asm-rom-param {
1536
+ display: flex;
1537
+ align-items: flex-start;
1538
+ gap: 8px;
1539
+ padding: 4px 0;
1540
+ }
1541
+
1542
+ .asm-rom-param-reg {
1543
+ flex-shrink: 0;
1544
+ min-width: 40px;
1545
+ font-family: var(--font-mono);
1546
+ font-size: 11px;
1547
+ font-weight: 600;
1548
+ color: var(--accent-orange);
1549
+ }
1550
+
1551
+ .asm-rom-param-desc {
1552
+ font-family: var(--font-sans);
1553
+ font-size: 11px;
1554
+ color: var(--text-secondary);
1555
+ }
1556
+
1557
+ .asm-rom-regs {
1558
+ font-family: var(--font-mono);
1559
+ font-size: 11px;
1560
+ color: var(--accent-green);
1561
+ }
1562
+
1563
+ .asm-rom-regs-warn {
1564
+ color: var(--accent-orange);
1565
+ }
1566
+
1567
+ .asm-rom-notes {
1568
+ font-style: italic;
1569
+ color: var(--text-tertiary);
1570
+ }
1571
+
1572
+ .asm-rom-example {
1573
+ margin: 4px 0 0 0;
1574
+ padding: 8px 10px;
1575
+ font-family: var(--font-mono);
1576
+ font-size: 10px;
1577
+ line-height: 1.4;
1578
+ color: var(--text-secondary);
1579
+ background: var(--editor-bg);
1580
+ border: 1px solid var(--glass-border-subtle);
1581
+ border-radius: 4px;
1582
+ overflow-x: auto;
1583
+ white-space: pre;
1584
+ }
1585
+
1586
+ .asm-rom-detail-actions {
1587
+ display: flex;
1588
+ gap: 8px;
1589
+ padding: 12px;
1590
+ background: var(--glass-bg-header);
1591
+ border-top: 1px solid var(--glass-border-subtle);
1592
+ }
1593
+
1594
+ .asm-rom-detail-actions .asm-btn {
1595
+ flex: 1;
1596
+ }
1597
+
1598
+ .asm-rom-insert-equ {
1599
+ background: var(--accent-purple-bg, rgba(150, 61, 151, 0.1));
1600
+ border-color: var(--accent-purple-border, rgba(150, 61, 151, 0.25));
1601
+ color: var(--accent-purple, #963D97);
1602
+ }
1603
+
1604
+ .asm-rom-insert-equ:hover {
1605
+ background: var(--accent-purple-bg-strong, rgba(150, 61, 151, 0.2));
1606
+ }
1607
+
1608
+ .asm-rom-insert-jsr {
1609
+ background: var(--accent-green-bg, rgba(97, 187, 70, 0.1));
1610
+ border-color: var(--accent-green-border, rgba(97, 187, 70, 0.25));
1611
+ color: var(--accent-green, #61BB46);
1612
+ }
1613
+
1614
+ .asm-rom-insert-jsr:hover {
1615
+ background: var(--accent-green-bg-strong, rgba(97, 187, 70, 0.2));
1616
+ }
1617
+