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,825 @@
1
+ /* Shared stylesheet linked from every SourceMonkey extension page
2
+ (collections.html, options.html, userscript.html). Pages still carry
3
+ their own page-specific styles in a <style> block; rules here are
4
+ for elements that show up on more than one page. New cross-page
5
+ styles belong in this file rather than copy-pasted into each
6
+ <style> block.
7
+
8
+ Currently shared:
9
+ - the collection-type bubble + its display-name sibling (DOM helper in
10
+ src/extension/collection-display.ts, used on the collections page heading and the
11
+ userscript viewer's Collection row), and the per-row scheme chip a
12
+ script wears inside a scripts collection;
13
+ - the warning banner box, whose file-access variant (DOM helper in
14
+ src/extension/file-access.ts) renders on both the collections page and the
15
+ viewer / install preview;
16
+ - the modal dialog shell, shared by the create / edit collection
17
+ dialog (src/extension/collection-dialog.ts) and the move-script dialog
18
+ (src/extension/move-dialog.ts);
19
+ - the "Install into" dropdown (src/extension/related-versions.ts), in the
20
+ install page's callout and its versions table;
21
+ - the removal buttons' glyph sizing and destructive colour
22
+ (src/extension/delete-icon.ts), on every page that has a remove button;
23
+ - the icon-button layout and spin state (src/extension/glyph.ts), shared by
24
+ the Refresh / options buttons on the collections page and the
25
+ viewer. */
26
+
27
+ /* Warning banner. Pages keep their own margin and colour variants
28
+ (`.banner.installed` on the viewer) in their
29
+ <style> block; everything below is common to every banner. */
30
+ .banner {
31
+ border: 1px solid #d97706;
32
+ background: #fffbeb;
33
+ padding: 10px 14px;
34
+ border-radius: 6px;
35
+ margin-bottom: 10px;
36
+ }
37
+
38
+ .banner strong { display: block; margin-bottom: 4px; }
39
+
40
+ /* A banner for something that stops scripts running, not a warning: red,
41
+ as the popup's bar for the same problem. */
42
+ .banner.banner-error { border-color: #e57373; background: #fdecea; color: #b71c1c; }
43
+ .banner.banner-error a { color: inherit; }
44
+
45
+ .banner p { margin: 4px 0; line-height: 16px; }
46
+
47
+ /* The `chrome://extensions/?id=…` link a permission banner can end
48
+ with. Styled as inline code because that's what it is — an address
49
+ the user may prefer to copy rather than click. */
50
+ .banner a.chrome-link {
51
+ display: inline-block;
52
+ background: #fef3c7;
53
+ padding: 0.15em 0.4em;
54
+ border-radius: 3px;
55
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
56
+ color: #92400e;
57
+ text-decoration: none;
58
+ }
59
+
60
+ .banner a.chrome-link { cursor: pointer; }
61
+ .banner a.chrome-link:hover { text-decoration: underline; }
62
+
63
+ /* A setting's name in a banner sentence: marked, but no bigger or
64
+ louder than the text around it. */
65
+ .banner code {
66
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
67
+ font-size: 0.9em;
68
+ }
69
+
70
+ .collection-display-name {
71
+ /* Prefer space / slash boundaries when wrapping. `<wbr>` markers
72
+ inserted after each `/` (see appendWithSlashBreaks in
73
+ src/extension/collection-display.ts) give the browser preferred break points
74
+ before it has to break inside a word. */
75
+ overflow-wrap: anywhere;
76
+ word-break: normal;
77
+ min-width: 0;
78
+ }
79
+
80
+ .collection-type-bubble {
81
+ display: inline-block;
82
+ padding: 1px 8px;
83
+ border-radius: 10px;
84
+ font-size: 11px;
85
+ font-weight: 600;
86
+ text-transform: uppercase;
87
+ letter-spacing: 0.04em;
88
+ color: #fff;
89
+ text-decoration: none;
90
+ /* Whole px: 1.5 x 11px = 16.5 would make its whole row fractional. */
91
+ line-height: 16px;
92
+ white-space: nowrap;
93
+ flex: 0 0 auto;
94
+ }
95
+ .collection-type-bubble:hover { opacity: 0.85; }
96
+
97
+ /* Kind + scheme: `-dir` in the scheme's base hue, `-manifest` darker,
98
+ and a neutral grey for a scripts collection, which has no scheme of
99
+ its own. `http-dir` is unreachable through the add paths (a plain
100
+ web directory can't be listed) but a legacy or hand-written row
101
+ still renders, and a bubble with no rule would be white on white. */
102
+ .bubble-file-dir { background: #d97706; }
103
+ .bubble-http-dir { background: #2563eb; }
104
+ .bubble-file-manifest { background: #92400e; }
105
+ .bubble-http-manifest { background: #1e3a8a; }
106
+ .bubble-github-dir { background: #6f42c1; }
107
+ .bubble-github-manifest { background: #4c2889; }
108
+ .bubble-scripts { background: #4b5563; }
109
+ /* An sm-dev run's test collection: a darker shade of the cyan "T" on
110
+ the toolbar icon in sm-dev's tabs, dark enough for white text. */
111
+ .bubble-sm-dev { background: #00838f; }
112
+ /* Form states, not collection kinds — only the collection dialog's Type
113
+ row ever wears these: red for a location (or an empty form) that
114
+ can't become a collection, grey while its verdict is being fetched. */
115
+ .bubble-invalid { background: #b00; }
116
+ .bubble-checking { background: #9ca3af; }
117
+
118
+ /* The per-row scheme chip inside a scripts collection: the same hues
119
+ as the bubbles, smaller, so a mixed collection still says where each
120
+ script loads from. */
121
+ .scheme-chip {
122
+ display: inline-block;
123
+ min-width: 2.2em;
124
+ text-align: center;
125
+ padding: 0 5px;
126
+ border-radius: 8px;
127
+ font-size: 10px;
128
+ font-weight: 600;
129
+ text-transform: uppercase;
130
+ letter-spacing: 0.04em;
131
+ color: #fff;
132
+ line-height: 14px;
133
+ white-space: nowrap;
134
+ }
135
+ .chip-file { background: #d97706; }
136
+ .chip-http { background: #2563eb; }
137
+ .chip-github { background: #6f42c1; }
138
+ .chip-scratch { background: #0f766e; }
139
+
140
+ /* ---- Modal dialog shell ---- */
141
+ /* `.sm-dialog` is the shell — frame, title bar, body grid, error slot,
142
+ action row — shared by the create / edit collection dialog
143
+ (src/extension/collection-dialog.ts) and the move-script dialog
144
+ (src/extension/move-dialog.ts). Each dialog also carries its own identity
145
+ class, which is what page code and tests select on. */
146
+ dialog.sm-dialog {
147
+ border: 1px solid #bbb;
148
+ border-radius: 8px;
149
+ padding: 0;
150
+ width: 520px;
151
+ max-width: calc(100vw - 2em);
152
+ color: #222;
153
+ font: 14px system-ui, sans-serif;
154
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
155
+ background: #fff;
156
+ box-sizing: border-box;
157
+ }
158
+ dialog.sm-dialog::backdrop { background: rgba(20, 24, 32, 0.35); }
159
+ /* Wider than the shared default: every row here can hold a long name
160
+ or path — the collection name, the file name with its subdirectory,
161
+ each dependency's path, the description. */
162
+ dialog.sm-dialog.copy-dialog { width: 680px; }
163
+ /* Same reason as the copy dialog: every row holds a path. */
164
+ dialog.sm-dialog.delete-dialog { width: 680px; }
165
+ /* Its result line can hold the saved file's whole path. */
166
+ dialog.sm-dialog.export-dialog { width: 560px; }
167
+ .export-dialog .dlg-intro { grid-column: 1 / -1; margin: 0; }
168
+ /* Checkbox, then label, with the hint under the label rather than under
169
+ the checkbox. The label is `display: contents` so its checkbox and
170
+ text sit in the grid's columns and a click on the text still ticks. */
171
+ .export-dialog .dlg-option { display: grid; grid-template-columns: auto 1fr; column-gap: 6px; align-items: baseline; }
172
+ .export-dialog .dlg-option .dlg-check { display: contents; }
173
+ .export-dialog .dlg-option .dlg-hint { grid-column: 2; }
174
+ .export-dialog .dlg-includes { display: flex; flex-direction: column; gap: 8px; padding-top: 5px; }
175
+ .export-dialog .dlg-result { grid-column: 1 / -1; overflow-wrap: anywhere; }
176
+ .export-dialog .dlg-result[hidden] { display: none; }
177
+ .export-dialog .dlg-result p { margin: 0 0 4px; }
178
+ .export-dialog .dlg-saved-path { overflow-wrap: anywhere; }
179
+ .export-dialog .dlg-saved .copy-btn { display: inline-flex; vertical-align: middle; width: 20px; height: 20px; margin-left: 0.4em; }
180
+ .sm-dialog .dlg-title {
181
+ font-size: 1em;
182
+ font-weight: 600;
183
+ margin: 0;
184
+ padding: 12px 16px;
185
+ border-bottom: 1px solid #e5e7eb;
186
+ }
187
+ .sm-dialog .dlg-body {
188
+ margin: 0;
189
+ padding: 14px 16px 4px;
190
+ display: grid;
191
+ grid-template-columns: max-content 1fr;
192
+ column-gap: 12px;
193
+ row-gap: 12px;
194
+ align-items: start;
195
+ }
196
+ .sm-dialog .dlg-label { padding-top: 5px; color: #444; }
197
+ /* Slot for a control the dialog rebuilds per open. Fills its grid
198
+ column the way the collection dialog's text inputs do. */
199
+ .sm-dialog .dlg-slot { min-width: 0; }
200
+ .sm-dialog .dlg-slot select { width: 100%; font: inherit; padding: 4px 7px; }
201
+ .sm-dialog .dlg-label[hidden] { display: none; }
202
+ /* The location box with its copy and open-in-a-new-tab buttons. It and
203
+ its label centre on each other: the label can take two lines. */
204
+ .sm-dialog .dlg-location { display: flex; gap: 6px; align-items: center; min-width: 0; align-self: center; }
205
+ .sm-dialog .dlg-location-label { align-self: center; padding-top: 0; }
206
+ .sm-dialog .dlg-location[hidden] { display: none; }
207
+ .sm-dialog .dlg-location input { flex: 1; min-width: 0; }
208
+ /* Its two buttons are one pair: the open button takes the copy
209
+ button's look (square, white, its border and hover) rather than the
210
+ page's grey, padded `.icon-btn`. */
211
+ .sm-dialog .dlg-location .copy-btn,
212
+ .sm-dialog .dlg-location .dlg-open-location {
213
+ width: var(--icon-btn-size);
214
+ min-width: 0;
215
+ height: var(--icon-btn-size);
216
+ padding: 0;
217
+ border: 1px solid #bbb;
218
+ border-radius: 3px;
219
+ background: #fff;
220
+ color: #444;
221
+ }
222
+ .sm-dialog .dlg-location button:hover:not(:disabled) { background: #eee; }
223
+ .sm-dialog .dlg-location button:active:not(:disabled) { background: #ddd; }
224
+ .sm-dialog .dlg-location button:disabled { cursor: default; opacity: 0.5; }
225
+ .sm-dialog input[type="text"],
226
+ .sm-dialog textarea {
227
+ width: 100%;
228
+ box-sizing: border-box;
229
+ font: inherit;
230
+ padding: 4px 7px;
231
+ }
232
+ /* A one-line box that grows to fit its value — `autoGrow` sets the
233
+ height, these bound it. Whole-px line metrics so N lines is an exact
234
+ height: 19 + 8 padding + 2 border = 29px for one line, 86px for the
235
+ four this caps at, after which it scrolls. Not user-resizable: the
236
+ content already decides the height. */
237
+ .sm-dialog textarea {
238
+ line-height: 19px;
239
+ min-height: 29px;
240
+ max-height: 86px;
241
+ resize: none;
242
+ overflow-y: auto;
243
+ }
244
+ .sm-dialog input[type="text"][hidden] { display: none; }
245
+ .sm-dialog input[type="text"]:disabled {
246
+ background: #f3f4f6;
247
+ color: #666;
248
+ border-color: #d1d5db;
249
+ }
250
+ /* `border-style` too: the UA gives text inputs an inset border, and
251
+ recolouring an inset border shades each side a different tint. */
252
+ .sm-dialog input[type="text"].invalid { border-style: solid; border-color: #b00; outline-color: #b00; }
253
+ /* The Type row: the inferred bubble, plus a hint for the one state
254
+ that has nothing to report in the error slot yet. */
255
+ .sm-dialog .dlg-type { display: flex; gap: 8px; align-items: baseline; padding-top: 3px; }
256
+ /* The shared bubble dims on hover because everywhere else it is a link.
257
+ This one is a report, not a target. */
258
+ .sm-dialog .dlg-type .collection-type-bubble:hover { opacity: 1; }
259
+ .sm-dialog .dlg-check {
260
+ display: flex;
261
+ gap: 6px;
262
+ align-items: baseline;
263
+ cursor: pointer;
264
+ }
265
+ .sm-dialog .dlg-check input { margin: 0; position: relative; top: 1px; flex: 0 0 auto; }
266
+ .sm-dialog .dlg-hint { color: #666; font-size: 0.85em; }
267
+ .sm-dialog .dlg-check.off { opacity: 0.5; cursor: default; }
268
+ .sm-dialog .dlg-error-row {
269
+ display: flex;
270
+ gap: 8px;
271
+ align-items: baseline;
272
+ padding: 8px 16px 0;
273
+ }
274
+ .sm-dialog .dlg-error {
275
+ color: #b00;
276
+ /* Messages that name a file and then say what to do put the two on
277
+ separate lines. Every other message is one line and unaffected. */
278
+ white-space: pre-line;
279
+ margin: 0;
280
+ min-height: 1.3em;
281
+ line-height: 1.3;
282
+ }
283
+ .sm-dialog .dlg-error.warn { color: #92400e; }
284
+ /* Offered inside the error line — today only "Install script", under
285
+ the "this is a single script" verdict. Its own height: this sits
286
+ INSIDE a line of message text, so the shared button height would
287
+ grow the error row around it. */
288
+ .sm-dialog .dlg-error-action {
289
+ height: 18px;
290
+ font: inherit;
291
+ padding: 1px 8px;
292
+ cursor: pointer;
293
+ flex: 0 0 auto;
294
+ }
295
+ .sm-dialog .dlg-error-action[hidden] { display: none; }
296
+ /* Copy dialog (src/extension/copy-dialog.ts): read-only values in the body
297
+ grid, the dependency list under its checkbox, and the file-access
298
+ banner slot above the form. */
299
+ .sm-dialog .dlg-static { padding-top: 5px; min-width: 0; overflow-wrap: anywhere; }
300
+ .sm-dialog .dlg-target-name { font-weight: 600; }
301
+ .sm-dialog .dlg-banner:empty { display: none; }
302
+ .sm-dialog .dlg-banner { padding: 12px 16px 0; }
303
+ .sm-dialog .dlg-banner > * { margin: 0; }
304
+ .sm-dialog .dlg-deps { min-width: 0; padding-top: 3px; }
305
+ .sm-dialog .dlg-deps .dlg-hint { margin-top: 3px; }
306
+ /* The delete dialog's headed lists (src/extension/delete-dialog.ts): one block
307
+ per reason, stacked, each hidden whole when it holds no files.
308
+ Scoped to that dialog — the copy dialog builds its checkbox and list
309
+ inside a `.dlg-deps` of its own, and stacking that one would move a
310
+ row this feature has no business touching. */
311
+ .delete-dialog .dlg-deps { display: flex; flex-direction: column; gap: 8px; }
312
+ /* Beats the `display: flex` above, which would otherwise leave a script
313
+ with no dependency files an empty grid row and its row-gap. */
314
+ .delete-dialog .dlg-deps[hidden] { display: none; }
315
+ .delete-dialog .dlg-dep-group[hidden] { display: none; }
316
+ .delete-dialog .dlg-dep-group .dlg-hint { margin-top: 0; }
317
+ /* A path + its copy button on one line: the script file's full path,
318
+ and each dependency file in the lists below it. */
319
+ .delete-dialog .dlg-path-row { display: flex; align-items: center; gap: 0.4em; }
320
+ .delete-dialog .dlg-path-row > span { overflow-wrap: anywhere; }
321
+ /* `display: flex` on an `li` drops its marker; `list-item` inside the
322
+ flex row would break the layout, so the bullet comes back as a
323
+ pseudo-element. */
324
+ .delete-dialog li.dlg-path-row { list-style: none; position: relative; }
325
+ .delete-dialog li.dlg-path-row::before { content: '•'; position: absolute; left: -1em; }
326
+ /* One size everywhere in the dialog: the rows differ in font size, so
327
+ the button's `em` sizing would otherwise differ with them. */
328
+ .delete-dialog .dlg-path-row .copy-btn { width: 20px; height: 20px; }
329
+ .sm-dialog .dlg-deps-list {
330
+ margin: 4px 0 0;
331
+ padding-left: 1.2em;
332
+ font-size: 0.85em;
333
+ color: #444;
334
+ max-height: 6.5em;
335
+ overflow-y: auto;
336
+ }
337
+ .sm-dialog .dlg-deps-list:empty { display: none; }
338
+ /* A dependency file the copy would overwrite, marked in the list. The
339
+ warning colour, not the error one: the same fact the line at the
340
+ bottom of the dialog reports, and Replace is a choice, not a fault. */
341
+ .sm-dialog .dlg-exists { color: #92400e; }
342
+ /* A second line under a field's label, for what it accepts that its
343
+ name doesn't say. */
344
+ .sm-dialog .dlg-label-note { display: block; font-size: 0.85em; color: #666; }
345
+ /* A heading INSIDE the body grid, spanning both its columns. */
346
+ .sm-dialog .dlg-section { grid-column: 1 / -1; font-weight: 600; }
347
+ /* `<original> -> [new value]` in one field row. */
348
+ .sm-dialog .dlg-arrow { display: flex; gap: 7px; align-items: center; min-width: 0; }
349
+ .sm-dialog .dlg-arrow input[type="text"] { flex: 1 1 auto; min-width: 0; }
350
+ /* The old value is shown in full, never elided. It takes exactly the
351
+ width its text needs (`flex-shrink: 0`, so the box beside it gives
352
+ way first rather than the two splitting the squeeze and wrapping it
353
+ mid-version as `1.0.` / `6`), and stops at half the row — a version
354
+ longer than that wraps inside its half. */
355
+ .sm-dialog .dlg-was {
356
+ flex: 0 0 auto;
357
+ max-width: 50%;
358
+ overflow-wrap: anywhere;
359
+ }
360
+ .sm-dialog .dlg-arrow-mark { color: #666; flex: 0 0 auto; }
361
+ /* Copy's dependency hint + list while the box is unticked: what would
362
+ happen, not what will. Same dimming as the unavailable checkbox. */
363
+ .sm-dialog .dimmed { opacity: 0.5; }
364
+ .sm-dialog .dlg-deps-list li { overflow-wrap: anywhere; }
365
+ .sm-dialog .dlg-actions {
366
+ display: flex;
367
+ justify-content: flex-end;
368
+ align-items: center;
369
+ gap: 8px;
370
+ padding: 12px 16px 14px;
371
+ }
372
+ .sm-dialog .dlg-actions button { padding: 0 11px; }
373
+ .sm-dialog .dlg-actions button.primary { font-weight: 600; }
374
+ /* The confirm of a dialog that destroys something (src/extension/delete-dialog.ts).
375
+ Coloured, not just bold: the button is one click from files leaving
376
+ the disk with nothing to undo it. */
377
+ .sm-dialog .dlg-actions button.danger { color: #b00; }
378
+ @keyframes sm-spin { to { transform: rotate(360deg); } }
379
+ .sm-dialog .busy-spinner {
380
+ display: inline-block;
381
+ width: 12px;
382
+ height: 12px;
383
+ border: 2px solid #ccc;
384
+ border-top-color: #555;
385
+ border-radius: 50%;
386
+ animation: sm-spin 0.7s linear infinite;
387
+ box-sizing: border-box;
388
+ }
389
+
390
+ /* ---- "Install into" dropdown (src/extension/related-versions.ts) ---- */
391
+ /* Ellipsised, not clipped: the control gives way to its neighbours
392
+ where a collection name is longer than the row (see the install
393
+ callout and the panel's offer row), and Chrome sizes the OPEN list
394
+ to its widest option, so the full name is still readable there. */
395
+ select.install-target {
396
+ font: inherit;
397
+ padding: 3px 6px;
398
+ max-width: 100%;
399
+ text-overflow: ellipsis;
400
+ }
401
+
402
+ /* ---- Icon buttons (src/extension/glyph.ts, src/extension/delete-icon.ts) ---- */
403
+
404
+ /* Every button whose content is a glyph — the removal cans, the
405
+ refresh arrow, the options gear — is one control with one look, on
406
+ every page. `.icon-btn` is put on by the code that paints the glyph,
407
+ so a button can't get the icon without the box.
408
+
409
+ The box is SET, not inferred. Letting each button size itself off
410
+ its content is what gave five identically-sized icons five different
411
+ button widths: three padding values, a text arrow measuring
412
+ differently from an SVG, and `align-self: stretch` on one of them.
413
+ Here the height and the glyph are both fixed, so every icon button
414
+ in a row lines up by construction, and the whole-pixel rule for the
415
+ collections page and the versions panel (docs/architecture.md,
416
+ "Extension-page styling") falls out for free — no `em` in any
417
+ vertical metric.
418
+
419
+ A dense context can shrink the pair by redefining the two custom
420
+ properties on an ancestor; nothing else needs to change. */
421
+ :root {
422
+ --icon-btn-size: 26px;
423
+ --icon-btn-glyph: 16px;
424
+ /* One button surface for every page. Chrome's own button paints no
425
+ hover or press state once an author background is set, and setting
426
+ one on only SOME buttons (the removal cans' red hover) left a row
427
+ where half the controls reacted to the pointer and half didn't.
428
+ So the whole progression is ours, and it only ever gets darker:
429
+ rest -> hover -> pressed. */
430
+ --btn-bg: #f6f6f6;
431
+ --btn-bg-hover: #e7e7e7;
432
+ --btn-bg-active: #d6d6d6;
433
+ --btn-border: #bbb;
434
+ --btn-fg: #222;
435
+ /* The destructive pair, same direction of travel. */
436
+ --btn-bg-danger-hover: #f5c2c7;
437
+ --btn-bg-danger-active: #e9a3ab;
438
+ --btn-fg-danger: #a3372c;
439
+ }
440
+
441
+ /* THE button surface, for every button in the extension — both pages,
442
+ the Options page, and every dialog. Anything that does not opt out
443
+ rests, hovers and presses the same, and the press is always DARKER
444
+ than the hover, never lighter.
445
+
446
+ `:where()` puts the whole thing at zero specificity, which is what
447
+ makes it safe to apply this broadly: it is a baseline, not an
448
+ override. Any class rule beats it, so a control keeps whatever it
449
+ sets for itself — but only what it actually sets. A rule that
450
+ declares a background and no height gets its own background and
451
+ THIS height; the fold triangle and the code tabs each pin a height
452
+ because of that, not by default.
453
+
454
+ Chrome paints no hover or press state on a native button, and the
455
+ moment any author background is set it stops painting one at all.
456
+ So this is not decoration: without it, whether a button reacts to
457
+ being pressed depended on whether some page had happened to style
458
+ it. */
459
+ :where(button) {
460
+ /* One height too, not just one surface. A button that isn't in some
461
+ hand-kept list of selectors still has to line up with the ones
462
+ beside it — the alternative is finding them one at a time. A
463
+ control that genuinely needs another size sets its own `height`
464
+ in a class rule, which (like everything here) outranks this. */
465
+ box-sizing: border-box;
466
+ height: var(--icon-btn-size);
467
+ font: inherit;
468
+ line-height: 1;
469
+ border: 1px solid var(--btn-border);
470
+ border-radius: 3px;
471
+ background: var(--btn-bg);
472
+ color: var(--btn-fg);
473
+ cursor: pointer;
474
+ }
475
+ :where(button:hover:not(:disabled)) { background: var(--btn-bg-hover); }
476
+ :where(button:active:not(:disabled)) { background: var(--btn-bg-active); }
477
+ :where(button:disabled) { cursor: not-allowed; opacity: 0.5; }
478
+ /* The blue ring the rest of the extension already uses (the code tabs,
479
+ the copy button, the panel's rows). The removal buttons carried their
480
+ own copy of this before their per-page rules were folded in here; a
481
+ glyph has no shape of its own to show focus with, so it can't be left
482
+ to the UA's. */
483
+ :where(button:focus-visible) { outline: 2px solid #4a90e2; outline-offset: 1px; }
484
+
485
+ /* `font: inherit` above takes the bold from a `<th>`, and the versions
486
+ table's "Refresh all" sits in a header cell. */
487
+ .versions-table button { font-weight: 400; }
488
+
489
+ /* What makes it an ICON button, on top of the shared surface above:
490
+ a square minimum so a lone glyph gets a box rather than a slot, and
491
+ centring for the glyph (plus a label, where it has one). */
492
+ .icon-btn {
493
+ min-width: var(--icon-btn-size);
494
+ padding: 0 6px;
495
+ /* Snug around a lone glyph; a labelled one takes the roomier padding
496
+ of the text buttons it sits beside (`.icon-btn` is a class and
497
+ would otherwise outrank a page's own `button` rule). */
498
+ display: inline-flex;
499
+ align-items: center;
500
+ justify-content: center;
501
+ gap: 0.4em;
502
+ vertical-align: middle;
503
+ }
504
+ .icon-btn:has(.btn-label) { padding: 0 11px; }
505
+ /* An author `display` outranks the UA's `[hidden] { display: none }`,
506
+ and this codebase does hide buttons with the attribute. */
507
+ .icon-btn[hidden] { display: none; }
508
+ .icon-btn:disabled { cursor: not-allowed; opacity: 0.4; }
509
+
510
+ /* The glyph fills a fixed square inside that box; it never sizes off
511
+ the font, so a button in 13px text and one in 14px text still hold
512
+ the same icon. */
513
+ .icon-btn .btn-glyph,
514
+ .icon-btn .delete-icon {
515
+ width: var(--icon-btn-glyph);
516
+ height: var(--icon-btn-glyph);
517
+ display: block;
518
+ flex: none;
519
+ }
520
+
521
+ /* Destructive: the removal cans hover red, and the one that deletes a
522
+ FILE also rests red. Shape (the disk badge on its glyph) and colour
523
+ both say it, because colour on its own isn't a cue every user gets. */
524
+ .icon-btn.remove-script:hover:not(:disabled),
525
+ .icon-btn.versions-remove:hover:not(:disabled) {
526
+ background: var(--btn-bg-danger-hover);
527
+ color: #b00;
528
+ }
529
+ .icon-btn.remove-script:active:not(:disabled),
530
+ .icon-btn.versions-remove:active:not(:disabled) { background: var(--btn-bg-danger-active); }
531
+ .icon-btn.deletes-file { color: var(--btn-fg-danger); }
532
+
533
+ /* In-flight. The glyph spins in place instead of the label changing to
534
+ "Refreshing…" — an icon-only button has no label to change, and a
535
+ fixed box means nothing moves while it spins. */
536
+ .btn-glyph.spinning {
537
+ animation: sm-spin 1.1s linear infinite;
538
+ transform-origin: 50% 50%;
539
+ }
540
+ @media (prefers-reduced-motion: reduce) {
541
+ .btn-glyph.spinning { animation: none; opacity: 0.55; }
542
+ }
543
+
544
+ /* ---- Page header bar (every extension page) ---- */
545
+
546
+ /* One bar across the top of every page: the extension icon, the
547
+ "SourceMonkey | <page>" heading, and whatever cross-page navigation
548
+ that page offers, pushed to the right edge.
549
+
550
+ Brown rather than the obvious green: the bar sits directly above the
551
+ viewer's green "Other versions" card and the amber warning banner
552
+ slot, and a green bar would read as the top of that card. Brown is
553
+ where the monkey icon's own colours live, and it is desaturated
554
+ enough not to be mistaken for the amber banner. */
555
+ :root {
556
+ --brand-fg: #6b4423;
557
+ --header-bg: #f2e9dc;
558
+ --header-border: #b59a78;
559
+ /* The content column every page centres. The bar's contents honour
560
+ it too, so the heading starts at the same x as the page body
561
+ underneath rather than at the window edge. Pages that run
562
+ full-bleed (the viewer) leave it unset. */
563
+ --page-width: none;
564
+ }
565
+
566
+ /* Full-bleed background; the inner row is what gets constrained. The
567
+ 16px side padding matches the page body's, so the two content edges
568
+ line up at every window width. */
569
+ .page-header {
570
+ background: var(--header-bg);
571
+ border-bottom: 1px solid var(--header-border);
572
+ padding: 0 16px;
573
+ }
574
+
575
+ .page-header-inner {
576
+ display: flex;
577
+ align-items: center;
578
+ gap: 10px;
579
+ /* Whole pixels, like the rest of the vertical metrics — see
580
+ docs/architecture.md, "Extension-page styling". */
581
+ padding: 8px 0;
582
+ max-width: var(--page-width);
583
+ margin: 0 auto;
584
+ }
585
+
586
+ .page-icon {
587
+ flex: 0 0 auto;
588
+ width: 24px;
589
+ height: 24px;
590
+ }
591
+
592
+ /* The heading takes the row's slack so the actions sit at the right
593
+ edge; `min-width: 0` lets a long script name wrap instead of
594
+ pushing them off. */
595
+ .page-header h1 {
596
+ flex: 1 1 auto;
597
+ min-width: 0;
598
+ margin: 0;
599
+ font-size: 1.15em;
600
+ font-weight: 700;
601
+ color: #222;
602
+ }
603
+
604
+ /* The product name and the separators after it, in the brand colour —
605
+ the same split the icon makes visually. The page name between or after
606
+ them stays in the heading's own colour.
607
+
608
+ Two shapes wear it, both rendering the same thing:
609
+ - Collections and Options spell it in their markup, as one span
610
+ around `SourceMonkey |`.
611
+ - The viewer builds it (`headingPrefixEl`, src/extension/page-heading.ts), a
612
+ span per term, because its heading has a page name in the middle
613
+ ("SourceMonkey | Install | <script>"). Those spans wear
614
+ `.heading-prefix` as well. */
615
+ .page-header h1 .brand { color: var(--brand-fg); }
616
+
617
+ /* The icon and the product name are a link home to the collections
618
+ page (src/extension/page-links.ts). Styled to look like the bar, not like a
619
+ link: it is chrome, and underlining it permanently would read as an
620
+ error. The underline on hover is what says it is clickable.
621
+
622
+ Deliberately NO colour here. The product name is `.brand` inside the
623
+ `<h1>`, so the rule above already paints it, and a `color` on this
624
+ selector would tie with that one on specificity and win on source
625
+ order — leaving a near-black "SourceMonkey" beside a brown `|`. */
626
+ .page-header a.page-home { text-decoration: none; }
627
+ .page-header a.page-home:hover { text-decoration: underline; }
628
+
629
+ /* The icon's wrapper: flex so the anchor is exactly the image's box
630
+ with no inline-layout gap under it, and `flex: 0 0 auto` because the
631
+ anchor is now the row's item, not the image. It sits outside the
632
+ `<h1>`, so nothing else colours it and the link blue has to be
633
+ turned off here. */
634
+ .page-header .page-icon-link {
635
+ flex: 0 0 auto;
636
+ display: flex;
637
+ color: inherit;
638
+ }
639
+
640
+ .page-header-actions {
641
+ flex: 0 0 auto;
642
+ display: flex;
643
+ align-items: center;
644
+ gap: 6px;
645
+ }
646
+
647
+ /* The page's own content column, under the bar. Content-box sizing so
648
+ `--page-width` means the text column, not the column plus padding —
649
+ that is what makes it line up with the bar's inner row. */
650
+ .page-body {
651
+ box-sizing: content-box;
652
+ max-width: var(--page-width);
653
+ margin: 0 auto;
654
+ padding: 24px 16px;
655
+ }
656
+
657
+ /* Square icon-only copy-to-clipboard button (src/extension/copy-button.ts), beside
658
+ a path in the viewer's Location row and the delete dialog's file row.
659
+ Swaps the copy icon for a checkmark while the .copied class is on it
660
+ (set briefly after a successful clipboard write). */
661
+ .copy-btn {
662
+ flex: 0 0 auto;
663
+ width: 1.6em;
664
+ height: 1.6em;
665
+ padding: 0;
666
+ display: inline-flex;
667
+ align-items: center;
668
+ justify-content: center;
669
+ border: 1px solid #bbb;
670
+ border-radius: 3px;
671
+ background: #fff;
672
+ color: #444;
673
+ cursor: pointer;
674
+ }
675
+ .copy-btn:hover { background: #eee; }
676
+ .copy-btn:active { background: #ddd; }
677
+ .copy-btn:focus-visible { outline: 2px solid #4a90e2; outline-offset: 1px; }
678
+ .copy-btn svg { width: 14px; height: 14px; display: block; }
679
+ .copy-btn .check-icon { display: none; color: #166534; }
680
+ .copy-btn.copied .copy-icon { display: none; }
681
+ .copy-btn.copied .check-icon { display: block; }
682
+
683
+ /* "deleted" / "modified" chip after a local file path whose file has
684
+ gone or changed on disk since it was read (src/extension/file-changes.ts).
685
+ Sized like `.scheme-chip` above but square-cornered like the
686
+ viewer's tab marks, so it reads as a remark on the path rather than
687
+ a collection kind. Red for a file that isn't there; amber for one
688
+ that is, but differs from what is loaded. */
689
+ .file-change-chip {
690
+ display: inline-block;
691
+ margin-left: 0.5em;
692
+ padding: 0 0.4em;
693
+ border-radius: 3px;
694
+ color: #fff;
695
+ font-size: 10px;
696
+ font-weight: 600;
697
+ text-transform: uppercase;
698
+ letter-spacing: 0.04em;
699
+ vertical-align: 1px;
700
+ cursor: default;
701
+ /* `text-indent` inherits into an inline-block and would shove the
702
+ word out of the chip on the collections page's hanging-indent
703
+ name cells. */
704
+ text-indent: 0;
705
+ /* A chip is one word and never breaks: in a flex row it must not
706
+ shrink (the path beside it wraps instead), and inherited
707
+ `overflow-wrap: anywhere` / `word-break` must not split it. */
708
+ flex: 0 0 auto;
709
+ white-space: nowrap;
710
+ overflow-wrap: normal;
711
+ word-break: normal;
712
+ }
713
+ .file-change-chip-missing { background: #b91c1c; }
714
+ /* Teal for "differs from what is loaded": a modified file, and the
715
+ collection whose refresh would pick such changes up. Chosen to be
716
+ unlike the amber the FILE-DIR bubble wears, which sits inches away. */
717
+ .file-change-chip-modified,
718
+ .file-change-chip-pending { background: #0f766e; }
719
+ /* Inside a flex row that already spaces its children with `gap` (the
720
+ viewer's Location and Local overrides rows), the margin would double
721
+ the gap on the chip's left only. */
722
+ .filename-cell > .file-change-chip,
723
+ .local-override-cell > .file-change-chip { margin-left: 0; }
724
+
725
+ /* ---- Tab strip over a code box (src/extension/code-tabs.ts, src/extension/compare.ts) ---- */
726
+
727
+ /* One file per tab: the viewer's main script, `@require`s and Log; the
728
+ compare page's per-file diffs. The active tab's bottom border takes
729
+ the box's own colour so it "opens into" the box below, which sits
730
+ 1px up to meet it (each page's own `margin-top: -1px`). */
731
+ .tabs {
732
+ display: flex;
733
+ flex: 0 0 auto;
734
+ gap: 3px;
735
+ margin: 0;
736
+ padding: 0;
737
+ overflow-x: auto;
738
+ }
739
+ /* An author `display` outranks the UA's `[hidden] { display: none }`. */
740
+ .tabs[hidden] { display: none; }
741
+ .tab {
742
+ /* Its own height: a tab sizes to its label and the strip's bottom
743
+ edge, and the shared button height squeezes the label's line box. */
744
+ height: auto;
745
+ font: inherit;
746
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
747
+ font-size: 12px;
748
+ line-height: 1.2;
749
+ padding: 0.45em 0.9em;
750
+ border: 1px solid #ccc;
751
+ border-radius: 4px 4px 0 0;
752
+ background: #e4e4e4;
753
+ color: #555;
754
+ cursor: pointer;
755
+ white-space: nowrap;
756
+ }
757
+ .tab:hover { background: #efefef; }
758
+ /* Hover lightens a tab toward the selected look, so pressing goes the
759
+ other way to stay a press. */
760
+ .tab:active:not(.active) { background: #d4d4d4; }
761
+ .tab.active {
762
+ background: #fafafa;
763
+ color: #222;
764
+ font-weight: 600;
765
+ border-bottom-color: #fafafa;
766
+ }
767
+ .tab:focus-visible { outline: 2px solid #4a90e2; outline-offset: -2px; }
768
+
769
+ /* ---- Site favicons (src/extension/site-icon.ts) ---- */
770
+
771
+ /* The icons inside a slot: one clickable <a> (or inert <span>) per
772
+ site, each a globe until the real favicon lands. The slot itself is
773
+ each page's own — a table's fixed-width column on the collections
774
+ page, the heading's on the viewer and compare pages (below). */
775
+ .site-icon-inner {
776
+ display: block;
777
+ width: 16px;
778
+ height: 16px;
779
+ flex: 0 0 auto;
780
+ color: #888;
781
+ }
782
+ a.site-icon-inner { text-decoration: none; }
783
+ a.site-icon-inner:hover { color: #444; }
784
+ .site-icon img { width: 16px; height: 16px; display: block; }
785
+ .site-icon-globe { width: 16px; height: 16px; display: block; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
786
+
787
+ /* Slot for the site favicons, sitting between the heading's
788
+ product prefix and the script's name. Always present, and at
789
+ least one icon wide, so the name starts at the same offset past
790
+ the prefix whether or not a favicon resolves. Holds one
791
+ clickable <a> per distinct site the script's @match names
792
+ (side by side, 2px gap), or one inert <span> when it names
793
+ none.
794
+ Inner content is a globe placeholder until the real favicon
795
+ loads. */
796
+ .page-header h1 .site-icon {
797
+ display: inline-flex;
798
+ gap: 2px;
799
+ min-width: 16px;
800
+ height: 16px;
801
+ margin-right: 0.4em;
802
+ /* Centred on the heading's CAP band, not on its baseline or its
803
+ descender line. `text-bottom` sits the 16px square on the
804
+ font's descender, which puts its centre ~1.4px below the
805
+ centre of the letters beside it — visible as a favicon
806
+ hanging low. The heading is 16.1px with a 12px cap height, so
807
+ 2px of the square below the baseline centres the two. */
808
+ vertical-align: -2px;
809
+ }
810
+
811
+ /* The menu a ⋯ button opens (src/extension/more-menu.ts), on the
812
+ toolbar popup and the collections page. Each page styles its own
813
+ `button.more-menu`. */
814
+ .menu {
815
+ position: fixed; z-index: 10; min-width: 220px;
816
+ background: #fff; border: 1px solid #c9c2b8; border-radius: 6px;
817
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16); padding: 4px 0;
818
+ }
819
+ .menu button {
820
+ display: block; width: 100%; height: auto; text-align: left;
821
+ border: none; border-radius: 0; background: transparent; padding: 5px 12px; font-size: 12.5px;
822
+ }
823
+ .menu button:hover:not(:disabled), .menu button:focus-visible { background: #f3efe9; }
824
+ .menu button:disabled { color: #a0a0a0; cursor: default; }
825
+ .menu hr { border: none; border-top: 1px solid var(--rule, #e3ddd4); margin: 4px 0; }