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,867 @@
1
+ /**
2
+ * File Explorer Window Styles
3
+ *
4
+ * Window chrome (container, header, title, close, resize handles,
5
+ * hidden/focused/dragging states) is inherited from BaseWindow via
6
+ * the debug-window classes in debug-windows.css.
7
+ * This file only contains file-explorer-specific content styles.
8
+ */
9
+
10
+ /* Override the BaseWindow content wrapper for file explorer layout:
11
+ remove default padding and overflow so the internal panels handle it */
12
+ #file-explorer-window > .debug-window-content {
13
+ padding: 0;
14
+ overflow: hidden;
15
+ display: flex;
16
+ flex-direction: column;
17
+ }
18
+
19
+ /* Toolbar */
20
+ .fe-toolbar {
21
+ display: flex;
22
+ align-items: center;
23
+ gap: 12px;
24
+ padding: 8px 12px;
25
+ background: var(--glass-border);
26
+ border-bottom: 1px solid var(--border-subtle);
27
+ flex-shrink: 0;
28
+ }
29
+
30
+ /* Source selector (Floppy / HD) */
31
+ .fe-source-selector {
32
+ display: flex;
33
+ gap: 2px;
34
+ background: var(--input-bg-deeper);
35
+ border-radius: var(--radius-sm);
36
+ padding: 2px;
37
+ }
38
+
39
+ .fe-source-selector.hidden {
40
+ display: none;
41
+ }
42
+
43
+ .fe-source-btn {
44
+ padding: 2px 8px;
45
+ border: none;
46
+ background: transparent;
47
+ color: var(--text-muted);
48
+ font-family: var(--font-sans);
49
+ font-size: 11px;
50
+ font-weight: 500;
51
+ cursor: pointer;
52
+ border-radius: var(--radius-sm);
53
+ transition:
54
+ background 0.15s,
55
+ color 0.15s;
56
+ }
57
+
58
+ .fe-source-btn:hover {
59
+ color: var(--text-primary);
60
+ background: var(--bg-light);
61
+ }
62
+
63
+ .fe-source-btn.active {
64
+ background: var(--accent-blue);
65
+ color: white;
66
+ }
67
+
68
+ .fe-drive-selector {
69
+ display: flex;
70
+ align-items: center;
71
+ gap: 6px;
72
+ }
73
+
74
+ .fe-drive-selector label {
75
+ font-family: var(--font-sans);
76
+ font-size: 11px;
77
+ color: var(--text-secondary);
78
+ }
79
+
80
+ .fe-drive-btn {
81
+ width: 24px;
82
+ height: 24px;
83
+ border: 1px solid var(--border-default);
84
+ background: var(--bg-primary);
85
+ color: var(--text-secondary);
86
+ font-family: var(--font-mono);
87
+ font-size: 11px;
88
+ cursor: pointer;
89
+ border-radius: var(--radius-sm);
90
+ }
91
+
92
+ .fe-drive-btn:hover {
93
+ border-color: var(--accent-blue);
94
+ color: var(--text-primary);
95
+ }
96
+
97
+ .fe-drive-btn.active {
98
+ background: var(--accent-blue);
99
+ border-color: var(--accent-blue);
100
+ color: white;
101
+ }
102
+
103
+ .fe-refresh-btn {
104
+ padding: 4px 10px;
105
+ border: 1px solid var(--border-default);
106
+ background: var(--bg-primary);
107
+ color: var(--text-secondary);
108
+ font-family: var(--font-sans);
109
+ font-size: 11px;
110
+ cursor: pointer;
111
+ border-radius: var(--radius-sm);
112
+ }
113
+
114
+ .fe-refresh-btn:hover {
115
+ border-color: var(--accent-blue);
116
+ color: var(--text-primary);
117
+ }
118
+
119
+ .fe-disk-info {
120
+ flex: 1;
121
+ font-family: var(--font-mono);
122
+ font-size: 11px;
123
+ color: var(--text-muted);
124
+ text-align: right;
125
+ overflow: hidden;
126
+ text-overflow: ellipsis;
127
+ white-space: nowrap;
128
+ }
129
+
130
+ /* Content area */
131
+ .fe-content {
132
+ flex: 1;
133
+ display: flex;
134
+ overflow: hidden;
135
+ min-height: 0;
136
+ }
137
+
138
+ /* Catalog panel */
139
+ .fe-catalog-panel {
140
+ width: 280px;
141
+ min-width: 200px;
142
+ border-right: 1px solid var(--border-subtle);
143
+ display: flex;
144
+ flex-direction: column;
145
+ overflow: hidden;
146
+ background: transparent;
147
+ }
148
+
149
+ .fe-panel-header {
150
+ padding: 6px 10px;
151
+ background: var(--glass-bg-header);
152
+ border-bottom: 1px solid var(--border-subtle);
153
+ font-family: var(--font-sans);
154
+ font-size: 10px;
155
+ font-weight: 600;
156
+ color: var(--text-secondary);
157
+ text-transform: uppercase;
158
+ letter-spacing: 0.5px;
159
+ display: flex;
160
+ align-items: center;
161
+ justify-content: space-between;
162
+ flex-shrink: 0;
163
+ }
164
+
165
+ .fe-catalog-list {
166
+ flex: 1;
167
+ overflow-y: auto;
168
+ font-family: var(--font-mono);
169
+ font-size: 12px;
170
+ background: var(--input-bg-dark);
171
+ }
172
+
173
+ .fe-catalog-item {
174
+ display: grid;
175
+ grid-template-columns: 28px 1fr 36px;
176
+ gap: 4px;
177
+ padding: 4px 8px;
178
+ cursor: pointer;
179
+ border-bottom: 1px solid var(--border-subtle);
180
+ }
181
+
182
+ .fe-catalog-item:hover {
183
+ background: var(--bg-light);
184
+ }
185
+
186
+ .fe-catalog-item.selected {
187
+ background: var(--accent-blue-bg);
188
+ border-color: var(--accent-blue);
189
+ }
190
+
191
+ .fe-file-type {
192
+ color: var(--accent-yellow);
193
+ text-align: center;
194
+ }
195
+
196
+ .fe-file-type.locked {
197
+ color: var(--accent-red);
198
+ }
199
+
200
+ .fe-file-name {
201
+ color: var(--text-primary);
202
+ overflow: hidden;
203
+ text-overflow: ellipsis;
204
+ white-space: nowrap;
205
+ }
206
+
207
+ .fe-file-sectors {
208
+ color: var(--text-muted);
209
+ text-align: right;
210
+ }
211
+
212
+ .fe-empty {
213
+ padding: 20px;
214
+ text-align: center;
215
+ color: var(--text-muted);
216
+ font-family: var(--font-sans);
217
+ font-size: 12px;
218
+ }
219
+
220
+ /* ProDOS Path Bar */
221
+ .fe-path-bar {
222
+ padding: 6px 10px;
223
+ background: var(--control-bg);
224
+ border-bottom: 1px solid var(--border-subtle);
225
+ font-family: var(--font-mono);
226
+ font-size: 11px;
227
+ color: var(--text-muted);
228
+ overflow: hidden;
229
+ text-overflow: ellipsis;
230
+ white-space: nowrap;
231
+ }
232
+
233
+ .fe-path-bar.hidden {
234
+ display: none;
235
+ }
236
+
237
+ .fe-path-item {
238
+ color: var(--accent-blue);
239
+ cursor: pointer;
240
+ }
241
+
242
+ .fe-path-item:hover {
243
+ text-decoration: underline;
244
+ }
245
+
246
+ .fe-path-item:last-child {
247
+ color: var(--text-primary);
248
+ cursor: default;
249
+ }
250
+
251
+ .fe-path-item:last-child:hover {
252
+ text-decoration: none;
253
+ }
254
+
255
+ /* ProDOS Directory entries */
256
+ .fe-catalog-item.fe-directory .fe-file-type {
257
+ color: var(--accent-blue);
258
+ }
259
+
260
+ .fe-catalog-item.fe-directory .fe-file-name {
261
+ color: var(--accent-blue);
262
+ }
263
+
264
+ .fe-catalog-item.fe-parent-dir {
265
+ background: var(--control-bg);
266
+ }
267
+
268
+ .fe-catalog-item.fe-parent-dir:hover {
269
+ background: var(--control-bg-hover);
270
+ }
271
+
272
+ /* File panel */
273
+ .fe-file-panel {
274
+ flex: 1;
275
+ display: flex;
276
+ flex-direction: column;
277
+ min-width: 0;
278
+ overflow: hidden;
279
+ background: transparent;
280
+ }
281
+
282
+ .fe-file-panel .fe-panel-header {
283
+ display: flex;
284
+ align-items: center;
285
+ gap: 12px;
286
+ }
287
+
288
+ .fe-file-title {
289
+ flex: 1;
290
+ font-family: var(--font-mono);
291
+ font-size: 11px;
292
+ font-weight: normal;
293
+ text-transform: none;
294
+ letter-spacing: normal;
295
+ color: var(--text-primary);
296
+ overflow: hidden;
297
+ text-overflow: ellipsis;
298
+ white-space: nowrap;
299
+ }
300
+
301
+ .fe-file-info {
302
+ font-family: var(--font-sans);
303
+ font-size: 10px;
304
+ font-weight: normal;
305
+ text-transform: none;
306
+ letter-spacing: normal;
307
+ color: var(--text-muted);
308
+ }
309
+
310
+ /* View toggle (ASM/HEX/MERLIN, TEXT/MERLIN) */
311
+ .fe-view-toggle,
312
+ .fe-text-view-toggle {
313
+ display: flex;
314
+ gap: 2px;
315
+ background: var(--input-bg-deeper);
316
+ border-radius: var(--radius-sm);
317
+ padding: 2px;
318
+ }
319
+
320
+ .fe-view-toggle.hidden,
321
+ .fe-text-view-toggle.hidden {
322
+ display: none;
323
+ }
324
+
325
+ .fe-view-btn {
326
+ padding: 2px 8px;
327
+ border: none;
328
+ background: transparent;
329
+ color: var(--text-muted);
330
+ font-family: var(--font-mono);
331
+ font-size: 10px;
332
+ font-weight: 500;
333
+ cursor: pointer;
334
+ border-radius: var(--radius-sm);
335
+ transition:
336
+ background 0.15s,
337
+ color 0.15s;
338
+ }
339
+
340
+ .fe-view-btn:hover {
341
+ color: var(--text-primary);
342
+ background: var(--bg-light);
343
+ }
344
+
345
+ .fe-view-btn.active {
346
+ background: var(--accent-blue);
347
+ color: white;
348
+ }
349
+
350
+ .fe-experimental {
351
+ margin-left: 4px;
352
+ padding: 1px 4px;
353
+ font-size: 8px;
354
+ font-weight: 600;
355
+ text-transform: uppercase;
356
+ background: var(--accent-orange, #f0883e);
357
+ color: #000;
358
+ border-radius: 3px;
359
+ vertical-align: middle;
360
+ }
361
+
362
+ /* ASM Legend */
363
+ .fe-asm-legend {
364
+ display: flex;
365
+ flex-wrap: wrap;
366
+ gap: 8px 16px;
367
+ padding: 6px 10px;
368
+ background: var(--input-bg);
369
+ border-bottom: 1px solid var(--border-subtle);
370
+ font-family: var(--font-mono);
371
+ font-size: 10px;
372
+ flex-shrink: 0;
373
+ }
374
+
375
+ .fe-asm-legend.hidden {
376
+ display: none;
377
+ }
378
+
379
+ .fe-asm-legend span {
380
+ display: inline-flex;
381
+ align-items: center;
382
+ }
383
+
384
+ .fe-asm-legend span::before {
385
+ content: "";
386
+ display: inline-block;
387
+ width: 8px;
388
+ height: 8px;
389
+ border-radius: 2px;
390
+ margin-right: 4px;
391
+ }
392
+
393
+ .fe-asm-legend .dis-branch::before {
394
+ background: var(--syntax-flow);
395
+ }
396
+
397
+ .fe-asm-legend .dis-load::before {
398
+ background: var(--syntax-load);
399
+ }
400
+
401
+ .fe-asm-legend .dis-math::before {
402
+ background: var(--syntax-math);
403
+ }
404
+
405
+ .fe-asm-legend .dis-stack::before {
406
+ background: var(--syntax-stack);
407
+ }
408
+
409
+ .fe-asm-legend .dis-address::before {
410
+ background: var(--syntax-math);
411
+ }
412
+
413
+ .fe-asm-legend .dis-immediate::before {
414
+ background: var(--syntax-flag);
415
+ }
416
+
417
+ .fe-asm-legend .dis-comment::before {
418
+ background: var(--syntax-comment);
419
+ }
420
+
421
+ .fe-asm-legend .dis-data::before {
422
+ background: var(--syntax-data);
423
+ }
424
+
425
+ /* Hex dump legend */
426
+ .fe-hex-legend {
427
+ display: flex;
428
+ flex-wrap: wrap;
429
+ gap: 8px 16px;
430
+ padding: 6px 10px;
431
+ background: var(--input-bg);
432
+ border-bottom: 1px solid var(--border-subtle);
433
+ font-family: var(--font-mono);
434
+ font-size: 10px;
435
+ flex-shrink: 0;
436
+ }
437
+
438
+ .fe-hex-legend.hidden {
439
+ display: none;
440
+ }
441
+
442
+ .fe-hex-legend span {
443
+ display: inline-flex;
444
+ align-items: center;
445
+ }
446
+
447
+ .fe-hex-legend span::before {
448
+ content: "";
449
+ display: inline-block;
450
+ width: 8px;
451
+ height: 8px;
452
+ border-radius: 2px;
453
+ margin-right: 4px;
454
+ }
455
+
456
+ .fe-hex-legend .hex-legend-printable::before {
457
+ background: var(--syntax-hex-printable);
458
+ }
459
+
460
+ .fe-hex-legend .hex-legend-control::before {
461
+ background: var(--syntax-hex-byte);
462
+ }
463
+
464
+ .fe-hex-legend .hex-legend-highbit::before {
465
+ background: var(--syntax-hex-highbit);
466
+ }
467
+
468
+ .fe-hex-legend .hex-legend-zero::before {
469
+ background: var(--syntax-hex-zero);
470
+ }
471
+
472
+ .fe-file-content {
473
+ flex: 1;
474
+ overflow: auto;
475
+ padding: 8px;
476
+ background: var(--input-bg-dark);
477
+ /* Isolate layout calculations to improve resize performance */
478
+ contain: strict;
479
+ }
480
+
481
+ /* Virtual scroll container for large disassemblies */
482
+ .fe-file-content .virtual-scroll-container {
483
+ contain: strict;
484
+ }
485
+
486
+ .fe-file-content .virtual-scroll-content {
487
+ color: var(--text-primary);
488
+ }
489
+
490
+ .fe-file-content pre {
491
+ margin: 0;
492
+ font-family: var(--font-mono);
493
+ font-size: 11px;
494
+ line-height: 1.5;
495
+ color: var(--text-primary);
496
+ white-space: pre-wrap;
497
+ word-break: break-all;
498
+ }
499
+
500
+ /* Hex dump styling */
501
+ .fe-file-content.hex pre {
502
+ color: var(--text-primary);
503
+ white-space: pre;
504
+ line-height: 1;
505
+ }
506
+
507
+ .hex-line {
508
+ display: flex;
509
+ align-items: baseline;
510
+ padding: 1px 0;
511
+ }
512
+
513
+ .hex-line:hover {
514
+ background: var(--overlay-faint);
515
+ }
516
+
517
+ .hex-addr {
518
+ color: var(--syntax-addr);
519
+ font-weight: 500;
520
+ flex-shrink: 0;
521
+ }
522
+
523
+ .hex-separator {
524
+ color: var(--syntax-separator);
525
+ flex-shrink: 0;
526
+ margin-right: 0.5em;
527
+ }
528
+
529
+ .hex-byte {
530
+ color: var(--syntax-hex-byte);
531
+ }
532
+
533
+ .hex-byte.hex-zero {
534
+ color: var(--syntax-hex-zero);
535
+ }
536
+
537
+ .hex-byte.hex-printable {
538
+ color: var(--syntax-hex-printable);
539
+ }
540
+
541
+ .hex-byte.hex-highbit {
542
+ color: var(--syntax-hex-highbit);
543
+ }
544
+
545
+ .hex-bytes {
546
+ flex: 1;
547
+ min-width: 0;
548
+ white-space: nowrap;
549
+ }
550
+
551
+ .hex-group-gap {
552
+ display: inline-block;
553
+ width: 0.75em;
554
+ }
555
+
556
+ .hex-ascii-separator {
557
+ color: var(--syntax-ascii-separator);
558
+ flex-shrink: 0;
559
+ margin: 0 0.4em;
560
+ }
561
+
562
+ .hex-ascii {
563
+ letter-spacing: 0;
564
+ flex-shrink: 0;
565
+ white-space: pre;
566
+ }
567
+
568
+ .hex-ascii-printable {
569
+ color: var(--syntax-ascii-printable);
570
+ }
571
+
572
+ .hex-ascii-dot {
573
+ color: var(--syntax-ascii-dot);
574
+ }
575
+
576
+ .hex-truncated {
577
+ color: var(--syntax-addr);
578
+ font-style: italic;
579
+ margin-top: 8px;
580
+ display: block;
581
+ }
582
+
583
+ /* Disassembler syntax highlighting */
584
+ .fe-file-content.asm pre {
585
+ color: var(--text-primary);
586
+ white-space: pre;
587
+ }
588
+
589
+ .dis-addr {
590
+ color: var(--text-muted, #6e7681);
591
+ }
592
+
593
+ .dis-bytes {
594
+ color: var(--accent-blue);
595
+ }
596
+
597
+ .dis-branch {
598
+ color: var(--syntax-flow);
599
+ font-weight: 500;
600
+ }
601
+
602
+ .dis-load {
603
+ color: var(--syntax-load);
604
+ font-weight: 500;
605
+ }
606
+
607
+ .dis-math {
608
+ color: var(--syntax-math);
609
+ font-weight: 500;
610
+ }
611
+
612
+ .dis-stack {
613
+ color: var(--syntax-stack);
614
+ font-weight: 500;
615
+ }
616
+
617
+ .dis-flag {
618
+ color: var(--syntax-flag);
619
+ font-weight: 500;
620
+ }
621
+
622
+ .dis-mnemonic {
623
+ color: var(--text-primary);
624
+ font-weight: 500;
625
+ }
626
+
627
+ .dis-directive {
628
+ color: var(--syntax-stack);
629
+ }
630
+
631
+ .dis-data {
632
+ color: var(--syntax-data);
633
+ }
634
+
635
+ .dis-immediate {
636
+ color: var(--syntax-flag);
637
+ }
638
+
639
+ .dis-address {
640
+ color: var(--syntax-math);
641
+ }
642
+
643
+ .dis-target {
644
+ color: var(--syntax-flow);
645
+ }
646
+
647
+ .dis-clickable {
648
+ cursor: pointer;
649
+ text-decoration: underline;
650
+ text-decoration-style: dotted;
651
+ text-underline-offset: 2px;
652
+ }
653
+
654
+ .dis-clickable:hover {
655
+ text-decoration-style: solid;
656
+ filter: brightness(1.2);
657
+ }
658
+
659
+ .dis-highlight {
660
+ background: var(--accent-blue-bg-strong);
661
+ display: inline-block;
662
+ width: 100%;
663
+ margin: 0 -8px;
664
+ padding: 0 8px;
665
+ }
666
+
667
+ .dis-register {
668
+ color: var(--syntax-register);
669
+ }
670
+
671
+ .dis-punct {
672
+ color: var(--text-muted, #6e7681);
673
+ }
674
+
675
+ .dis-comment {
676
+ color: var(--syntax-comment);
677
+ font-style: italic;
678
+ }
679
+
680
+ .dis-number {
681
+ color: var(--syntax-number);
682
+ }
683
+
684
+ .dis-unknown {
685
+ color: var(--accent-red);
686
+ }
687
+
688
+ /* BASIC syntax highlighting */
689
+ .fe-file-content.basic pre {
690
+ color: var(--text-primary);
691
+ white-space: pre;
692
+ }
693
+
694
+ .bas-linenum {
695
+ color: var(--text-muted, #6e7681);
696
+ }
697
+
698
+ /* All keywords/commands - same color */
699
+ .bas-flow,
700
+ .bas-loop,
701
+ .bas-io,
702
+ .bas-graphics,
703
+ .bas-memory,
704
+ .bas-func,
705
+ .bas-var,
706
+ .bas-misc,
707
+ .bas-keyword {
708
+ color: var(--syntax-keyword);
709
+ font-weight: 500;
710
+ }
711
+
712
+ .bas-variable {
713
+ color: var(--text-primary); /* White for variables */
714
+ }
715
+
716
+ .bas-string {
717
+ color: var(--syntax-string);
718
+ }
719
+
720
+ .bas-number {
721
+ color: var(--syntax-math);
722
+ }
723
+
724
+ .bas-comment {
725
+ color: var(--syntax-comment);
726
+ font-style: italic;
727
+ }
728
+
729
+ .bas-data {
730
+ color: var(--syntax-string);
731
+ }
732
+
733
+ .bas-operator {
734
+ color: var(--syntax-operator);
735
+ }
736
+
737
+ .bas-punct {
738
+ color: var(--syntax-operator);
739
+ }
740
+
741
+ .bas-lineref {
742
+ cursor: pointer;
743
+ text-decoration: underline;
744
+ text-decoration-style: dotted;
745
+ text-underline-offset: 2px;
746
+ }
747
+
748
+ .bas-lineref:hover {
749
+ text-decoration-style: solid;
750
+ filter: brightness(1.2);
751
+ }
752
+
753
+ .bas-highlight {
754
+ background: var(--accent-blue-bg-strong);
755
+ display: inline-block;
756
+ width: 100%;
757
+ margin: 0 -8px;
758
+ padding: 0 8px;
759
+ }
760
+
761
+ .fe-file-content.text pre {
762
+ color: var(--text-primary);
763
+ }
764
+
765
+ .fe-file-content .fe-error {
766
+ color: var(--accent-red);
767
+ padding: 20px;
768
+ text-align: center;
769
+ }
770
+
771
+ /* Merlin assembler source view */
772
+ .fe-file-content.merlin pre {
773
+ color: var(--text-primary);
774
+ white-space: pre;
775
+ }
776
+
777
+ /* Each source line is a flex row with fixed-width columns */
778
+ .mer-line {
779
+ display: flex;
780
+ align-items: baseline;
781
+ }
782
+
783
+ .mer-line:hover {
784
+ background: var(--overlay-faint);
785
+ }
786
+
787
+ .mer-col {
788
+ flex-shrink: 0;
789
+ white-space: pre;
790
+ }
791
+
792
+ .mer-col-label {
793
+ min-width: 13ch;
794
+ width: 13ch;
795
+ }
796
+
797
+ .mer-col-opcode {
798
+ min-width: 7ch;
799
+ width: 7ch;
800
+ }
801
+
802
+ .mer-col-operand {
803
+ min-width: 20ch;
804
+ width: 20ch;
805
+ }
806
+
807
+ .mer-col-comment {
808
+ flex: 1;
809
+ min-width: 0;
810
+ }
811
+
812
+ /* Full-line comments span the entire row */
813
+ .mer-comment-line {
814
+ display: flex;
815
+ }
816
+
817
+ .mer-comment-line .mer-comment {
818
+ flex: 1;
819
+ }
820
+
821
+ /* Label colours */
822
+ .mer-label { color: var(--syntax-flow); }
823
+ .mer-local { color: var(--syntax-math); }
824
+
825
+ /* Mnemonic categories - matching disassembler colour scheme */
826
+ .mer-branch { color: var(--syntax-flow); font-weight: 500; }
827
+ .mer-load { color: var(--syntax-load); font-weight: 500; }
828
+ .mer-math { color: var(--syntax-math); font-weight: 500; }
829
+ .mer-stack { color: var(--syntax-stack); font-weight: 500; }
830
+ .mer-flag { color: var(--syntax-flag); font-weight: 500; }
831
+ .mer-macro { color: var(--text-primary); font-weight: 500; }
832
+
833
+ /* Directives */
834
+ .mer-directive { color: var(--syntax-keyword); font-weight: 500; }
835
+
836
+ /* Operand sub-tokens */
837
+ .mer-number { color: var(--syntax-number); }
838
+ .mer-string { color: var(--syntax-string); }
839
+ .mer-immediate { color: var(--syntax-flag); }
840
+ .mer-symbol { color: var(--text-primary); }
841
+ .mer-punct { color: var(--text-muted); }
842
+
843
+ /* Comments */
844
+ .mer-comment { color: var(--syntax-comment); font-style: italic; }
845
+
846
+ /* Scrollbar styling */
847
+ .fe-catalog-list::-webkit-scrollbar,
848
+ .fe-file-content::-webkit-scrollbar {
849
+ width: 8px;
850
+ height: 8px;
851
+ }
852
+
853
+ .fe-catalog-list::-webkit-scrollbar-track,
854
+ .fe-file-content::-webkit-scrollbar-track {
855
+ background: var(--bg-primary);
856
+ }
857
+
858
+ .fe-catalog-list::-webkit-scrollbar-thumb,
859
+ .fe-file-content::-webkit-scrollbar-thumb {
860
+ background: var(--border-default);
861
+ border-radius: 4px;
862
+ }
863
+
864
+ .fe-catalog-list::-webkit-scrollbar-thumb:hover,
865
+ .fe-file-content::-webkit-scrollbar-thumb:hover {
866
+ background: var(--border-muted);
867
+ }