sourcemonkey 0.0.0-stage → 0.5.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 (367) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +87 -2
  3. package/dist/bytes.js +37 -0
  4. package/dist/channel-placeholder.js +5 -0
  5. package/dist/collection-scan.js +17 -0
  6. package/dist/collections.html +353 -0
  7. package/dist/compare.html +358 -0
  8. package/dist/composed-source.js +205 -0
  9. package/dist/connect-prompt.html +47 -0
  10. package/dist/debug/icons.html +211 -0
  11. package/dist/debug/storage.html +163 -0
  12. package/dist/debug-log.js +75 -0
  13. package/dist/diagnostic-location.js +64 -0
  14. package/dist/eval-hook.js +308 -0
  15. package/dist/extension/background.js +5263 -0
  16. package/dist/extension/channel.js +133 -0
  17. package/dist/extension/code-links.js +187 -0
  18. package/dist/extension/code-tabs.js +460 -0
  19. package/dist/extension/collection-dialog.js +619 -0
  20. package/dist/extension/collection-display.js +322 -0
  21. package/dist/extension/collections.js +2905 -0
  22. package/dist/extension/compare.js +867 -0
  23. package/dist/extension/concurrency.js +186 -0
  24. package/dist/extension/connect-grants.js +109 -0
  25. package/dist/extension/connect-prompt-page.js +70 -0
  26. package/dist/extension/connect-prompt.js +266 -0
  27. package/dist/extension/copy-button.js +63 -0
  28. package/dist/extension/copy-dialog.js +502 -0
  29. package/dist/extension/copy-preference.js +66 -0
  30. package/dist/extension/debug/icons.js +203 -0
  31. package/dist/extension/debug/storage.js +365 -0
  32. package/dist/extension/deep-link.js +77 -0
  33. package/dist/extension/delete-dialog.js +432 -0
  34. package/dist/extension/delete-icon.js +40 -0
  35. package/dist/extension/details-tooltips.js +66 -0
  36. package/dist/extension/directories.js +679 -0
  37. package/dist/extension/export-backup.js +407 -0
  38. package/dist/extension/export-dialog.js +142 -0
  39. package/dist/extension/file-access.js +74 -0
  40. package/dist/extension/file-changes.js +346 -0
  41. package/dist/extension/frame-info.js +85 -0
  42. package/dist/extension/github-provider.js +336 -0
  43. package/dist/extension/glyph.js +84 -0
  44. package/dist/extension/gm-bindings.js +601 -0
  45. package/dist/extension/gm-download.js +419 -0
  46. package/dist/extension/gm-menu.js +228 -0
  47. package/dist/extension/gm-notification.js +141 -0
  48. package/dist/extension/gm-originator-map.js +23 -0
  49. package/dist/extension/gm-tab-data.js +121 -0
  50. package/dist/extension/gm-tab.js +160 -0
  51. package/dist/extension/gm-url-change.js +111 -0
  52. package/dist/extension/gm-url-scheme.js +27 -0
  53. package/dist/extension/gm-values.js +176 -0
  54. package/dist/extension/gm-window-control.js +104 -0
  55. package/dist/extension/gm-xhr-headers.js +333 -0
  56. package/dist/extension/gm-xhr.js +584 -0
  57. package/dist/extension/injector.js +3145 -0
  58. package/dist/extension/install-capture.js +277 -0
  59. package/dist/extension/line-diff.js +233 -0
  60. package/dist/extension/local-copy.js +560 -0
  61. package/dist/extension/local-delete.js +276 -0
  62. package/dist/extension/location-kinds.js +108 -0
  63. package/dist/extension/log-format.js +158 -0
  64. package/dist/extension/managed-changes.js +361 -0
  65. package/dist/extension/managed-items.js +57 -0
  66. package/dist/extension/match-index.js +375 -0
  67. package/dist/extension/missing-scripts.js +66 -0
  68. package/dist/extension/more-menu.js +109 -0
  69. package/dist/extension/move-dialog.js +197 -0
  70. package/dist/extension/offscreen.js +37 -0
  71. package/dist/extension/options.js +504 -0
  72. package/dist/extension/page-heading.js +170 -0
  73. package/dist/extension/page-links.js +199 -0
  74. package/dist/extension/parse-check-client.js +70 -0
  75. package/dist/extension/parse-check.js +161 -0
  76. package/dist/extension/parse-sandbox-host.js +172 -0
  77. package/dist/extension/parse-sandbox.js +175 -0
  78. package/dist/extension/popup-commands-open.js +41 -0
  79. package/dist/extension/popup-view.js +387 -0
  80. package/dist/extension/popup.js +703 -0
  81. package/dist/extension/prism-userscript.js +53 -0
  82. package/dist/extension/refresh-error.js +136 -0
  83. package/dist/extension/refresh-targets.js +160 -0
  84. package/dist/extension/related-versions.js +1144 -0
  85. package/dist/extension/resize-observer-loop.js +19 -0
  86. package/dist/extension/row-cache.js +387 -0
  87. package/dist/extension/script-blobs.js +413 -0
  88. package/dist/extension/script-details.js +658 -0
  89. package/dist/extension/script-enablement.js +285 -0
  90. package/dist/extension/script-identity.js +310 -0
  91. package/dist/extension/script-keys.js +54 -0
  92. package/dist/extension/script-log-id.js +155 -0
  93. package/dist/extension/script-log.js +290 -0
  94. package/dist/extension/script-rejection.js +104 -0
  95. package/dist/extension/script-sites.js +158 -0
  96. package/dist/extension/script-store.js +3507 -0
  97. package/dist/extension/script-updater.js +991 -0
  98. package/dist/extension/script-url-hash.js +61 -0
  99. package/dist/extension/select-all.js +37 -0
  100. package/dist/extension/select-open-guard.js +90 -0
  101. package/dist/extension/site-icon.js +1261 -0
  102. package/dist/extension/sm-dev-link.js +302 -0
  103. package/dist/extension/solo-click.js +58 -0
  104. package/dist/extension/sticky-numbers.js +188 -0
  105. package/dist/extension/storage-breakdown.js +253 -0
  106. package/dist/extension/storage-scan.js +86 -0
  107. package/dist/extension/storage-usage.js +194 -0
  108. package/dist/extension/structural-keys.js +29 -0
  109. package/dist/extension/sw-teardown.js +36 -0
  110. package/dist/extension/tab-status.js +403 -0
  111. package/dist/extension/toolbar-summary.js +105 -0
  112. package/dist/extension/user-scripts-access.js +43 -0
  113. package/dist/extension/userscript.js +3672 -0
  114. package/dist/extension/value-store.js +204 -0
  115. package/dist/extension/version-probe-fetch.js +68 -0
  116. package/dist/extension/worker-client.js +109 -0
  117. package/dist/extension/worker-ops.js +171 -0
  118. package/dist/extension/zip-writer.js +24 -0
  119. package/dist/external-files.js +878 -0
  120. package/dist/file-loader.js +436 -0
  121. package/dist/file-locations.js +439 -0
  122. package/dist/generated-wrappers.js +5 -0
  123. package/dist/github-auth.js +148 -0
  124. package/dist/github-urls.js +46 -0
  125. package/dist/gm-api-catalog.js +217 -0
  126. package/dist/gm-connect.js +273 -0
  127. package/dist/gm-xhr-types.js +5 -0
  128. package/dist/http-read.js +142 -0
  129. package/dist/icons/icon-128.png +0 -0
  130. package/dist/icons/icon-16.png +0 -0
  131. package/dist/icons/icon-48.png +0 -0
  132. package/dist/local-file-overrides.js +558 -0
  133. package/dist/manifest.json +38 -0
  134. package/dist/markup-response.js +126 -0
  135. package/dist/match-targets.js +305 -0
  136. package/dist/menu-captions.js +22 -0
  137. package/dist/offscreen.html +39 -0
  138. package/dist/options.html +197 -0
  139. package/dist/parse-check-protocol.js +51 -0
  140. package/dist/parse-location.js +171 -0
  141. package/dist/parse-sandbox.html +56 -0
  142. package/dist/phase-timing.js +155 -0
  143. package/dist/popup.html +197 -0
  144. package/dist/public-suffixes.js +6957 -0
  145. package/dist/run-context.js +31 -0
  146. package/dist/runtime-messages.js +34 -0
  147. package/dist/sandboxed-page.js +35 -0
  148. package/dist/script-build.js +787 -0
  149. package/dist/script-display.js +383 -0
  150. package/dist/script-icon.js +43 -0
  151. package/dist/script-links.js +204 -0
  152. package/dist/script-source-url.js +214 -0
  153. package/dist/script-world.js +65 -0
  154. package/dist/sm-dev-protocol.js +84 -0
  155. package/dist/source-map.js +177 -0
  156. package/dist/stack-link.js +138 -0
  157. package/dist/styles.css +825 -0
  158. package/dist/unsafe-window-use.js +229 -0
  159. package/dist/url-match.js +734 -0
  160. package/dist/userscript-header.js +248 -0
  161. package/dist/userscript.html +1165 -0
  162. package/dist/vendor/fflate.LICENSE +21 -0
  163. package/dist/vendor/fflate.js +2692 -0
  164. package/dist/vendor/prism/prism-line-numbers.css +1 -0
  165. package/dist/vendor/prism/prism-line-numbers.js +1 -0
  166. package/dist/vendor/prism/prism.css +1 -0
  167. package/dist/vendor/prism/prism.js +1946 -0
  168. package/dist/version-compare.js +141 -0
  169. package/dist/version-probe.js +120 -0
  170. package/lib/build-info.json +1 -0
  171. package/lib/bytes.d.ts +3 -0
  172. package/lib/bytes.js +37 -0
  173. package/lib/channel-placeholder.d.ts +1 -0
  174. package/lib/channel-placeholder.js +5 -0
  175. package/lib/collection-scan.d.ts +8 -0
  176. package/lib/collection-scan.js +17 -0
  177. package/lib/composed-source.d.ts +28 -0
  178. package/lib/composed-source.js +205 -0
  179. package/lib/debug-log.d.ts +9 -0
  180. package/lib/debug-log.js +75 -0
  181. package/lib/diagnostic-location.d.ts +8 -0
  182. package/lib/diagnostic-location.js +64 -0
  183. package/lib/eval-hook.d.ts +34 -0
  184. package/lib/eval-hook.js +308 -0
  185. package/lib/external-files.d.ts +111 -0
  186. package/lib/external-files.js +878 -0
  187. package/lib/file-loader.d.ts +48 -0
  188. package/lib/file-loader.js +436 -0
  189. package/lib/file-locations.d.ts +44 -0
  190. package/lib/file-locations.js +439 -0
  191. package/lib/generated-wrappers.d.ts +11 -0
  192. package/lib/generated-wrappers.js +5 -0
  193. package/lib/github-auth.d.ts +12 -0
  194. package/lib/github-auth.js +148 -0
  195. package/lib/github-urls.d.ts +1 -0
  196. package/lib/github-urls.js +46 -0
  197. package/lib/gm-api-catalog.d.ts +24 -0
  198. package/lib/gm-api-catalog.js +217 -0
  199. package/lib/gm-connect.d.ts +34 -0
  200. package/lib/gm-connect.js +273 -0
  201. package/lib/gm-xhr-types.d.ts +68 -0
  202. package/lib/gm-xhr-types.js +5 -0
  203. package/lib/harness/browser-extensions.d.ts +73 -0
  204. package/lib/harness/browser-extensions.js +285 -0
  205. package/lib/harness/browser-lang.d.ts +20 -0
  206. package/lib/harness/browser-lang.js +86 -0
  207. package/lib/harness/browser-launch.d.ts +14 -0
  208. package/lib/harness/browser-launch.js +184 -0
  209. package/lib/harness/checks.d.ts +110 -0
  210. package/lib/harness/checks.js +321 -0
  211. package/lib/harness/cli.d.ts +2 -0
  212. package/lib/harness/cli.js +2259 -0
  213. package/lib/harness/command-args.d.ts +91 -0
  214. package/lib/harness/command-args.js +369 -0
  215. package/lib/harness/command-lines.d.ts +80 -0
  216. package/lib/harness/command-lines.js +180 -0
  217. package/lib/harness/command-list.d.ts +206 -0
  218. package/lib/harness/command-list.js +1475 -0
  219. package/lib/harness/console-commands.d.ts +463 -0
  220. package/lib/harness/console-commands.js +3216 -0
  221. package/lib/harness/download-watch.d.ts +21 -0
  222. package/lib/harness/download-watch.js +156 -0
  223. package/lib/harness/extension-backend.d.ts +41 -0
  224. package/lib/harness/extension-backend.js +100 -0
  225. package/lib/harness/extension-host.d.ts +112 -0
  226. package/lib/harness/extension-host.js +552 -0
  227. package/lib/harness/extension-launch.d.ts +67 -0
  228. package/lib/harness/extension-launch.js +285 -0
  229. package/lib/harness/extension-link.d.ts +315 -0
  230. package/lib/harness/extension-link.js +607 -0
  231. package/lib/harness/external-manager.d.ts +146 -0
  232. package/lib/harness/external-manager.js +414 -0
  233. package/lib/harness/fixture.d.ts +165 -0
  234. package/lib/harness/fixture.js +461 -0
  235. package/lib/harness/frame-sessions.d.ts +71 -0
  236. package/lib/harness/frame-sessions.js +248 -0
  237. package/lib/harness/frames.d.ts +68 -0
  238. package/lib/harness/frames.js +216 -0
  239. package/lib/harness/help-format.d.ts +17 -0
  240. package/lib/harness/help-format.js +127 -0
  241. package/lib/harness/host.d.ts +352 -0
  242. package/lib/harness/host.js +423 -0
  243. package/lib/harness/index.d.ts +8 -0
  244. package/lib/harness/index.js +10 -0
  245. package/lib/harness/input-file.d.ts +18 -0
  246. package/lib/harness/input-file.js +61 -0
  247. package/lib/harness/json-output.d.ts +565 -0
  248. package/lib/harness/json-output.js +71 -0
  249. package/lib/harness/manager-actions.d.ts +21 -0
  250. package/lib/harness/manager-actions.js +129 -0
  251. package/lib/harness/manager-commands.d.ts +142 -0
  252. package/lib/harness/manager-commands.js +1196 -0
  253. package/lib/harness/manager-fetch.d.ts +33 -0
  254. package/lib/harness/manager-fetch.js +239 -0
  255. package/lib/harness/managers.d.ts +24 -0
  256. package/lib/harness/managers.js +27 -0
  257. package/lib/harness/output-style.d.ts +125 -0
  258. package/lib/harness/output-style.js +322 -0
  259. package/lib/harness/page-commands.d.ts +134 -0
  260. package/lib/harness/page-commands.js +1141 -0
  261. package/lib/harness/page-output.d.ts +67 -0
  262. package/lib/harness/page-output.js +139 -0
  263. package/lib/harness/page-watch.d.ts +171 -0
  264. package/lib/harness/page-watch.js +607 -0
  265. package/lib/harness/parse-check-node.d.ts +3 -0
  266. package/lib/harness/parse-check-node.js +132 -0
  267. package/lib/harness/path-args.d.ts +22 -0
  268. package/lib/harness/path-args.js +148 -0
  269. package/lib/harness/playwright-chromium.d.ts +16 -0
  270. package/lib/harness/playwright-chromium.js +86 -0
  271. package/lib/harness/prepare.d.ts +168 -0
  272. package/lib/harness/prepare.js +364 -0
  273. package/lib/harness/prompt-editor.d.ts +17 -0
  274. package/lib/harness/prompt-editor.js +354 -0
  275. package/lib/harness/prompt-history.d.ts +13 -0
  276. package/lib/harness/prompt-history.js +89 -0
  277. package/lib/harness/rebuild-advice.d.ts +6 -0
  278. package/lib/harness/rebuild-advice.js +39 -0
  279. package/lib/harness/run-log.d.ts +47 -0
  280. package/lib/harness/run-log.js +140 -0
  281. package/lib/harness/run-logs.d.ts +132 -0
  282. package/lib/harness/run-logs.js +241 -0
  283. package/lib/harness/run.d.ts +194 -0
  284. package/lib/harness/run.js +1973 -0
  285. package/lib/harness/runs.d.ts +229 -0
  286. package/lib/harness/runs.js +726 -0
  287. package/lib/harness/save-html.d.ts +39 -0
  288. package/lib/harness/save-html.js +89 -0
  289. package/lib/harness/saved-pages.d.ts +120 -0
  290. package/lib/harness/saved-pages.js +275 -0
  291. package/lib/harness/script-mark.d.ts +17 -0
  292. package/lib/harness/script-mark.js +56 -0
  293. package/lib/harness/snapshot.d.ts +143 -0
  294. package/lib/harness/snapshot.js +474 -0
  295. package/lib/harness/stuck-tabs.d.ts +19 -0
  296. package/lib/harness/stuck-tabs.js +131 -0
  297. package/lib/harness/tab-refs.d.ts +20 -0
  298. package/lib/harness/tab-refs.js +80 -0
  299. package/lib/harness/tampermonkey.d.ts +71 -0
  300. package/lib/harness/tampermonkey.js +356 -0
  301. package/lib/harness/tm-ids.d.ts +18 -0
  302. package/lib/harness/tm-ids.js +88 -0
  303. package/lib/harness/violentmonkey.d.ts +34 -0
  304. package/lib/harness/violentmonkey.js +162 -0
  305. package/lib/harness/wait.d.ts +77 -0
  306. package/lib/harness/wait.js +458 -0
  307. package/lib/http-read.d.ts +30 -0
  308. package/lib/http-read.js +142 -0
  309. package/lib/local-file-overrides.d.ts +35 -0
  310. package/lib/local-file-overrides.js +558 -0
  311. package/lib/manifest.json +38 -0
  312. package/lib/markup-response.d.ts +11 -0
  313. package/lib/markup-response.js +126 -0
  314. package/lib/match-targets.d.ts +18 -0
  315. package/lib/match-targets.js +305 -0
  316. package/lib/menu-captions.d.ts +1 -0
  317. package/lib/menu-captions.js +22 -0
  318. package/lib/parse-check-protocol.d.ts +27 -0
  319. package/lib/parse-check-protocol.js +51 -0
  320. package/lib/parse-location.d.ts +12 -0
  321. package/lib/parse-location.js +171 -0
  322. package/lib/phase-timing.d.ts +12 -0
  323. package/lib/phase-timing.js +155 -0
  324. package/lib/public-suffixes.d.ts +1 -0
  325. package/lib/public-suffixes.js +6957 -0
  326. package/lib/run-context.d.ts +2 -0
  327. package/lib/run-context.js +31 -0
  328. package/lib/runtime-messages.d.ts +10 -0
  329. package/lib/runtime-messages.js +34 -0
  330. package/lib/sandboxed-page.d.ts +5 -0
  331. package/lib/sandboxed-page.js +35 -0
  332. package/lib/script-build.d.ts +111 -0
  333. package/lib/script-build.js +787 -0
  334. package/lib/script-display.d.ts +51 -0
  335. package/lib/script-display.js +383 -0
  336. package/lib/script-icon.d.ts +16 -0
  337. package/lib/script-icon.js +43 -0
  338. package/lib/script-links.d.ts +24 -0
  339. package/lib/script-links.js +204 -0
  340. package/lib/script-source-url.d.ts +8 -0
  341. package/lib/script-source-url.js +214 -0
  342. package/lib/script-world.d.ts +6 -0
  343. package/lib/script-world.js +65 -0
  344. package/lib/sm-dev-protocol.d.ts +251 -0
  345. package/lib/sm-dev-protocol.js +84 -0
  346. package/lib/source-map.d.ts +32 -0
  347. package/lib/source-map.js +177 -0
  348. package/lib/stack-link.d.ts +15 -0
  349. package/lib/stack-link.js +138 -0
  350. package/lib/unsafe-window-use.d.ts +1 -0
  351. package/lib/unsafe-window-use.js +229 -0
  352. package/lib/url-match.d.ts +40 -0
  353. package/lib/url-match.js +734 -0
  354. package/lib/userscript-header.d.ts +33 -0
  355. package/lib/userscript-header.js +248 -0
  356. package/lib/version-compare.d.ts +6 -0
  357. package/lib/version-compare.js +141 -0
  358. package/lib/version-probe.d.ts +17 -0
  359. package/lib/version-probe.js +120 -0
  360. package/package.json +55 -3
  361. package/skills/SourceMonkey-dev/SKILL.md +868 -0
  362. package/skills/SourceMonkey-dev/references/cdp.md +293 -0
  363. package/skills/SourceMonkey-dev/references/commands.md +297 -0
  364. package/skills/SourceMonkey-dev/references/other-managers.md +63 -0
  365. package/skills/SourceMonkey-dev/references/specs.md +46 -0
  366. package/skills/SourceMonkey-friction/SKILL.md +103 -0
  367. package/skills/SourceMonkey-friction/references/template.md +59 -0
@@ -0,0 +1,1165 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>SourceMonkey | Userscript</title>
6
+ <link rel="stylesheet" href="vendor/prism/prism.css" />
7
+ <link rel="stylesheet" href="vendor/prism/prism-line-numbers.css" />
8
+ <link rel="stylesheet" href="styles.css" />
9
+ <!-- Ahead of the Prism scripts and userscript.js on purpose: this
10
+ one paints the header bar's heading, and it has to run before
11
+ the browser's first paint rather than after the viewer's whole
12
+ module graph has loaded. Deferred like every module, so the <h1>
13
+ it writes into is already parsed. See src/extension/page-heading.ts. -->
14
+ <script src="extension/page-heading.js" type="module"></script>
15
+ <style>
16
+ /* The body is at least the viewport and grows past it only when
17
+ the code box's minimum height (`--code-box-min`) no longer
18
+ fits under the details panel — then the page scrolls, padding
19
+ and all. `height: 100%` instead would fix the body at the
20
+ viewport and let that overflow spill out of it. */
21
+ html { height: 100%; margin: 0; }
22
+ body {
23
+ min-height: 100%;
24
+ margin: 0;
25
+ font: 14px system-ui, sans-serif;
26
+ color: #222;
27
+ display: flex;
28
+ flex-direction: column;
29
+ box-sizing: border-box;
30
+ }
31
+ /* The page under the header bar. The body's flex column moves
32
+ down one level so the code box can still take the leftover
33
+ height: `min-height: 0` is what lets this column shrink below
34
+ its content, which is what makes the box scroll rather than
35
+ push the page taller. Full-bleed — the viewer has no
36
+ `--page-width` column, so its padding is the only inset. */
37
+ .page-main {
38
+ flex: 1 1 auto;
39
+ min-height: 0;
40
+ display: flex;
41
+ flex-direction: column;
42
+ /* 16px, matching `.page-header`'s side padding, so the heading
43
+ starts directly above the page's own first line. `1em` here
44
+ is 14px and put the two two pixels apart. */
45
+ padding: 16px;
46
+ box-sizing: border-box;
47
+ }
48
+ /* No focus ring, ever. The `tabindex` in the body exists only so
49
+ in-page navigation can park focus here for a screen reader to
50
+ announce the new script from — the heading is not a control and
51
+ is not tabbable, so a ring around it reads as a text field.
52
+ `:focus-visible` is not the discriminator it looks like: Chrome
53
+ counts a programmatic focus as visible when the focus it
54
+ replaced came from the keyboard, so the ring appeared for some
55
+ clicks and not others. */
56
+ h1:focus { outline: none; }
57
+ /* No hanging indent here, unlike the collections page's name cell:
58
+ the favicon is no longer the first thing on the line (the
59
+ "SourceMonkey | " / "SourceMonkey | Install | " prefix is), so
60
+ there is no single x-position for continuation lines to align
61
+ to. */
62
+ /* Size, weight and colour come from `.page-header h1`
63
+ (styles.css) — every page's heading is the same one. Only the
64
+ wrap behaviour is the viewer's own, because only here is the
65
+ heading a filename. */
66
+ h1 {
67
+ /* Slash-aware wrap: prefer spaces / slashes (with `<wbr>`
68
+ markers inserted by appendWithSlashBreaks), then anywhere
69
+ inside a word only when nothing else fits. */
70
+ overflow-wrap: anywhere;
71
+ word-break: normal;
72
+ }
73
+ /* The heading's favicon slot (`h1 .site-icon`) is shared with the
74
+ compare page — see styles.css. */
75
+ /* The icons inside the slot (`.site-icon-inner`, the globe, the
76
+ <img>) are styled once for every page in styles.css. */
77
+ /* Controls row: everything that acts on the script itself —
78
+ the enable toggle, Local copy…, the delete trash can, Refresh.
79
+ The filename, size, and status moved into the details panel
80
+ below where the dl gives them aligned label/value columns. */
81
+ .meta-row {
82
+ display: flex;
83
+ align-items: center;
84
+ /* One gap for the whole row, matching the one inside
85
+ `.meta-actions`: the controls are peers, so a wider gap on one
86
+ side of the trash can than the other reads as a mistake. */
87
+ gap: 0.5em;
88
+ margin: 0 0 0.5em;
89
+ font-size: 0.95em;
90
+ }
91
+ .meta-row[hidden] { display: none; }
92
+ .meta-status { font-weight: 600; }
93
+ .status-ok { color: #166534; }
94
+ .status-invalid, .status-rejected, .status-error { color: #b00; }
95
+ .status-warning, .status-outdated { color: #b67200; }
96
+ .status-refresh-failed { color: #c2410c; }
97
+ /* Status row is a link to the Log tab — keep it looking like
98
+ status text (not a default blue underline). */
99
+ .meta-status[href] { text-decoration: none; color: inherit; cursor: pointer; }
100
+ .meta-status[href]:hover { text-decoration: underline; }
101
+ /* Horizontal padding only: an `.icon-btn` brings its own, and
102
+ this rule outranks it on specificity — without the `:not()`
103
+ the row's Refresh comes out wider than the trash can beside
104
+ it. Height, surface and hover are shared (styles.css). */
105
+ .meta-row button:not(.icon-btn) { padding: 0 0.7em; }
106
+ .meta-row .toggle { display: inline-flex; align-items: center; gap: 0.3em; cursor: pointer; margin-left: auto; }
107
+ /* The script's own actions, between the Enabled box and Refresh.
108
+ Nothing here styles the buttons: every button in this row —
109
+ Local copy…, the trash can, Refresh — takes the one shared
110
+ surface and height from styles.css. This used to `revert` the
111
+ trash can's border and background to the browser's own, back
112
+ when the shared style gave it no chrome at all; once the
113
+ shared style became the chrome, that revert was what made this
114
+ one button look unlike everything beside it. */
115
+ .meta-row .meta-actions {
116
+ display: flex;
117
+ align-items: center;
118
+ gap: 0.5em;
119
+ }
120
+ .meta-row .toggle input[type="checkbox"] { cursor: pointer; margin: 0; }
121
+ .meta-row .toggle.toggle-disabled { cursor: not-allowed; opacity: 0.5; }
122
+ .meta-row .toggle.toggle-disabled input[type="checkbox"] { cursor: not-allowed; }
123
+ .message { margin: 0 0 0.5em; }
124
+ .message.error { color: #b00; }
125
+ .message.refresh-failed { color: #c2410c; }
126
+ .message:empty { display: none; }
127
+ /* Preview-mode install callout, banner, and action row. With
128
+ nothing installed, the callout IS the page's question — "Install
129
+ into [collection]" — so it gets the box; when copies exist the
130
+ banner takes that spot, in one box with the table that carries
131
+ the choice. The row under either holds Cancel / View raw
132
+ source. */
133
+ .install-callout {
134
+ display: flex;
135
+ align-items: center;
136
+ gap: 0.5em;
137
+ flex-wrap: wrap;
138
+ /* Same green as the versions panel: both are about
139
+ where a copy of this script lives. */
140
+ border: 1px solid #b9d4b1;
141
+ background: #dbecd6;
142
+ border-radius: 6px;
143
+ padding: 10px 14px;
144
+ margin: 0 0 10px;
145
+ }
146
+ .install-callout[hidden] { display: none; }
147
+ /* Unbolded on purpose, and so with no weight of its own: the
148
+ label is the connector in "Install into <collection>", not a
149
+ heading over the row — the button ahead of it is the verb, and
150
+ a bold word between the two controls breaks the sentence. */
151
+ .install-callout label[hidden] { display: none; }
152
+ /* A collection name can be longer than the callout. The row wraps
153
+ first (`flex-wrap` above) and the dropdown then shrinks rather
154
+ than running past the edge; Chrome sizes the OPEN list to its
155
+ widest option, so the full name is still readable there. */
156
+ .install-callout select { flex: 0 1 auto; min-width: 0; }
157
+ /* Horizontal only: height and the disabled state are shared
158
+ (styles.css). */
159
+ .install-callout button { padding: 0 0.9em; }
160
+ .install-callout .primary { font-weight: 600; }
161
+ .actions { display: flex; gap: 0.5em; align-items: center; margin: 0 0 0.7em; }
162
+ .actions[hidden] { display: none; }
163
+ .actions button { padding: 0 0.9em; }
164
+ .actions button:disabled { cursor: not-allowed; opacity: 0.5; }
165
+ .actions .primary { font-weight: 600; }
166
+ .actions .spacer { margin-left: auto; }
167
+ /* The banner box is in styles.css (shared with the collections page,
168
+ which is also where the file-access banner comes from). Only
169
+ the viewer's own colour variant lives here — the amber default
170
+ is a warning, and "already installed" is not. */
171
+ /* Matches the versions panel — this banner is about which of
172
+ those copies to act on, so the two share a ground before the
173
+ `merged` rule below makes them literally one box. */
174
+ .banner.installed { border-color: #b9d4b1; background: #dbecd6; }
175
+ /* One line, not the block-level heading `.banner strong` gives
176
+ every other banner: this one is a sentence with its follow-up
177
+ in the same breath, and the table under it is what needs the
178
+ vertical room. */
179
+ .banner.installed strong { display: inline; margin-bottom: 0; }
180
+ /* …and when both are on screen they are literally one box: the
181
+ wrapper takes the green card and the two children give up
182
+ their own borders, so "This script is already installed" and
183
+ the table of copies read as one statement rather than two
184
+ stacked cards in the same colour. Only the preview's installed
185
+ case sets `merged` (renderInstalledBanner); a warning banner
186
+ raised alongside keeps its own amber box inside. */
187
+ #status-box.merged {
188
+ border: 1px solid #b9d4b1;
189
+ background: #dbecd6;
190
+ border-radius: 6px;
191
+ padding: 10px 14px;
192
+ margin: 0 0 10px;
193
+ }
194
+ #status-box.merged .banner.installed {
195
+ border: 0;
196
+ background: none;
197
+ padding: 0;
198
+ margin: 0;
199
+ border-radius: 0;
200
+ }
201
+ /* The blank line between the banner's one line and the first row
202
+ of the table is this margin — a preview's panel draws no
203
+ heading of its own, so nothing else separates them. */
204
+ #status-box.merged #other-versions {
205
+ border: 0;
206
+ background: none;
207
+ padding: 0;
208
+ margin: 14px 0 0;
209
+ }
210
+ /* `@keyframes sm-spin` is in styles.css, shared with the dialog
211
+ spinner and the glyph buttons' spin state. */
212
+ .busy-spinner { display: inline-block; width: 12px; height: 12px; margin-left: -0.2em; border: 2px solid #ccc; border-top-color: #555; border-radius: 50%; animation: sm-spin 0.7s linear infinite; box-sizing: border-box; }
213
+ /* The "loaded from local disk" chip, worn by a code tab whose
214
+ body came off local disk rather than from the URL its
215
+ declaration names. Loud enough to notice without hovering,
216
+ which is the whole reason that fact isn't left to the
217
+ tooltip. */
218
+ .tab-mark {
219
+ white-space: nowrap;
220
+ padding: 0 0.4em;
221
+ border-radius: 3px;
222
+ background: #d97706;
223
+ color: #fff;
224
+ font-size: 10px;
225
+ font-weight: 600;
226
+ text-transform: uppercase;
227
+ letter-spacing: 0.04em;
228
+ }
229
+ /* Details panel: the header fields worth surfacing (when a
230
+ metadata block is present) plus the resolved Collection /
231
+ Location / Size / Status rows. Cleared via :empty when there's
232
+ no script. */
233
+ #header-summary {
234
+ margin: 0 0 11px;
235
+ padding: 8px 11px;
236
+ border: 1px solid #ddd;
237
+ border-radius: 4px;
238
+ background: #f5f7fa;
239
+ }
240
+ #header-summary:empty { display: none; }
241
+ #header-summary dl {
242
+ display: grid;
243
+ grid-template-columns: max-content 1fr;
244
+ column-gap: 0.8em;
245
+ row-gap: 0.25em;
246
+ margin: 0;
247
+ }
248
+ #header-summary dt {
249
+ font-weight: 600;
250
+ color: #555;
251
+ }
252
+ #header-summary dd {
253
+ margin: 0;
254
+ /* Slash-aware wrap for any long URL/path that lands in a
255
+ dd value (Location, Match, Exclude patterns, …). */
256
+ overflow-wrap: anywhere;
257
+ word-break: normal;
258
+ }
259
+ /* An upstream copy that's ahead of the one we run — same amber as
260
+ the OUTDATED status this row is the detail behind. Only the
261
+ "newer" direction is highlighted; running ahead of the published
262
+ version is normal for a local edit. */
263
+ #header-summary dd.version-newer {
264
+ color: #b67200;
265
+ font-weight: 600;
266
+ }
267
+ #header-summary ul {
268
+ margin: 0;
269
+ padding-left: 1.1em;
270
+ }
271
+ /* The "(N more)" / "(show fewer)" bullet that folds a long list
272
+ (see `bulletList` in script-details.ts). A button styled as
273
+ text: muted like the row labels so it reads as an aside, not an
274
+ item, with an underline on hover to say it's clickable. */
275
+ .list-fold { list-style: none; }
276
+ .list-fold-toggle {
277
+ all: unset;
278
+ cursor: pointer;
279
+ color: #555;
280
+ font: inherit;
281
+ }
282
+ .list-fold-toggle:hover { text-decoration: underline; }
283
+ .list-fold-toggle:focus-visible { outline: 2px solid #4a90e2; outline-offset: 1px; }
284
+ /* Network access: the "Declared / Undeclared in @connect:" line
285
+ above each of its lists, muted like the row labels. */
286
+ .list-heading { color: #555; }
287
+ /* Network access: a prompt answer and its Reset button
288
+ (`addConnect` in script-details.ts). A short button, so the row
289
+ keeps the height of its neighbours. */
290
+ .connect-answer { display: inline-flex; align-items: center; gap: 0.25em; }
291
+ .connect-answer button { height: 20px; padding: 0 7px; margin-left: 0.4em; font-size: 0.9em; }
292
+ /* Match and Network access rows: each value is led by its
293
+ site's favicon (a globe when it names no site), between the
294
+ bullet and the URL. The slot is a flex item so a wrapping pattern's
295
+ continuation lines don't tuck under the icon. */
296
+ .pattern-cell {
297
+ display: inline-flex;
298
+ align-items: baseline;
299
+ gap: 0.4em;
300
+ max-width: 100%;
301
+ }
302
+ /* The text is the flex item that shrinks; without this a long
303
+ pattern would push the cell wider instead of wrapping. */
304
+ .pattern-cell > :not(.pattern-icon) { min-width: 0; }
305
+ .pattern-icon {
306
+ display: inline-flex;
307
+ width: 16px;
308
+ height: 16px;
309
+ flex: 0 0 auto;
310
+ /* Centred on the line rather than sat on the baseline, which
311
+ left the square hanging low beside the pattern text. */
312
+ align-self: center;
313
+ }
314
+ /* Location row: path text + a square copy-icon button to its
315
+ right. min-width:0 lets long paths shrink and wrap rather
316
+ than blow out the grid column. */
317
+ .filename-cell {
318
+ display: flex;
319
+ align-items: center;
320
+ gap: 0.4em;
321
+ min-width: 0;
322
+ }
323
+ .filename-text {
324
+ /* Slash-aware wrap; see h1 above. */
325
+ overflow-wrap: anywhere;
326
+ word-break: normal;
327
+ min-width: 0;
328
+ }
329
+ /* Local overrides row: one entry per overridden `@require` /
330
+ `@resource`. Same flex shape as the Location cell — it's the
331
+ same kind of value (a path plus its copy button). */
332
+ .local-override-cell {
333
+ display: flex;
334
+ align-items: center;
335
+ gap: 0.4em;
336
+ min-width: 0;
337
+ }
338
+ /* The `@require` / `@resource` tag that says which kind of
339
+ declaration this entry stood in for. Muted and monospace: it's
340
+ a label on the path beside it, not the value. */
341
+ .local-override-kind {
342
+ flex: none;
343
+ color: #777;
344
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
345
+ font-size: 11px;
346
+ }
347
+ .local-override-path {
348
+ /* Slash-aware wrap; see h1 above. */
349
+ overflow-wrap: anywhere;
350
+ word-break: normal;
351
+ min-width: 0;
352
+ }
353
+ /* Anchors in the details panel (Match patterns, Location)
354
+ read as plain text by default; underline only on hover so
355
+ the rows stay calm. The bubble is excluded so its `color:#fff`
356
+ survives — its hover affordance is the opacity dip below. */
357
+ #header-summary dd a:not(.collection-type-bubble) { color: inherit; text-decoration: none; }
358
+ #header-summary dd a:not(.collection-type-bubble):hover { text-decoration: underline; }
359
+ /* Anchors inside the highlighted code block. Inherit Prism's
360
+ token color (comment-grey, string-green, etc.) so the code
361
+ box keeps reading as code; only the hover underline signals
362
+ clickability. */
363
+ pre.code-box a.code-link { color: inherit; text-decoration: none; }
364
+ pre.code-box a.code-link:hover { text-decoration: underline; }
365
+ /* `.log-id-cell` deliberately has no rules: the log ID reads as
366
+ regular text like every other value in the panel. It's a
367
+ filename, not code, and it was the only monospace row. The
368
+ class stays as a hook for finding the cell. Wrapping comes from
369
+ the `dd`'s own slash-aware rule. */
370
+ /* ---- "Other versions" panel (src/extension/related-versions.ts) ----
371
+ Sits at the top of the page, under the title and above the
372
+ controls row: which copy you are looking at comes before
373
+ anything that acts on it. Same card shape as #header-summary
374
+ further down, but a green ground rather than that panel's
375
+ grey — this is the one that carries live controls, so it has
376
+ to read as a different kind of thing at a glance. Empty when
377
+ nothing relates, and hidden by the :empty rule rather than a
378
+ `hidden` attribute the renderer would have to manage. */
379
+ #other-versions {
380
+ margin: 0 0 11px;
381
+ padding: 8px 11px;
382
+ border: 1px solid #b9d4b1;
383
+ border-radius: 4px;
384
+ background: #dbecd6;
385
+ }
386
+ #other-versions:empty { display: none; }
387
+ /* Heading line: the title, and the fold control pushed to the
388
+ far corner. The gap below belongs to the line rather than to
389
+ the <h2>, so a folded panel is exactly one line tall with no
390
+ trailing space under it. */
391
+ .versions-head {
392
+ display: flex;
393
+ align-items: baseline;
394
+ justify-content: space-between;
395
+ gap: 8px;
396
+ margin: 0 0 8px;
397
+ }
398
+ .versions-head.collapsed { margin: 0; }
399
+ /* …except when a failure line follows the folded heading: the two
400
+ are the whole panel then, and they still need a gap. */
401
+ .versions-head.collapsed + .versions-message { margin-top: 8px; }
402
+ #other-versions h2 {
403
+ font-size: 1.1em;
404
+ font-weight: 650;
405
+ color: #333;
406
+ line-height: 18px;
407
+ margin: 0;
408
+ }
409
+ /* A bare triangle, quiet until pointed at: it sits above the
410
+ panel's own controls and must not compete with them. Padded out
411
+ to a real target — it is the panel's only fold affordance, and
412
+ the glyph itself is a few pixels wide. */
413
+ .versions-collapse {
414
+ flex: none;
415
+ /* Its own height: this is a small inline affordance inside the
416
+ panel heading, not a control in a row of buttons, so the
417
+ shared button height would make it loom over the heading. */
418
+ height: 18px;
419
+ border: 0;
420
+ border-radius: 3px;
421
+ background: none;
422
+ padding: 0 6px;
423
+ font-size: 12px;
424
+ line-height: 18px;
425
+ color: #4a6a44;
426
+ cursor: pointer;
427
+ }
428
+ .versions-collapse:hover { background: #cbe3c5; color: #223; }
429
+ /* Pressed is a shade past hover, the same direction of travel
430
+ as every other button in the extension (styles.css). */
431
+ .versions-collapse:active { background: #b8d6b1; color: #223; }
432
+ /* A bare glyph has no shape of its own to show focus with — and
433
+ this is the control the fold hands focus back to. */
434
+ .versions-collapse:focus-visible { outline: 2px solid #4a90e2; outline-offset: 1px; }
435
+ .versions-section-heading {
436
+ font-size: 1em;
437
+ font-weight: 600;
438
+ color: #444;
439
+ line-height: 16px;
440
+ margin: 13px 0 4px;
441
+ }
442
+ .versions-section-heading:first-of-type { margin-top: 0; }
443
+ /* The parenthesized gloss names which match produced the rows
444
+ below. It belongs to the heading, so it lives inside the
445
+ <h3> — but at body weight, or the two sections would read as
446
+ equally emphatic. */
447
+ .versions-heading-gloss {
448
+ font-weight: 400;
449
+ color: #777;
450
+ font-size: 12px;
451
+ }
452
+ /* A heading row that is there for a screen reader and not for the
453
+ eye — the install-offer section's, whose labels the section
454
+ above it has already shown (see `makeTable`). Taken out of
455
+ flow rather than `display: none`, which drops it from the
456
+ accessibility tree along with the page. */
457
+ .versions-table thead.visually-hidden {
458
+ position: absolute;
459
+ width: 1px;
460
+ height: 1px;
461
+ overflow: hidden;
462
+ clip-path: inset(50%);
463
+ white-space: nowrap;
464
+ }
465
+ /* `fixed` + the <colgroup> the renderer emits is what keeps the
466
+ two sections' columns aligned with each other: without it each
467
+ <table> sizes its own columns from its own content and the
468
+ panel reads as two unrelated grids. */
469
+ /* Whole-px vertical metrics in this panel, and `separate` borders
470
+ rather than `collapse` (a collapsed border is split half into each
471
+ adjacent cell, landing rows on half pixels) — see
472
+ docs/architecture.md, "Extension-page styling". */
473
+ .versions-table {
474
+ width: 100%;
475
+ border-collapse: separate;
476
+ border-spacing: 0;
477
+ table-layout: fixed;
478
+ }
479
+ /* Status, Version, Content, and the actions column are sized to
480
+ their own widest content by `fitColumns` (related-versions.ts),
481
+ which writes the custom properties below onto the panel. The
482
+ fallbacks are what the first paint uses and what a measurement
483
+ of a hidden panel falls back to: wide enough for REFRESH
484
+ FAILED and a date-shaped @version. Everything left over goes to
485
+ Location, which is the column that can always use it. */
486
+ .versions-table col.col-enabled { width: 2.2em; }
487
+ .versions-table col.col-collection { width: 26%; }
488
+ .versions-table col.col-status { width: var(--w-col-status, 8em); }
489
+ .versions-table col.col-version { width: var(--w-col-version, 7em); }
490
+ .versions-table col.col-compare { width: var(--w-col-compare, 7em); }
491
+ .versions-table col.col-actions { width: var(--w-col-actions, 6em); }
492
+ .versions-table col.col-remove { width: 2.4em; }
493
+ /* Same #444 as the section heading above the table: the panel's
494
+ two kinds of heading are both headings, and at 11px uppercase
495
+ a lighter grey reads as faded rather than as secondary. */
496
+ .versions-table th {
497
+ text-align: left;
498
+ font-size: 11px;
499
+ font-weight: 600;
500
+ color: #444;
501
+ text-transform: uppercase;
502
+ letter-spacing: 0.04em;
503
+ padding: 0 6px 2px 0;
504
+ border-bottom: 1px solid #b9d4b1;
505
+ }
506
+ .versions-table td {
507
+ padding: 5px 7px 5px 0;
508
+ line-height: 16px;
509
+ vertical-align: top;
510
+ border-bottom: 1px solid #c9e0c2;
511
+ }
512
+ .versions-table tr:last-child td { border-bottom-color: transparent; }
513
+ .versions-table .col-actions {
514
+ text-align: right;
515
+ padding-right: 0;
516
+ white-space: nowrap;
517
+ }
518
+ .versions-table th.col-actions button { font-size: 12px; }
519
+ /* Type styling for the body cells is scoped to `td`, here and in
520
+ the Location rule below. A column class sits on the `th` too,
521
+ and `.versions-table .col-x` outranks `.versions-table th`, so
522
+ an unscoped `color` / `font-size` here leaks into that
523
+ column's heading — which is how COLLECTION, LOCATION, STATUS
524
+ and VERSION ended up drawn in three combinations of size and
525
+ grey. The heading row is one row and reads as one. */
526
+ .versions-table td.col-version {
527
+ color: #555;
528
+ font-variant-numeric: tabular-nums;
529
+ overflow-wrap: anywhere;
530
+ }
531
+ /* A wider right gutter than the other columns get: these two are
532
+ measured to their content, so without it the widest status
533
+ would sit hard against the version beside it. On the `th` as
534
+ well, so heading and values share an edge, and inside the
535
+ measured width, so the gutter survives the fit. */
536
+ .versions-table .col-status,
537
+ .versions-table .col-version,
538
+ .versions-table .col-compare { padding-right: 1.1em; }
539
+ /* Status reuses the `status-*` colours the controls row and the
540
+ collections page already use, so one verdict is one colour
541
+ everywhere, and styles its link as status text — see
542
+ docs/script-identity.md for why the colour, not the underline,
543
+ is what has to carry. */
544
+ .versions-table td.col-status { font-size: 12px; }
545
+ .versions-table .col-status a {
546
+ font-weight: 600;
547
+ text-decoration: none;
548
+ white-space: nowrap;
549
+ }
550
+ .versions-table .col-status a:hover { text-decoration: underline; }
551
+ /* Compare is a verdict like Status and dressed like one. Green is
552
+ Status's own OK. DIFFERENT is blue, not the `modified` chip's
553
+ teal: on this panel's green card teal and green are near twins
554
+ down a column, and the two words have to be told apart at a
555
+ glance. BASE (NEW on a preview) marks the row the rest are
556
+ compared against and carries no colour — it is a label, not a
557
+ verdict. */
558
+ .versions-table td.col-compare { font-size: 12px; white-space: nowrap; }
559
+ /* Flush left, all of it: the heading, the words, and the DIFF
560
+ button's EDGE — not its label — start on the column's line. */
561
+ .versions-table td.col-compare span { font-weight: 600; }
562
+ .versions-table .content-same { color: #166534; }
563
+ .versions-table .content-different { color: #1d4ed8; }
564
+ /* DIFF: the verdict as a button, since it opens the compare page.
565
+ The shared button surface (styles.css), in DIFFERENT's blue and
566
+ the column's weight, sized like the row's other buttons. */
567
+ .versions-table button.content-diff {
568
+ padding: 0 0.6em;
569
+ font-size: 12px;
570
+ font-weight: 600;
571
+ color: #1d4ed8;
572
+ }
573
+ .versions-table .content-base { color: #555; }
574
+ /* Slash-aware wrap; see the h1 rule above. `min-width: 0` lets
575
+ a long URL shrink its column rather than widening the table. */
576
+ .versions-table .col-collection,
577
+ .versions-table .col-location {
578
+ overflow-wrap: anywhere;
579
+ word-break: normal;
580
+ min-width: 0;
581
+ }
582
+ .versions-table td.col-location { font-size: 12px; color: #555; }
583
+ .versions-collection-name {
584
+ color: inherit;
585
+ text-decoration: none;
586
+ font-weight: 500;
587
+ }
588
+ .versions-collection-name:hover { text-decoration: underline; }
589
+ .versions-table .col-location a { color: inherit; text-decoration: none; }
590
+ .versions-table .col-location a:hover { text-decoration: underline; }
591
+ /* A deeper tint of the panel's own green, not the blue used
592
+ elsewhere for "current" — on this ground a blue row would read
593
+ as a different kind of highlight rather than as emphasis. */
594
+ .versions-table tr.is-current { background: #c3e0ba; }
595
+ /* Rows that select their copy when clicked anywhere that isn't a
596
+ control (installed mode only — see `versionRow`). The hover
597
+ tint stops short of the current row's, so "the row under the
598
+ pointer" and "the row you are on" stay distinguishable while
599
+ the pointer is over one of them. */
600
+ .versions-table tr.is-navigable { cursor: pointer; }
601
+ .versions-table tr.is-navigable:hover { background: #d3e8cb; }
602
+ /* The rows are the tab stops the Location links used to be, so
603
+ they need a ring of their own — the current row included: it
604
+ takes focus after a selection and on the Up/Down walk, even
605
+ though activating it does nothing. Inset, because an outline
606
+ drawn outside a table row is clipped by the row above it. */
607
+ .versions-table tr.is-navigable:focus-visible,
608
+ .versions-table tr.is-current:focus-visible {
609
+ outline: 2px solid #4a7f3d;
610
+ outline-offset: -2px;
611
+ }
612
+ .versions-current-marker { color: #666; }
613
+ .versions-this-page { font-weight: 700; color: #333; }
614
+ .versions-table tr.is-offer .versions-offer-text {
615
+ color: #888;
616
+ font-style: italic;
617
+ }
618
+ /* The install-offer row's controls, in the one cell that spans
619
+ everything left of Location (see `installRow`). One line —
620
+ "Install into <collection>" — reading the way the header
621
+ callout does, with the button next to the dropdown that
622
+ decides what it will do rather than out at the table's right
623
+ edge. The disabled-button explanation sits under the line. */
624
+ .versions-table td.col-install { padding-right: 10px; }
625
+ /* Button, connector and dropdown on one line. `min-width: 0` on
626
+ the select is what lets it give way to them instead of
627
+ overflowing the cell — a flex item's default floor is its
628
+ content width, and a long collection name is wider than two
629
+ columns. Chrome sizes the open list to its widest option, so
630
+ a name truncated here is still readable in the list. */
631
+ .install-offer-pick {
632
+ display: flex;
633
+ align-items: center;
634
+ gap: 6px;
635
+ }
636
+ .install-offer-pick select { flex: 1 1 auto; min-width: 0; }
637
+
638
+ /* The recommended action in a preview that already has copies:
639
+ update one of them rather than install another. Set here
640
+ because the shared `.primary` bolding is scoped to the callout
641
+ and the action row. */
642
+ .versions-table td.col-actions button.primary { font-weight: 600; }
643
+ /* Not bold, for the same reason the header's Install isn't once
644
+ copies are listed (`showInstallCallout`): this row offers
645
+ ANOTHER copy alongside versions the user could update instead,
646
+ so it is an alternative, not the recommended move. The
647
+ emphasis is on the rows' Update buttons. */
648
+ .versions-table td.col-install button {
649
+ flex: none;
650
+ font: inherit;
651
+ padding: 0.35em 0.9em;
652
+ cursor: pointer;
653
+ }
654
+ /* Greyed by explicit colours, not by `opacity` — on this panel's
655
+ green ground a translucent button takes the green on and stops
656
+ reading as a disabled control at all. */
657
+ .versions-table td.col-install button:disabled {
658
+ cursor: not-allowed;
659
+ background: #ececec;
660
+ border-color: #c2c2c2;
661
+ color: #999;
662
+ }
663
+ /* Why Install is off: its own line under the sentence above, not
664
+ spliced into the middle of it. Empty — and so invisible —
665
+ otherwise. */
666
+ .install-offer-note {
667
+ margin-top: 5px;
668
+ font-size: 12px;
669
+ color: #666;
670
+ font-style: italic;
671
+ }
672
+ .versions-table .toggle {
673
+ display: inline-flex;
674
+ align-items: center;
675
+ cursor: pointer;
676
+ }
677
+ .versions-table .toggle input[type="checkbox"] { cursor: pointer; margin: 0; }
678
+ /* Same treatment as the controls-row toggle when the parent
679
+ collection is off: the box can't be clicked, so it must not look
680
+ clickable. */
681
+ .versions-table .toggle.toggle-disabled { cursor: not-allowed; opacity: 0.5; }
682
+ .versions-table .toggle.toggle-disabled input[type="checkbox"] { cursor: not-allowed; }
683
+ /* Trash can, in its own column hard against the table's right
684
+ edge. The button itself is `.icon-btn` in styles.css — the same
685
+ control as the refetch arrow beside it, which is what the two
686
+ looked like two different widgets before. Disabled (a script
687
+ inside a collection) keeps the button on screen, since the
688
+ column would otherwise look ragged with no clue why. */
689
+ .versions-table .col-remove {
690
+ text-align: right;
691
+ padding-right: 0;
692
+ white-space: nowrap;
693
+ }
694
+ /* A disabled row button (a script inside a collection, which the
695
+ collection's own removal takes) stays a button — dimmed, but
696
+ still a box with a border. Dropping the border left a bare
697
+ glyph floating on the panel's green, which read as an icon
698
+ rather than a control that happens to be unavailable. The
699
+ dimming is `.icon-btn:disabled` in styles.css. */
700
+ /* The panel reports its own action failures here rather than in
701
+ the page's `#message` bar — see related-versions.ts. */
702
+ .versions-message {
703
+ margin: 0 0 0.5em;
704
+ color: #b3261e;
705
+ font-size: 12px;
706
+ }
707
+ /* Narrow windows shed the Version column rather than letting
708
+ every cell wrap to an unreadable ribbon. It is the least
709
+ load-bearing: nothing acts on it, and the copies it
710
+ distinguishes are still distinguished by collection and location.
711
+ It stays in the DOM (hidden, not dropped) so nothing has to
712
+ re-render on resize.
713
+ Zeroing the <col> width alongside `display: none` on the
714
+ cells is what actually reclaims the space: under
715
+ `table-layout: fixed` the colgroup, not the cells, is what
716
+ sets column width.
717
+
718
+ Status does not shed either: it is the column that says
719
+ whether a copy is actually working, and its link is the only
720
+ route to that copy's log from here.
721
+
722
+ Location does NOT shed, though it used to. Its link is the
723
+ only way to reach another copy's page now that a preview with
724
+ several targets drops its header Open button in favour of this
725
+ table — hiding it would leave a narrow window with no route to
726
+ a copy at all. Wrapping a long path is the lesser cost. */
727
+ @media (max-width: 640px) {
728
+ .versions-table col.col-version { width: 0; }
729
+ .versions-table .col-version { display: none; }
730
+ }
731
+ /* Collection row layout. Grid layout so a long display name wraps
732
+ inside the middle column instead of dropping back to the row's
733
+ left edge. The bubble's own styling (color, padding, hover) is
734
+ in styles.css, the cross-page shared stylesheet. */
735
+ /* `minmax(0, max-content)` on the name, not `1fr`: a name that
736
+ fits keeps its natural width, so the Move button sits right
737
+ after it instead of being flung to the margin. A name too long
738
+ for the row fills the track, wraps inside it, and the button
739
+ ends up at the right edge — which is where it belongs once
740
+ there is no "right after the name" to sit at. */
741
+ .collection-cell {
742
+ display: grid;
743
+ grid-template-columns: max-content minmax(0, max-content) max-content;
744
+ column-gap: 0.5em;
745
+ align-items: baseline;
746
+ min-width: 0;
747
+ }
748
+ /* Move control: the Collection row's own button, in a column of
749
+ its own so a wrapping name never drags it down onto the last
750
+ wrapped line.
751
+
752
+ Its height is no longer its own business: every button takes
753
+ the shared height (styles.css), which is what keeps it level
754
+ with the versions table's row buttons now that those hold a
755
+ glyph. Only the padding is here. */
756
+ .collection-move { padding: 0 0.7em; }
757
+ /* `.copy-btn` (the square copy-to-clipboard button) is in
758
+ styles.css: the delete dialog uses it on every page. */
759
+ /* Tab strip above the code box: one tab per source file (main
760
+ script + each @require). Always rendered. The strip sits
761
+ entirely above the code box (no overlap, no negative margin
762
+ tricks) so the layout is robust against the body's flex
763
+ column constraints. */
764
+ /* The tab strip itself (`.tabs`, `.tab`) is shared with the
765
+ compare page — see styles.css. Only the chip's placement in a
766
+ tab is this page's own. */
767
+ /* Positioning only — the chip's own look is above. */
768
+ .tab-mark { margin-left: 0.5em; vertical-align: 1px; }
769
+ /* The code box fills the rest of the viewport and scrolls. The
770
+ padding/border give it a textbox-like look; tabindex makes it
771
+ keyboard-focusable so it scrolls with arrow keys. The
772
+ top-left rounding is dropped so the active tab meets the box
773
+ cleanly along that edge. margin-top:-1px lets the active tab's
774
+ transparent bottom border merge with the code box's top
775
+ border so the active tab visually "opens into" the box.
776
+
777
+ A tall details panel (a script with dozens of @match lines) would
778
+ otherwise squeeze the box to nothing. `--code-box-min` keeps a
779
+ useful number of lines visible and lets the PAGE scroll instead
780
+ — the one case where the viewer accepts a page-level scroll bar.
781
+ 20 lines at Prism's line-height (1.5, set on the <code> by
782
+ vendor/prism/prism.css, so not ours to pin here) and this box's
783
+ 13px font, plus its padding and border: the box is border-box
784
+ so the minimum is its outer height, and the Log pane below
785
+ shares it so switching tabs doesn't reflow. */
786
+ .page-main { --code-box-min: calc(20 * 1.5 * 13px + 2 * 0.8 * 13px + 2px); }
787
+ pre.code-box {
788
+ /* Basis 0: the box's own content must never size the page —
789
+ it scrolls inside the box. Its floor is the minimum below. */
790
+ flex: 1 1 0;
791
+ min-height: var(--code-box-min);
792
+ box-sizing: border-box;
793
+ margin: -1px 0 0;
794
+ overflow: auto;
795
+ border: 1px solid #ccc;
796
+ border-radius: 0 4px 4px 4px;
797
+ padding: 0.8em;
798
+ background: #fafafa;
799
+ font: 13px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
800
+ }
801
+ pre.code-box:focus { outline: 2px solid #4a90e2; outline-offset: -2px; }
802
+ /* Tinted band behind the `// ==UserScript== … // ==/UserScript==`
803
+ block. `display: block` lets the band span every header line;
804
+ the negative left/right margin (paired with matching padding)
805
+ extends the band out to the code-box's padding edges so it
806
+ reads as a full-width strip rather than a floating rectangle.
807
+ The grey paint lives on a ::before with z-index: -1 (rather
808
+ than `background:` on the span) so the line-highlight
809
+ overlay can sit at the same z-index and, by document order,
810
+ paint over the grey when a header line is highlighted. */
811
+ pre.code-box .token.userscript-header {
812
+ display: block;
813
+ position: relative;
814
+ margin: 0 -0.8em;
815
+ padding: 0 0.8em;
816
+ }
817
+ pre.code-box .token.userscript-header::before {
818
+ content: '';
819
+ position: absolute;
820
+ inset: 0;
821
+ background: #f0f0f0;
822
+ z-index: -1;
823
+ }
824
+ /* Log pane mirrors the code box's outer dimensions so swapping
825
+ between a code tab and the Log tab doesn't reflow the page.
826
+ Same border/margin trick as .code-box so the active Log tab's
827
+ bottom border merges with the pane's top border. */
828
+ .log-pane {
829
+ flex: 1 1 0;
830
+ min-height: var(--code-box-min);
831
+ box-sizing: border-box;
832
+ margin: -1px 0 0;
833
+ overflow: auto;
834
+ border: 1px solid #ccc;
835
+ border-radius: 0 4px 4px 4px;
836
+ background: #fafafa;
837
+ }
838
+ .log-pane[hidden] { display: none; }
839
+ .log-pane:focus { outline: 2px solid #4a90e2; outline-offset: -2px; }
840
+ .log-pane table {
841
+ width: 100%;
842
+ border-collapse: collapse;
843
+ font: 12px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
844
+ }
845
+ .log-pane th, .log-pane td {
846
+ padding: 0.35em 0.6em;
847
+ text-align: left;
848
+ vertical-align: top;
849
+ border-bottom: 1px solid #eee;
850
+ }
851
+ .log-pane th {
852
+ background: #f0f0f0;
853
+ font-weight: 600;
854
+ color: #555;
855
+ position: sticky;
856
+ top: 0;
857
+ z-index: 1;
858
+ }
859
+ .log-pane td.log-ts { white-space: nowrap; color: #555; }
860
+ .log-pane td.log-source { white-space: nowrap; color: #555; }
861
+ .log-pane td.log-msg { white-space: pre-wrap; word-break: break-word; }
862
+ .log-pane td.log-level { white-space: nowrap; }
863
+ .log-pane .log-level-badge {
864
+ display: inline-block;
865
+ padding: 0 0.45em;
866
+ border-radius: 3px;
867
+ font-weight: 600;
868
+ font-size: 11px;
869
+ text-transform: uppercase;
870
+ letter-spacing: 0.04em;
871
+ }
872
+ .log-pane .log-level-info { background: #e7eef7; color: #345; }
873
+ .log-pane .log-level-warning { background: #fdf1c5; color: #6b4f00; }
874
+ .log-pane .log-level-error { background: #fbe2e2; color: #8a1d1d; }
875
+ /* State-carrying entries (see `LogEntry.state`): the same hues the
876
+ Status badge uses for that state, on a badge background. */
877
+ .log-pane .log-state-ok { background: #dcfce7; color: #166534; }
878
+ .log-pane .log-state-invalid,
879
+ .log-pane .log-state-rejected { background: #fbe2e2; color: #8a1d1d; }
880
+ .log-pane .log-state-outdated { background: #fdf1c5; color: #6b4f00; }
881
+ .log-pane .log-state-refresh-failed { background: #ffedd5; color: #c2410c; }
882
+ .log-empty {
883
+ padding: 1em;
884
+ color: #777;
885
+ font: 13px system-ui, sans-serif;
886
+ }
887
+ .log-toolbar {
888
+ display: flex;
889
+ justify-content: flex-end;
890
+ gap: 0.4em;
891
+ padding: 0.4em 0.6em;
892
+ border-bottom: 1px solid #eee;
893
+ position: sticky;
894
+ top: 0;
895
+ background: #fafafa;
896
+ z-index: 2;
897
+ }
898
+ .log-toolbar button {
899
+ font: inherit;
900
+ padding: 0.2em 0.7em;
901
+ cursor: pointer;
902
+ }
903
+ /* Save/Copy are disabled while the log is empty — there is
904
+ nothing to hand out but a header row. */
905
+ .log-toolbar button:disabled {
906
+ cursor: default;
907
+ opacity: 0.5;
908
+ }
909
+ /* Clickable `sourcemonkey://…:L:C` refs inside log messages.
910
+ The log table renders with a monospace font, so a regular
911
+ blue underline reads clearly without disrupting the column. */
912
+ .log-pane .log-stack-link {
913
+ color: #1d4ed8;
914
+ text-decoration: underline;
915
+ cursor: pointer;
916
+ }
917
+ .log-pane .log-stack-link:hover { color: #2563eb; }
918
+ /* The `(in <file>, line N, column M)` part of a diagnostic we
919
+ derived ourselves — a header problem, a bad `@require`, a
920
+ syntax error. Appears in three places with three different
921
+ surrounding colours (the red `.message` bar, an amber banner,
922
+ a Log row), so it inherits the surrounding weight and marks
923
+ itself only with an underline and the monospace face the file
924
+ name deserves. `color: inherit` keeps the red error bar red
925
+ rather than half red and half blue. */
926
+ .diagnostic-link {
927
+ color: inherit;
928
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
929
+ text-decoration: underline;
930
+ cursor: pointer;
931
+ }
932
+ .diagnostic-link:hover { text-decoration-thickness: 2px; }
933
+ /* The line-numbers plugin makes <code> position: relative but
934
+ leaves it inline; without an explicit display:block the
935
+ absolute .line-flash overlay below sizes to the line box
936
+ instead of the full code area. `z-index: 0` turns <code>
937
+ into a stacking context so the highlight overlay can sit
938
+ BEHIND the text via z-index: -1 without escaping <code>. */
939
+ pre.code-box.line-numbers > code { display: block; z-index: 0; }
940
+ /* Highlight overlay used by the log-message link click handler
941
+ and the clickable line-number gutter. Sits BEHIND the
942
+ syntax-highlighted text so the line stays maximally
943
+ readable. Persists until the user highlights a different
944
+ line or switches to a different tab (tab swap replaces
945
+ <code>'s textContent and the overlay with it). */
946
+ .line-flash {
947
+ position: absolute;
948
+ /* Extend by 0.8em on each side so the highlight covers the
949
+ full visual extent of any line — including the userscript
950
+ header band, which uses `margin: 0 -0.8em` to reach the
951
+ code-box's padding edges. */
952
+ left: -0.8em;
953
+ right: -0.8em;
954
+ pointer-events: none;
955
+ background: #fff3a6;
956
+ z-index: -1;
957
+ }
958
+ /* Vertical accent bar inside .line-flash. Rendered only when
959
+ the highlight came from a stack ref that carried a column;
960
+ inline `left:` is set to (col - 1) * char width so the bar
961
+ points at the reported character position. */
962
+ .line-flash-col-bar {
963
+ position: absolute;
964
+ top: 0;
965
+ bottom: 0;
966
+ width: 2px;
967
+ background: #f5b500;
968
+ pointer-events: none;
969
+ }
970
+ /* Make the line-numbers gutter behave like a clickable strip:
971
+ each line number highlights its row when clicked. The plugin
972
+ renders the numbers via `::before` on the span, so we set
973
+ pointer-events: auto on the span (default is `none` on the
974
+ parent rows) and add a hover affordance. */
975
+ .line-numbers .line-numbers-rows.clickable {
976
+ pointer-events: auto;
977
+ }
978
+ .line-numbers .line-numbers-rows.clickable > span {
979
+ cursor: pointer;
980
+ }
981
+ .line-numbers .line-numbers-rows.clickable > span:hover::before {
982
+ color: #1d4ed8;
983
+ font-weight: 600;
984
+ }
985
+ </style>
986
+ </head>
987
+ <body>
988
+ <!-- Shared glyph sprite: the one copy of every inline SVG glyph in the
989
+ extension. scripts/build.mjs inlines it into each page wherever the
990
+ page writes an `#include glyph-sprite` marker comment. (Spelling
991
+ that marker out here would be nice, but its own closing `--` plus
992
+ `>` would end THIS comment and spill the rest onto the page.)
993
+
994
+ One source of truth: the markup used to be copy-pasted into each
995
+ page's HTML, which is how two pages end up with glyphs that have
996
+ quietly drifted apart.
997
+
998
+ Each symbol is defined once per page and referenced by a `use`
999
+ element, so a hundred rows share one copy of the path data instead
1000
+ of inlining it per row.
1001
+
1002
+ #sm-globe favicon placeholder until a site icon loads, and
1003
+ the permanent icon for a script with no resolvable
1004
+ origin (src/extension/site-icon.ts; styling on
1005
+ `.site-icon-globe`).
1006
+ #sm-trash remove SourceMonkey's record of a script.
1007
+ #sm-trash-file delete the script FILE from disk — the same can,
1008
+ badged with a disk. Both painted by
1009
+ src/extension/delete-icon.ts, which explains the pair.
1010
+ The can is drawn ~19% smaller than #sm-trash — its
1011
+ own inner scale(.9) inside the normalizing
1012
+ wrapper's scale(.9) — so the badge has a corner to
1013
+ sit in without swallowing the can. Deliberate: the two appear in the same
1014
+ column in the "Other versions" panel, and the
1015
+ badged one has to stay a can at 15px.
1016
+ #sm-copy the viewer's "copy this to the clipboard" button,
1017
+ #sm-check and the checkmark it flashes on success
1018
+ (src/extension/copy-button.ts).
1019
+ #sm-refresh refetch a collection, a script, or one row of the
1020
+ "Other versions" table. Its busy state is this
1021
+ same arc spinning (`.btn-glyph.spinning`), so the
1022
+ button never changes shape mid-refresh.
1023
+ #sm-gear open a collection's rename / options dialog.
1024
+ #sm-open open a location in a new tab (the collection
1025
+ dialog's button beside its location box).
1026
+ #sm-swap the compare page's "swap the two sides" button:
1027
+ two arrows, one each way, the same width so their
1028
+ ends line up.
1029
+
1030
+ Colour comes from `currentColor`, so a button's own `color` (and
1031
+ its hover) drives the glyph.
1032
+
1033
+ OPTICAL SIZING — read before editing a path or a stroke width.
1034
+ Identical 16px boxes do not make icons look the same size; the ink
1035
+ inside them has to match too. As drawn, these ranged from 18 to
1036
+ 23.3 units of 24, and the gear read ~22% larger than the arrow. So
1037
+ a glyph that needed resizing is wrapped in
1038
+ <g transform="translate(12 12) scale(k) translate(-12 -12)">
1039
+ and its `stroke-width` is DIVIDED by the same k. Consequences:
1040
+ - The number in the file is not the number that renders. Every
1041
+ glyph here strokes at 1.75 units once its wrapper is applied
1042
+ (1.9/... , 1.95/.9, 1.667*1.05, 1.825*.959). Change a stroke
1043
+ width and you break that unless you change k with it.
1044
+ - #sm-refresh translates by -13, not -12: Feather's rotate-cw is
1045
+ drawn a unit right of centre, and this puts it back. It is not
1046
+ a typo.
1047
+ - #sm-copy and #sm-check are deliberately outside this: they
1048
+ stroke at 2.0 in the 14px copy button. That button sits beside
1049
+ the 1.75 set only in the collection dialog, next to #sm-open,
1050
+ where the smaller box evens out the heavier stroke. -->
1051
+ <svg width="0" height="0" style="position:absolute" aria-hidden="true">
1052
+ <symbol id="sm-globe" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"></circle><path d="M2 12h20"></path><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></symbol>
1053
+ <symbol id="sm-trash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 6h17"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path><path d="M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"></path><path d="M10 10.5v7"></path><path d="M14 10.5v7"></path></symbol>
1054
+ <symbol id="sm-trash-file" viewBox="0 0 24 24"><g transform="translate(12 12) scale(.9) translate(-12 -12)"><mask id="sm-trash-file-cut" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24"><rect width="24" height="24" fill="#fff"></rect><circle cx="19.6" cy="19.6" r="5.2" fill="#000"></circle></mask><g mask="url(#sm-trash-file-cut)" transform="translate(-.7 -1.5) scale(.9)" fill="none" stroke="currentColor" stroke-width="2.167" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 6h17"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path><path d="M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"></path><path d="M10 10.5v7"></path><path d="M14 10.5v7"></path></g><g transform="translate(14.53 14.36) scale(.422)" fill="none" stroke="currentColor" stroke-width="4.611" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"></ellipse><path d="M3 5v14c0 1.66 4.03 3 9 3s9-1.34 9-3V5"></path></g></g></symbol>
1055
+ <symbol id="sm-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></symbol>
1056
+ <symbol id="sm-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></symbol>
1057
+ <symbol id="sm-refresh" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.667" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(12 12) scale(1.05) translate(-13 -12)"><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path><polyline points="23 4 23 10 17 10"></polyline></g></symbol>
1058
+ <symbol id="sm-swap" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7.5h18"></path><path d="M16.5 3l4.5 4.5-4.5 4.5"></path><path d="M21 16.5H3"></path><path d="M7.5 12L3 16.5 7.5 21"></path></symbol>
1059
+ <symbol id="sm-gear" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.825" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(12 12) scale(.959) translate(-12 -12)"><circle cx="12" cy="12" r="3.1"></circle><path d="M19.4 14.6a1.6 1.6 0 0 0 .32 1.77l.06.06a1.95 1.95 0 1 1-2.76 2.76l-.06-.06a1.6 1.6 0 0 0-1.77-.32 1.6 1.6 0 0 0-.97 1.47V21a1.95 1.95 0 1 1-3.9 0v-.1a1.6 1.6 0 0 0-1.05-1.47 1.6 1.6 0 0 0-1.77.32l-.06.06a1.95 1.95 0 1 1-2.76-2.76l.06-.06a1.6 1.6 0 0 0 .32-1.77 1.6 1.6 0 0 0-1.47-.97H3a1.95 1.95 0 1 1 0-3.9h.1a1.6 1.6 0 0 0 1.47-1.05 1.6 1.6 0 0 0-.32-1.77l-.06-.06a1.95 1.95 0 1 1 2.76-2.76l.06.06a1.6 1.6 0 0 0 1.77.32H9a1.6 1.6 0 0 0 .97-1.47V3a1.95 1.95 0 1 1 3.9 0v.1a1.6 1.6 0 0 0 .97 1.47 1.6 1.6 0 0 0 1.77-.32l.06-.06a1.95 1.95 0 1 1 2.76 2.76l-.06.06a1.6 1.6 0 0 0-.32 1.77V9a1.6 1.6 0 0 0 1.47.97H21a1.95 1.95 0 1 1 0 3.9h-.1a1.6 1.6 0 0 0-1.47.97z"></path></g></symbol>
1060
+ <symbol id="sm-open" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><path d="M10 14L21 3"></path></symbol>
1061
+ </svg>
1062
+ <header class="page-header">
1063
+ <div class="page-header-inner">
1064
+ <a class="page-home page-icon-link" href="collections.html" target="_blank"
1065
+ rel="noopener" tabindex="-1" aria-hidden="true">
1066
+ <img class="page-icon" src="icons/icon-48.png" alt="" />
1067
+ </a>
1068
+ <!-- `tabindex="-1"` so in-page navigation between copies can move
1069
+ focus here: the heading, the details, and the code all change
1070
+ with no document load for a screen reader to announce. Not
1071
+ reachable by Tab, and it draws no focus ring (see the h1 rule
1072
+ in the stylesheet above). -->
1073
+ <!-- The brand run ships in the markup, so the bar reads
1074
+ "SourceMonkey |" from the document's own first paint rather
1075
+ than after any script has run. Exactly what
1076
+ `headingPrefixEl(INSTALLED_HEADING)` builds (src/extension/page-heading.ts),
1077
+ so when the heading is rendered for real this part of it does
1078
+ not move: the installed page repaints the same link and
1079
+ separator, and the install page appends its "Install |"
1080
+ after them.
1081
+ The product name is a link home to the collections page.
1082
+ It carries a real href and `target` so a click before
1083
+ `userscript.js` has run still opens a new tab; once the
1084
+ page's delegated handler is installed (installHomeLinkHandler,
1085
+ src/extension/page-links.ts) the click goes to the NAMED collections
1086
+ tab instead. -->
1087
+ <h1 id="filename" tabindex="-1"><a class="heading-prefix brand page-home" href="collections.html"
1088
+ target="_blank" rel="noopener" title="Open the collections page">SourceMonkey</a><span class="heading-prefix brand"> | </span></h1>
1089
+ </div>
1090
+ </header>
1091
+ <div class="page-main">
1092
+ <!-- Banner + versions panel, directly under the title and ABOVE the
1093
+ controls row: which copies of this script exist is the first
1094
+ thing either mode has to answer, and every control below acts
1095
+ on the one copy this page is showing. In the preview's
1096
+ "already installed" case the two are merged into one box (the
1097
+ `merged` class) — see `renderInstalledBanner`. -->
1098
+ <div id="status-box">
1099
+ <!-- In preview mode (`?preview=<url>`) the banner says what this
1100
+ file is relative to what's installed, and the action row asks
1101
+ the install / update question; the action row stays hidden for
1102
+ an installed script, which uses the controls row below. The
1103
+ banner slot is shared with the file-access banner, which either
1104
+ mode can raise when a local read fails. -->
1105
+ <div id="banner-slot"></div>
1106
+ <div id="other-versions"></div>
1107
+ </div>
1108
+ <div id="meta-row" class="meta-row" hidden>
1109
+ <label id="enable-label" class="toggle" title="Enable this script">
1110
+ <input id="enable-checkbox" type="checkbox" />
1111
+ <span>Enabled</span>
1112
+ </label>
1113
+ <!-- Local copy… and the delete trash can, filled per render
1114
+ (`makeScriptActions`). Empty until the first one, and the
1115
+ row it is in stays hidden until then. -->
1116
+ <span id="meta-actions" class="meta-actions"></span>
1117
+ <!-- Icon-only; the glyph is painted by src/extension/userscript.ts
1118
+ (setGlyphButton), which is safe to leave empty here
1119
+ because #meta-row ships `hidden` and is only revealed
1120
+ once the script has loaded. -->
1121
+ <button id="refresh-btn" type="button"></button>
1122
+ </div>
1123
+ <!-- Install stays hidden until the fetch has landed and we know
1124
+ whether this file is installable and not already installed,
1125
+ so it is never clickable without a handler behind it. The
1126
+ dropdown is filled per preview (see `showInstallCallout`); it
1127
+ is absent for a location with no single-file spelling, where
1128
+ Install adds a whole collection instead. -->
1129
+ <div id="install-callout" class="install-callout" hidden>
1130
+ <button id="install-btn" class="primary" type="button">Install</button>
1131
+ <label id="install-target-label" for="install-target">into</label>
1132
+ <span id="install-target-slot"></span>
1133
+ </div>
1134
+ <div id="preview-actions" class="actions" hidden>
1135
+ <button id="open-btn" type="button" hidden>Open installed script</button>
1136
+ <button id="continue-btn" class="primary" type="button" hidden
1137
+ title="Open this location in the browser, without previewing it">Continue to page</button>
1138
+ <button id="cancel-btn" type="button">Cancel</button>
1139
+ <button id="view-source-btn" class="spacer" type="button" title="Open the unprocessed file in a new tab">View raw source</button>
1140
+ </div>
1141
+ <p id="message" class="message"></p>
1142
+ <div id="header-summary"></div>
1143
+ <div id="tabs" class="tabs" role="tablist" hidden></div>
1144
+ <pre id="code-pane" class="code-box line-numbers" tabindex="0"><code id="content" class="language-javascript"></code></pre>
1145
+ <div id="log-pane" class="log-pane" tabindex="0" role="tabpanel" hidden></div>
1146
+ </div>
1147
+ <!-- `defer`, not blocking: a synchronous script here stalls parsing,
1148
+ and everything deferred — page-heading.js included — has to wait
1149
+ for parsing to finish. That put the header bar's name a couple
1150
+ of frames behind the page's first paint. Deferred scripts still
1151
+ run in document order, so Prism is still defined before
1152
+ userscript.js evaluates.
1153
+
1154
+ `data-manual` stands Prism's own automatic highlightAll() pass
1155
+ down. Nothing wanted it — code-tabs.ts highlights the code box
1156
+ itself, once it has code to highlight — and deferring changed
1157
+ WHEN that pass fires (readyState is no longer `loading`, so
1158
+ Prism schedules it on a frame instead of DOMContentLoaded). A
1159
+ pass that rebuilt the block from its textContent would drop the
1160
+ <a> elements code-links.ts puts in. -->
1161
+ <script src="vendor/prism/prism.js" data-manual defer></script>
1162
+ <script src="vendor/prism/prism-line-numbers.js" defer></script>
1163
+ <script src="extension/userscript.js" type="module"></script>
1164
+ </body>
1165
+ </html>