@vscode/markdown-editor 0.0.2-1 → 0.0.2-100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +31 -0
  2. package/dist/commands.d.ts +67 -0
  3. package/dist/commands.js +183 -0
  4. package/dist/commands.js.map +1 -0
  5. package/dist/config-BGeaJqWk.js +286 -0
  6. package/dist/config-BGeaJqWk.js.map +1 -0
  7. package/dist/config.d.ts +10 -0
  8. package/dist/config.js +6 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/index.d.ts +1901 -112
  11. package/dist/index.js +7073 -1969
  12. package/dist/index.js.map +1 -1
  13. package/dist/markdown-editor.css +1 -0
  14. package/dist/stringEdit-CVDbCUBY.js +215 -0
  15. package/dist/stringEdit-CVDbCUBY.js.map +1 -0
  16. package/dist/web-editors.d.ts +297 -0
  17. package/dist/web-editors.js +7359 -0
  18. package/dist/web-editors.js.map +1 -0
  19. package/package.json +60 -15
  20. package/src/contrib/comments/commentInput.css +89 -0
  21. package/src/contrib/comments/commentWidget.css +60 -0
  22. package/src/contrib/find/find.css +347 -0
  23. package/src/view/editor.css +1316 -44
  24. package/src/view/themes/default.css +13 -4
  25. package/src/view/themes/github.css +16 -18
  26. package/src/view/themes/vscode-default.css +397 -0
  27. package/src/view/themes/vscode-github.css +393 -0
  28. package/dist/_observables/assert.d.ts +0 -2
  29. package/dist/_observables/deps.d.ts +0 -28
  30. package/dist/_observables/disposables.d.ts +0 -19
  31. package/dist/_observables/equals.d.ts +0 -32
  32. package/dist/_observables/index.d.ts +0 -2
  33. package/dist/_observables/observableInternal/base.d.ts +0 -172
  34. package/dist/_observables/observableInternal/changeTracker.d.ts +0 -44
  35. package/dist/_observables/observableInternal/commonFacade/cancellation.d.ts +0 -24
  36. package/dist/_observables/observableInternal/commonFacade/deps.d.ts +0 -24
  37. package/dist/_observables/observableInternal/debugLocation.d.ts +0 -21
  38. package/dist/_observables/observableInternal/debugName.d.ts +0 -33
  39. package/dist/_observables/observableInternal/experimental/deferUnobserve.d.ts +0 -16
  40. package/dist/_observables/observableInternal/experimental/reducer.d.ts +0 -37
  41. package/dist/_observables/observableInternal/experimental/utils.d.ts +0 -15
  42. package/dist/_observables/observableInternal/index.d.ts +0 -25
  43. package/dist/_observables/observableInternal/logging/consoleObservableLogger.d.ts +0 -40
  44. package/dist/_observables/observableInternal/logging/debugGetDependencyGraph.d.ts +0 -4
  45. package/dist/_observables/observableInternal/logging/debugger/debuggerRpc.d.ts +0 -4
  46. package/dist/_observables/observableInternal/logging/debugger/devToolsLogger.d.ts +0 -43
  47. package/dist/_observables/observableInternal/logging/debugger/rpc.d.ts +0 -41
  48. package/dist/_observables/observableInternal/logging/debugger/utils.d.ts +0 -13
  49. package/dist/_observables/observableInternal/logging/logging.d.ts +0 -30
  50. package/dist/_observables/observableInternal/map.d.ts +0 -18
  51. package/dist/_observables/observableInternal/observables/baseObservable.d.ts +0 -58
  52. package/dist/_observables/observableInternal/observables/constObservable.d.ts +0 -5
  53. package/dist/_observables/observableInternal/observables/derived.d.ts +0 -46
  54. package/dist/_observables/observableInternal/observables/derivedImpl.d.ts +0 -83
  55. package/dist/_observables/observableInternal/observables/lazyObservableValue.d.ts +0 -27
  56. package/dist/_observables/observableInternal/observables/observableFromEvent.d.ts +0 -37
  57. package/dist/_observables/observableInternal/observables/observableSignal.d.ts +0 -11
  58. package/dist/_observables/observableInternal/observables/observableSignalFromEvent.d.ts +0 -5
  59. package/dist/_observables/observableInternal/observables/observableValue.d.ts +0 -37
  60. package/dist/_observables/observableInternal/observables/observableValueOpts.d.ts +0 -8
  61. package/dist/_observables/observableInternal/reactions/autorun.d.ts +0 -56
  62. package/dist/_observables/observableInternal/reactions/autorunImpl.d.ts +0 -53
  63. package/dist/_observables/observableInternal/set.d.ts +0 -17
  64. package/dist/_observables/observableInternal/transaction.d.ts +0 -27
  65. package/dist/_observables/observableInternal/utils/promise.d.ts +0 -75
  66. package/dist/_observables/observableInternal/utils/runOnChange.d.ts +0 -7
  67. package/dist/_observables/observableInternal/utils/utils.d.ts +0 -43
  68. package/dist/_observables/observableInternal/utils/utilsCancellation.d.ts +0 -10
  69. package/dist/_observables/observableInternal/utils/valueWithChangeEvent.d.ts +0 -10
  70. package/dist/_observables/utils.d.ts +0 -15
  71. package/dist/observables.d.ts +0 -4
  72. package/dist/observables.js +0 -463
  73. package/dist/observables.js.map +0 -1
  74. package/dist/runOnChange-owE1SMC0.js +0 -1514
  75. package/dist/runOnChange-owE1SMC0.js.map +0 -1
@@ -1,3 +1,6 @@
1
+ @import '@vscode/codicons/dist/codicon.css';
2
+ @import '../contrib/find/find.css';
3
+
1
4
  /*
2
5
  * Base editor styles — ABSOLUTE MINIMUM.
3
6
  *
@@ -12,32 +15,680 @@
12
15
  * theme files (`themes/default.css`, `themes/github.css`) applied via the
13
16
  * `classNames` editor option; those selectors only ever match inside their
14
17
  * own theme class and never style the global scope.
18
+ *
19
+ * NO `--vscode-*` variables may be referenced here. This base file must stay
20
+ * theme-agnostic and know nothing about VS Code. Where a value needs to vary
21
+ * per theme, expose a local `--md-*` custom property WITH a sensible literal
22
+ * fallback (e.g. `var(--md-cursor-background, #000)`) and let a theme file set
23
+ * it. Only the `themes/vscode-*.css` themes are permitted to read `--vscode-*`
24
+ * variables and map them onto these `--md-*` properties.
15
25
  */
16
26
 
17
27
  .md-editor {
18
- position: relative;
28
+ display: flow-root;
19
29
  outline: none;
20
30
  /* The editor paints its own cursor (`.md-cursor`); hide the native caret. */
21
31
  caret-color: transparent;
22
- padding: 48px;
32
+ }
33
+
34
+ .md-editor-a11y-status {
35
+ position: absolute;
36
+ width: 1px;
37
+ height: 1px;
38
+ padding: 0;
39
+ margin: -1px;
40
+ overflow: hidden;
41
+ clip: rect(0, 0, 0, 0);
42
+ white-space: nowrap;
43
+ border: 0;
44
+ }
45
+
46
+ /*
47
+ * The transient empty paragraph — the blank line conjured by pressing Enter at
48
+ * the end of a paragraph (see `PendingParagraph` in the model). It is not part
49
+ * of the document (Markdown has no empty-paragraph node); it holds a single
50
+ * `<br>` so it occupies one line's height, and the caret is painted over it.
51
+ */
52
+ .md-pending-paragraph {
53
+ min-height: 1em;
54
+ }
55
+
56
+ /*
57
+ * Inner content container. Holds the rendered document and the cursor/selection
58
+ * overlays, which position themselves relative to this box, so it is the
59
+ * positioning context. In limited-width mode the editor sets an inline
60
+ * `max-width` here and the auto inline margins center it within the full-width
61
+ * `.md-editor`. The block-start padding keeps every document clear of the top
62
+ * edge, independent of the first block's theme margins.
63
+ */
64
+ .md-editor-content {
65
+ --md-editor-content-inline-start-padding: 48px;
66
+ --md-readonly-toggle-width: 58px;
67
+ --md-readonly-toggle-height: 32px;
68
+ /* Leaves 16px of optical separation beyond the active block's 8px outset glow. */
69
+ --md-readonly-toggle-gap: 24px;
70
+ --md-readonly-toggle-inset: 4px;
71
+ --md-editor-content-inline-end-padding: var(--md-editor-content-inline-start-padding);
72
+ position: relative;
73
+ margin-inline: auto;
74
+ padding-block: 24px 0;
75
+ padding-inline: var(--md-editor-content-inline-start-padding) var(--md-editor-content-inline-end-padding);
76
+ }
77
+
78
+ .md-editor-content-with-readonly-toggle {
79
+ --md-editor-content-inline-end-padding: calc(var(--md-readonly-toggle-width) + var(--md-readonly-toggle-gap) + var(--md-readonly-toggle-inset));
80
+ }
81
+
82
+ .md-editor-content-with-readonly-toggle>.md-document :is(.md-heading, .md-paragraph) {
83
+ overflow-wrap: anywhere;
23
84
  }
24
85
 
25
86
  .md-block-active {
26
- background: #f8f8f8;
87
+ background: var(--md-block-active-background, #f8f8f8);
27
88
  border-radius: 4px;
28
- box-shadow: 0 0 0 8px #f8f8f8;
89
+ box-shadow: 0 0 0 8px var(--md-block-active-background, #f8f8f8);
29
90
  }
30
91
 
31
92
  /*
32
- * A rendered (inactive) link opens on a plain click, so it keeps the anchor's
33
- * pointer cursor. Once its block is active the link is editable source and a
34
- * plain click places the caret (Ctrl/Cmd+click still opens), so it shows the
35
- * normal editing cursor like the surrounding text.
93
+ * The whole-empty-document case. Markdown has no empty-paragraph node, so a
94
+ * document with no content parses to a single empty paragraph (see
95
+ * `_ensureBlocks` in the parser) which renders as a childless `<p>` of zero
96
+ * height. Give it one line's height so the editor presents an intentional,
97
+ * clickable empty editing surface — and so typing the first character causes no
98
+ * layout shift (a filled line is also one `lh` tall).
99
+ */
100
+ .md-paragraph:empty {
101
+ min-height: 1lh;
102
+ }
103
+
104
+ /*
105
+ * ...and never paint the active-block card over that zero-content line: with no
106
+ * text to size it, the card's background + 8px box-shadow glow would show up as
107
+ * a stray gray bar. The two extra classes outrank the base `.md-block-active`
108
+ * rule above in every theme (themes only remap `--md-block-active-background`).
109
+ */
110
+ .md-paragraph:empty.md-block-active {
111
+ background: transparent;
112
+ box-shadow: none;
113
+ }
114
+
115
+ /*
116
+ * Cursor mirrors the same open affordance as the underline below: the anchor's
117
+ * pointer cursor appears exactly when a click would open the link. An inactive
118
+ * (rendered) link opens on a plain click, so it keeps the browser's default
119
+ * anchor pointer. Once its block is active a plain click places the caret, so
120
+ * the link shows the normal editing cursor — except while Ctrl/Cmd is held
121
+ * (`.md-mod-down`), when a click opens it and the pointer returns.
36
122
  */
37
123
  .md-block-active a {
38
124
  cursor: inherit;
39
125
  }
40
126
 
127
+ .md-editor.md-mod-down .md-block-active a[href] {
128
+ cursor: pointer;
129
+ }
130
+
131
+ /*
132
+ * Link underline is an "open affordance": show it only while a click on the
133
+ * link right now would actually open it. An inactive (rendered) link opens on
134
+ * a plain click, so hovering it underlines. An active link's plain click edits
135
+ * its source — it only opens with Ctrl/Cmd — so it underlines on hover only
136
+ * while that modifier is held (`.md-mod-down`, set live by the view).
137
+ */
138
+ .md-editor a[href]:hover {
139
+ text-decoration: underline;
140
+ }
141
+
142
+ .md-editor:not(.md-mod-down) .md-block-active a[href]:hover {
143
+ text-decoration: none;
144
+ }
145
+
146
+ .md-rich-link {
147
+ display: inline-flex;
148
+ align-items: baseline;
149
+ max-width: min(100%, 52rem);
150
+ box-sizing: border-box;
151
+ gap: 0.24em;
152
+ padding: 1px 0.3em;
153
+ border: 1px solid color-mix(in srgb, var(--vscode-textLink-foreground, #0969da) 24%, transparent);
154
+ border-radius: 0.3em;
155
+ background: var(--vscode-button-secondaryBackground, #f3f3f3);
156
+ color: inherit;
157
+ font-size: 1em;
158
+ line-height: 1.25;
159
+ text-decoration: none;
160
+ vertical-align: baseline;
161
+ white-space: nowrap;
162
+ cursor: pointer;
163
+ --md-rich-link-success-color: var(--vscode-charts-green, #1f883d);
164
+ }
165
+
166
+ .md-rich-link:hover {
167
+ border-color: var(--vscode-focusBorder, color-mix(in srgb, currentColor 42%, transparent));
168
+ background: var(--vscode-button-secondaryHoverBackground, #e5e5e5);
169
+ text-decoration: none;
170
+ }
171
+
172
+ .md-rich-link:focus-visible {
173
+ outline: 1px solid var(--vscode-focusBorder, currentColor);
174
+ outline-offset: 1px;
175
+ }
176
+
177
+ .md-rich-link-icon {
178
+ flex: none;
179
+ align-self: center;
180
+ font-size: 0.92em;
181
+ color: color-mix(in srgb, var(--vscode-textLink-foreground, #0969da) 78%, currentColor);
182
+ }
183
+
184
+ .md-rich-link-label,
185
+ .md-rich-link-title,
186
+ .md-rich-link-detail {
187
+ overflow: hidden;
188
+ text-overflow: ellipsis;
189
+ }
190
+
191
+ .md-rich-link-label,
192
+ .md-rich-link-title {
193
+ flex: 0 1 auto;
194
+ min-width: 0;
195
+ color: var(--vscode-textLink-foreground, currentColor);
196
+ font-weight: 600;
197
+ }
198
+
199
+ .md-rich-link-title {
200
+ max-width: 200px;
201
+ }
202
+
203
+ .md-rich-link[data-md-rich-link-kind='session'] :is(.md-rich-link-label, .md-rich-link-title) {
204
+ max-width: 150px;
205
+ }
206
+
207
+ .md-rich-link-label[hidden],
208
+ .md-rich-link-title[hidden],
209
+ .md-rich-link-reference[hidden] {
210
+ display: none;
211
+ }
212
+
213
+ .md-rich-link-reference {
214
+ flex: none;
215
+ color: var(--vscode-descriptionForeground, color-mix(in srgb, currentColor 72%, transparent));
216
+ font-size: 0.92em;
217
+ }
218
+
219
+ .md-rich-link-detail {
220
+ flex: 1 1 auto;
221
+ min-width: 1.5em;
222
+ color: var(--vscode-descriptionForeground, color-mix(in srgb, currentColor 72%, transparent));
223
+ font-size: 0.92em;
224
+ }
225
+
226
+ .md-rich-link-detail::before {
227
+ content: '·';
228
+ margin-right: 0.28em;
229
+ }
230
+
231
+ .md-rich-link-status {
232
+ flex: none;
233
+ display: inline-flex;
234
+ align-self: center;
235
+ align-items: center;
236
+ gap: 0.22em;
237
+ margin-left: 0.04em;
238
+ color: var(--vscode-descriptionForeground, currentColor);
239
+ font-size: 0.86em;
240
+ font-weight: 600;
241
+ line-height: 1;
242
+ }
243
+
244
+ .md-rich-link-detail[hidden],
245
+ .md-rich-link-changes[hidden],
246
+ .md-rich-link-status[hidden] {
247
+ display: none;
248
+ }
249
+
250
+ .md-rich-link-changes {
251
+ flex: none;
252
+ display: inline-flex;
253
+ align-self: center;
254
+ gap: 0.28em;
255
+ font-size: 0.86em;
256
+ font-weight: 600;
257
+ line-height: 1;
258
+ }
259
+
260
+ .md-rich-link-changes::before,
261
+ .md-rich-link:not(
262
+ [data-md-rich-link-kind='issue'],
263
+ [data-md-rich-link-kind='pullRequest'],
264
+ [data-md-rich-link-kind='session']
265
+ ) .md-rich-link-primary-status::before {
266
+ content: '·';
267
+ color: var(--vscode-descriptionForeground, currentColor);
268
+ font-weight: 400;
269
+ }
270
+
271
+ .md-rich-link-insertions {
272
+ color: var(--vscode-charts-green, #1f883d);
273
+ }
274
+
275
+ .md-rich-link-deletions {
276
+ color: var(--vscode-charts-red, #cf222e);
277
+ }
278
+
279
+ .md-rich-link-status-icon {
280
+ flex: none;
281
+ align-self: center;
282
+ font-size: 1em;
283
+ }
284
+
285
+ .md-rich-link:is(
286
+ [data-md-rich-link-status='open'],
287
+ [data-md-rich-link-status='closed'],
288
+ [data-md-rich-link-status='merged'],
289
+ [data-md-rich-link-status='draft'],
290
+ [data-md-rich-link-status='notPlanned']
291
+ ) .md-rich-link-primary-status {
292
+ color: var(--md-rich-link-state-color);
293
+ }
294
+
295
+ .md-rich-link-secondary-status {
296
+ margin-left: 0.06em;
297
+ }
298
+
299
+ .md-rich-link-secondary-status::before {
300
+ content: '·';
301
+ margin-right: 0.08em;
302
+ color: var(--vscode-descriptionForeground, currentColor);
303
+ font-weight: 400;
304
+ }
305
+
306
+ .md-rich-link:is(
307
+ [data-md-rich-link-status='open'],
308
+ [data-md-rich-link-status='closed'],
309
+ [data-md-rich-link-status='merged'],
310
+ [data-md-rich-link-status='draft'],
311
+ [data-md-rich-link-status='notPlanned']
312
+ ) .md-rich-link-primary-status {
313
+ align-self: baseline;
314
+ padding: 0;
315
+ border: 0;
316
+ border-radius: 0;
317
+ background: transparent;
318
+ font-size: 1em;
319
+ line-height: inherit;
320
+ }
321
+
322
+ .md-rich-link[data-md-rich-link-status='success'] .md-rich-link-primary-status {
323
+ color: var(--vscode-charts-green, #1f883d);
324
+ }
325
+
326
+ .md-rich-link[data-md-rich-link-secondary-status='success'] .md-rich-link-secondary-status {
327
+ color: var(--md-rich-link-success-color);
328
+ }
329
+
330
+ .md-rich-link[data-md-rich-link-status='warning'] .md-rich-link-primary-status,
331
+ .md-rich-link[data-md-rich-link-secondary-status='warning'] .md-rich-link-secondary-status {
332
+ color: var(--vscode-editorWarning-foreground, #bf8700);
333
+ }
334
+
335
+ .md-rich-link[data-md-rich-link-status='error'] .md-rich-link-primary-status,
336
+ .md-rich-link[data-md-rich-link-secondary-status='error'] .md-rich-link-secondary-status {
337
+ color: var(--vscode-errorForeground, #cf222e);
338
+ }
339
+
340
+ .md-rich-link[data-md-rich-link-status='pending'] .md-rich-link-primary-status,
341
+ .md-rich-link[data-md-rich-link-secondary-status='pending'] .md-rich-link-secondary-status {
342
+ color: var(--vscode-editorWarning-foreground, #bf8700);
343
+ }
344
+
345
+ .md-rich-link[data-md-rich-link-kind='issue'] .md-rich-link-primary-status .md-rich-link-status-label,
346
+ .md-rich-link[data-md-rich-link-kind='pullRequest'] :is(
347
+ .md-rich-link-primary-status,
348
+ .md-rich-link-secondary-status
349
+ ) .md-rich-link-status-label {
350
+ display: none;
351
+ }
352
+
353
+ .md-rich-link[data-md-rich-link-status='open'] {
354
+ --md-rich-link-state-color: var(--vscode-charts-green, #1f883d);
355
+ }
356
+
357
+ .md-rich-link[data-md-rich-link-kind='issue'][data-md-rich-link-status='closed'],
358
+ .md-rich-link[data-md-rich-link-status='merged'] {
359
+ --md-rich-link-state-color: var(--vscode-charts-purple, #8250df);
360
+ }
361
+
362
+ .md-rich-link[data-md-rich-link-kind='pullRequest'][data-md-rich-link-status='closed'] {
363
+ --md-rich-link-state-color: var(--vscode-charts-red, #cf222e);
364
+ }
365
+
366
+ .md-rich-link[data-md-rich-link-status='draft'],
367
+ .md-rich-link[data-md-rich-link-status='notPlanned'] {
368
+ --md-rich-link-state-color: var(--vscode-descriptionForeground, #656d76);
369
+ }
370
+
371
+ .md-rich-link[data-md-rich-link-kind='pullRequest'][data-md-rich-link-secondary-status='error'] .md-rich-link-secondary-status {
372
+ color: var(--vscode-charts-red, var(--vscode-errorForeground, #cf222e));
373
+ }
374
+
375
+ .md-rich-link:is(
376
+ [data-md-rich-link-kind='issue'],
377
+ [data-md-rich-link-kind='pullRequest']
378
+ ) {
379
+ align-items: center;
380
+ gap: 4px;
381
+ padding: 1px 6px;
382
+ border-color: var(--vscode-button-secondaryBorder, var(--vscode-button-border, transparent));
383
+ border-radius: 4px;
384
+ background: var(--vscode-button-secondaryBackground, #f3f3f3);
385
+ color: var(--vscode-button-secondaryForeground, #242424);
386
+ font-size: 1em;
387
+ line-height: 1.25;
388
+ vertical-align: -0.5px;
389
+ }
390
+
391
+ .md-rich-link:is(
392
+ [data-md-rich-link-kind='issue'],
393
+ [data-md-rich-link-kind='pullRequest']
394
+ ):hover {
395
+ border-color: var(--vscode-button-secondaryBorder, var(--vscode-button-border, transparent));
396
+ background: var(--vscode-button-secondaryHoverBackground, #e5e5e5);
397
+ color: var(--vscode-button-secondaryForeground, #242424);
398
+ }
399
+
400
+ .md-rich-link:is(
401
+ [data-md-rich-link-kind='issue'],
402
+ [data-md-rich-link-kind='pullRequest']
403
+ ) .md-rich-link-reference {
404
+ display: none;
405
+ }
406
+
407
+ .md-rich-link:is(
408
+ [data-md-rich-link-kind='issue'],
409
+ [data-md-rich-link-kind='pullRequest']
410
+ ) :is(
411
+ .md-rich-link-label,
412
+ .md-rich-link-title,
413
+ .md-rich-link-primary-status,
414
+ .md-rich-link-secondary-status
415
+ ) {
416
+ align-self: center;
417
+ font-size: inherit;
418
+ line-height: inherit;
419
+ }
420
+
421
+ .md-rich-link:is(
422
+ [data-md-rich-link-kind='issue'],
423
+ [data-md-rich-link-kind='pullRequest']
424
+ ) :is(.md-rich-link-label, .md-rich-link-title) {
425
+ position: relative;
426
+ top: 0.25px;
427
+ max-width: 200px;
428
+ color: inherit;
429
+ font-weight: 400;
430
+ }
431
+
432
+ .md-rich-link:is(
433
+ [data-md-rich-link-kind='issue'],
434
+ [data-md-rich-link-kind='pullRequest']
435
+ ) .md-rich-link-status {
436
+ align-items: center;
437
+ height: 1.25em;
438
+ }
439
+
440
+ .md-rich-link:is(
441
+ [data-md-rich-link-kind='issue'],
442
+ [data-md-rich-link-kind='pullRequest']
443
+ ) .md-rich-link-status-icon {
444
+ display: inline-flex;
445
+ align-items: center;
446
+ justify-content: center;
447
+ width: 12px;
448
+ height: 12px;
449
+ font-size: 12px;
450
+ line-height: 12px;
451
+ }
452
+
453
+ .md-rich-link:is(
454
+ [data-md-rich-link-kind='issue'],
455
+ [data-md-rich-link-kind='pullRequest']
456
+ ) .md-rich-link-secondary-status::before {
457
+ align-self: center;
458
+ line-height: inherit;
459
+ }
460
+
461
+ .md-rich-link[data-md-rich-link-kind='session'] {
462
+ align-items: center;
463
+ gap: 4px;
464
+ padding: 1px 6px;
465
+ border-color: var(--vscode-chat-requestBorder, var(--vscode-input-border, color-mix(in srgb, currentColor 24%, transparent)));
466
+ border-radius: 4px;
467
+ background: var(--vscode-button-secondaryBackground, #f3f3f3);
468
+ color: var(--vscode-descriptionForeground, #656d76);
469
+ font-size: 1em;
470
+ font-weight: var(--vscode-agents-fontWeight-regular, 400);
471
+ line-height: 1.25;
472
+ vertical-align: baseline;
473
+ }
474
+
475
+ .md-rich-link[data-md-rich-link-kind='session']:hover {
476
+ border-color: var(--vscode-chat-requestBorder, var(--vscode-input-border, color-mix(in srgb, currentColor 24%, transparent)));
477
+ background: var(--vscode-toolbar-hoverBackground, color-mix(in srgb, currentColor 8%, transparent));
478
+ }
479
+
480
+ .md-rich-link[data-md-rich-link-kind='session'] :is(.md-rich-link-label, .md-rich-link-title) {
481
+ color: inherit;
482
+ font-weight: 400;
483
+ }
484
+
485
+ .md-rich-link[data-md-rich-link-kind='session'] .md-rich-link-primary-status {
486
+ align-self: center;
487
+ align-items: center;
488
+ width: 12px;
489
+ height: 12px;
490
+ margin: 0;
491
+ padding: 0;
492
+ border: 0;
493
+ border-radius: 0;
494
+ background: transparent;
495
+ font-size: 1em;
496
+ line-height: inherit;
497
+ }
498
+
499
+ .md-rich-link[data-md-rich-link-kind='session'] .md-rich-link-primary-status .md-rich-link-status-label {
500
+ display: none;
501
+ }
502
+
503
+ .md-rich-link[data-md-rich-link-kind='session'] .md-rich-link-status-icon:not(.monaco-pixel-spinner, [hidden]) {
504
+ display: inline-flex;
505
+ align-items: center;
506
+ justify-content: center;
507
+ width: 12px;
508
+ height: 12px;
509
+ font-size: 12px;
510
+ line-height: 12px;
511
+ }
512
+
513
+ .md-rich-link .md-rich-link-status-icon[hidden] {
514
+ display: none;
515
+ }
516
+
517
+ .md-rich-link[data-md-rich-link-kind='session'][data-md-rich-link-status='neutral'] .md-rich-link-primary-status,
518
+ .md-rich-link[data-md-rich-link-kind='session'][data-md-rich-link-status='success'] .md-rich-link-primary-status,
519
+ .md-rich-link[data-md-rich-link-kind='session'][data-md-rich-link-status='pending'] .md-rich-link-primary-status {
520
+ color: var(--vscode-descriptionForeground, #656d76);
521
+ }
522
+
523
+ .md-rich-link .monaco-pixel-spinner {
524
+ display: inline-grid;
525
+ grid-template-columns: repeat(2, 2px);
526
+ grid-template-rows: repeat(3, 2px);
527
+ column-gap: 2px;
528
+ row-gap: 2px;
529
+ place-content: center;
530
+ width: 16px;
531
+ height: 16px;
532
+ color: currentColor;
533
+ contain: layout style size paint;
534
+ isolation: isolate;
535
+ pointer-events: none;
536
+ transform: translateZ(0);
537
+ }
538
+
539
+ .md-rich-link[data-md-rich-link-kind='session'] .monaco-pixel-spinner {
540
+ width: 12px;
541
+ height: 12px;
542
+ }
543
+
544
+ .md-rich-link .monaco-pixel-spinner-dot {
545
+ display: block;
546
+ width: 2px;
547
+ height: 2px;
548
+ border-radius: 50%;
549
+ background-color: currentColor;
550
+ opacity: 0;
551
+ transform: translateY(-4px);
552
+ animation: monaco-pixel-spinner-dot-cycle 1820ms steps(6, jump-none) infinite;
553
+ }
554
+
555
+ .md-rich-link .monaco-pixel-spinner-dot:nth-child(1) {
556
+ animation-delay: 520ms;
557
+ }
558
+
559
+ .md-rich-link .monaco-pixel-spinner-dot:nth-child(2) {
560
+ animation-delay: 650ms;
561
+ }
562
+
563
+ .md-rich-link .monaco-pixel-spinner-dot:nth-child(3) {
564
+ animation-delay: 260ms;
565
+ }
566
+
567
+ .md-rich-link .monaco-pixel-spinner-dot:nth-child(4) {
568
+ animation-delay: 390ms;
569
+ }
570
+
571
+ .md-rich-link .monaco-pixel-spinner-dot:nth-child(5) {
572
+ animation-name: monaco-pixel-spinner-dot-cycle-long;
573
+ }
574
+
575
+ .md-rich-link .monaco-pixel-spinner-dot:nth-child(6) {
576
+ animation-name: monaco-pixel-spinner-dot-cycle-short;
577
+ animation-delay: 130ms;
578
+ }
579
+
580
+ .md-rich-link .monaco-pixel-spinner-ring .monaco-pixel-spinner-dot {
581
+ opacity: 0.25;
582
+ transform: none;
583
+ animation: monaco-pixel-spinner-ring-pulse 1200ms steps(4, jump-none) infinite;
584
+ }
585
+
586
+ .md-rich-link .monaco-pixel-spinner-ring .monaco-pixel-spinner-dot:nth-child(1) {
587
+ animation-delay: 0ms;
588
+ }
589
+
590
+ .md-rich-link .monaco-pixel-spinner-ring .monaco-pixel-spinner-dot:nth-child(2) {
591
+ animation-delay: 200ms;
592
+ }
593
+
594
+ .md-rich-link .monaco-pixel-spinner-ring .monaco-pixel-spinner-dot:nth-child(3) {
595
+ animation-delay: 1000ms;
596
+ }
597
+
598
+ .md-rich-link .monaco-pixel-spinner-ring .monaco-pixel-spinner-dot:nth-child(4) {
599
+ animation-delay: 400ms;
600
+ }
601
+
602
+ .md-rich-link .monaco-pixel-spinner-ring .monaco-pixel-spinner-dot:nth-child(5) {
603
+ animation-delay: 800ms;
604
+ }
605
+
606
+ .md-rich-link .monaco-pixel-spinner-ring .monaco-pixel-spinner-dot:nth-child(6) {
607
+ animation-delay: 600ms;
608
+ }
609
+
610
+ @keyframes monaco-pixel-spinner-dot-cycle {
611
+ 0% {
612
+ opacity: 0;
613
+ transform: translateY(-4px);
614
+ }
615
+ 9.34%, 57.14% {
616
+ opacity: 1;
617
+ transform: translateY(0);
618
+ }
619
+ 66.48%, 100% {
620
+ opacity: 0;
621
+ transform: translateY(7px);
622
+ }
623
+ }
624
+
625
+ @keyframes monaco-pixel-spinner-dot-cycle-long {
626
+ 0% {
627
+ opacity: 0;
628
+ transform: translateY(-4px);
629
+ }
630
+ 9.34%, 64.29% {
631
+ opacity: 1;
632
+ transform: translateY(0);
633
+ }
634
+ 73.63%, 100% {
635
+ opacity: 0;
636
+ transform: translateY(7px);
637
+ }
638
+ }
639
+
640
+ @keyframes monaco-pixel-spinner-dot-cycle-short {
641
+ 0% {
642
+ opacity: 0;
643
+ transform: translateY(-4px);
644
+ }
645
+ 9.34%, 50% {
646
+ opacity: 1;
647
+ transform: translateY(0);
648
+ }
649
+ 59.34%, 100% {
650
+ opacity: 0;
651
+ transform: translateY(7px);
652
+ }
653
+ }
654
+
655
+ @keyframes monaco-pixel-spinner-ring-pulse {
656
+ 0%, 100% {
657
+ opacity: 0.25;
658
+ transform: none;
659
+ }
660
+ 16.67% {
661
+ opacity: 1;
662
+ transform: none;
663
+ }
664
+ }
665
+
666
+ @media (prefers-reduced-motion: reduce) {
667
+ .md-rich-link .monaco-pixel-spinner-dot {
668
+ animation: none;
669
+ opacity: 1;
670
+ transform: translateY(0);
671
+ }
672
+ }
673
+
674
+ .md-rich-link[data-md-rich-link-kind='session'][data-md-rich-link-status='warning'] .md-rich-link-primary-status {
675
+ color: var(--vscode-list-warningForeground, #855f00);
676
+ }
677
+
678
+ .md-rich-link[data-md-rich-link-kind='session'][data-md-rich-link-status='warning'] {
679
+ border-color: var(--vscode-list-warningForeground, #855f00);
680
+ background-color: color-mix(in srgb, var(--vscode-list-warningForeground, #855f00) 12%, transparent);
681
+ color: var(--vscode-list-warningForeground, #855f00);
682
+ }
683
+
684
+ .md-rich-link[data-md-rich-link-kind='session'][data-md-rich-link-status='error'] .md-rich-link-primary-status {
685
+ color: var(--vscode-errorForeground, #cf222e);
686
+ }
687
+
688
+ .md-rich-link-unavailable {
689
+ border-style: dashed;
690
+ }
691
+
41
692
  .md-fence-spacer {
42
693
  visibility: hidden;
43
694
  font-family: 'Cascadia Code', 'Fira Code', monospace;
@@ -47,7 +698,13 @@
47
698
  .md-marker {
48
699
  color: #999;
49
700
  font-family: 'Cascadia Code', 'Fira Code', monospace;
50
- font-size: 0.85em;
701
+ /*
702
+ * Revealed source is painted a step smaller than body text. Published as a
703
+ * custom property because a gutter marker has to undo it to size its box
704
+ * against the body line box — see `.md-list-item-active>.md-marker-listItemMarker`.
705
+ */
706
+ --md-marker-font-scale: 0.85;
707
+ font-size: calc(1em * var(--md-marker-font-scale));
51
708
  display: inline;
52
709
  overflow: hidden;
53
710
  max-width: 100px;
@@ -73,6 +730,69 @@
73
730
  white-space: pre-wrap;
74
731
  }
75
732
 
733
+ /*
734
+ * An unhandled block: a construct the parser does not model (setext heading,
735
+ * an extension token). Its raw source is shown verbatim,
736
+ * styled like a code block but visibly flagged as "not understood" by a dashed
737
+ * warning border, so the content is preserved and editable rather than silently
738
+ * dropped.
739
+ *
740
+ * The wrapper is the non-scrolling box (border + block spacing); the inner
741
+ * `.md-unhandled-scroll` <pre> is the horizontal scroller.
742
+ */
743
+ .md-unhandled-block {
744
+ margin: 0.5em 0;
745
+ border: 1px dashed #d0a000;
746
+ border-radius: 4px;
747
+ }
748
+
749
+ /*
750
+ * Inner scroller. Beats the per-theme `.md-theme-* .md-code-block` box rules
751
+ * (same class count) via the extra `pre` type selector: no margin/border of its
752
+ * own (those live on the wrapper).
753
+ */
754
+ pre.md-unhandled-scroll.md-code-block {
755
+ margin: 0;
756
+ border: 0;
757
+ border-radius: 4px;
758
+ }
759
+
760
+ /*
761
+ * Complete block HTML comments are authoring metadata, not unsupported-syntax
762
+ * warnings. Keep them source-identifiable but quiet while reading, and reveal
763
+ * their exact whitespace when the block becomes active.
764
+ */
765
+ .md-html-comment {
766
+ margin: 0.125em 0 0.25em;
767
+ padding: 0.125em 0;
768
+ overflow: hidden;
769
+ color: var(--md-html-comment-foreground, #6e7378);
770
+ font-family: var(--md-html-comment-font-family, 'Cascadia Code', 'Fira Code', monospace);
771
+ font-size: 0.85em;
772
+ line-height: 1.5;
773
+ text-overflow: ellipsis;
774
+ white-space: nowrap;
775
+ transition: color 80ms ease-out;
776
+ }
777
+
778
+ .md-html-comment:not(.md-html-comment-source):hover {
779
+ color: var(--md-html-comment-hover-foreground, #45494e);
780
+ }
781
+
782
+ .md-html-comment-source {
783
+ overflow: visible;
784
+ text-overflow: clip;
785
+ white-space: pre-wrap;
786
+ }
787
+
788
+ .md-html-comment-syntax {
789
+ opacity: 0.6;
790
+ }
791
+
792
+ .md-html-comment-source .md-html-comment-syntax {
793
+ opacity: 1;
794
+ }
795
+
76
796
  /*
77
797
  * Visible whitespace indicators, shown only in the active/source view. The real
78
798
  * whitespace character stays in the DOM (so source ↔ DOM mapping and selection
@@ -172,15 +892,79 @@
172
892
  }
173
893
 
174
894
  /*
175
- * Glue (table cell pipes, the task `[x] ` source, source padding) keeps its
176
- * inline footprint when hidden so column widths and the checkbox gutter stay
177
- * identical between active and inactive states.
895
+ * A soft ending followed by an explicit blockquote continuation marker renders
896
+ * a real line break in both views. Its source newline is still mapped and is
897
+ * revealed while editing, but contributes no hidden width in rendered mode.
898
+ */
899
+ .md-blockquote-linebreak-source-hidden {
900
+ display: none;
901
+ }
902
+
903
+ /*
904
+ * Structural quote prefixes between child blocks can be owned by a source gap
905
+ * instead of an inline continuation marker. Keep the exact gap for active
906
+ * editing, but remove it entirely from inactive layout and hit testing.
907
+ */
908
+ .md-glue-blockQuoteSourceGap.md-glue-hidden {
909
+ display: none;
910
+ }
911
+
912
+ /*
913
+ * Glue normally keeps its inline footprint when hidden so source padding and
914
+ * widget gutters stay identical between active and inactive states. Hidden
915
+ * table-cell glue is the exception below: leaving it in inline flow lets its
916
+ * invisible spaces wrap around long cell content.
178
917
  */
179
918
  .md-glue-hidden {
180
919
  display: inline;
181
920
  visibility: hidden;
182
921
  }
183
922
 
923
+ /*
924
+ * Inactive table pipes stay in the DOM/source tree, but leave layout and
925
+ * hit-testing entirely. Keeping an invisible rect either in the content flow or
926
+ * over the cell padding can create phantom lines or steal clicks from visible
927
+ * text. Hidden source offsets therefore collapse to the neighboring semantic
928
+ * seam, matching other display-none markers. Visible pipes retain the per-theme
929
+ * active/source layout.
930
+ */
931
+ .md-table td>.md-glue-tableCellGlue.md-glue-hidden {
932
+ display: none;
933
+ }
934
+
935
+ /*
936
+ * Active table: take each cell's TRAILING structural glue (the source space
937
+ * after the cell text, and — via the per-theme `right: 0` rule — the last
938
+ * column's closing `|`) out of the cell's inline flow. Left in flow, that glue
939
+ * wraps below long cell content (the same wrapping the hidden-glue note above
940
+ * describes), which makes the cell two lines tall: the browser's default
941
+ * `vertical-align: middle` then re-centres the other cells' single-line content
942
+ * in Y, their runs merge into one oversized VisualLine, and the caret — sized
943
+ * directly from that line box — grows far past the line height while the
944
+ * visible pipes drift apart row-to-row. Positioning the trailing glue
945
+ * absolutely removes it from wrapping flow while keeping its real client rects
946
+ * at the static (content-line) position, so caret placement, hit-testing,
947
+ * source mapping and injectivity are unchanged. `top`/`bottom: auto` keep it on
948
+ * that content line rather than the cell's top edge. This mirrors the inactive
949
+ * `display: none` above; the leading `| ` glue deliberately stays in flow (a
950
+ * relative glyph shift, per theme) so first-text X is preserved.
951
+ *
952
+ * `:not(:first-child)` restricts this to a genuine trailing glue: a non-empty
953
+ * cell emits leading + trailing glue, but an EMPTY cell parses to a single glue
954
+ * node that is simultaneously first and last child. That lone node is the
955
+ * cell's leading pipe, so it must stay in flow like every other leading pipe;
956
+ * excluding it keeps empty cells identical to their previous (base) behaviour.
957
+ */
958
+ .md-table.md-block-active td {
959
+ position: relative;
960
+ }
961
+
962
+ .md-table.md-block-active td>.md-glue-tableCellGlue:last-child:not(:first-child) {
963
+ position: absolute;
964
+ top: auto;
965
+ bottom: auto;
966
+ }
967
+
184
968
  /*
185
969
  * Inter-block glue: the run of blank lines between two top-level blocks. It is
186
970
  * mounted as the last inline child of the block that precedes it, so it sits at
@@ -191,7 +975,8 @@
191
975
  * adds no line break and no height — active and inactive therefore have the
192
976
  * same height. When hidden it collapses to nothing.
193
977
  */
194
- .md-glue-blockGap {
978
+ .md-glue-blockGap,
979
+ .md-glue-blockQuoteSourceGap {
195
980
  white-space: normal;
196
981
  }
197
982
 
@@ -217,15 +1002,6 @@
217
1002
  visibility: hidden;
218
1003
  }
219
1004
 
220
- /*
221
- * Table cell-glue pipes (`| `) keep their inline footprint when hidden so the
222
- * column widths stay identical active and inactive.
223
- */
224
- .md-marker-tableCellGlue.md-marker-hidden {
225
- display: inline;
226
- visibility: hidden;
227
- }
228
-
229
1005
  /*
230
1006
  * The code-block fences (```lang / ```) each sit on their own source line. When
231
1007
  * hidden they keep their vertical footprint (visibility hidden, not display
@@ -260,6 +1036,48 @@
260
1036
  height: 16px;
261
1037
  }
262
1038
 
1039
+ /*
1040
+ * A wide table scrolls horizontally inside its wrapper (the block box) instead
1041
+ * of overflowing the page and scrolling the editor's fixed left gutter away.
1042
+ * The wrapper is the scroll viewport the selection/caret clipping measures (see
1043
+ * `BlockViewNode.scrollElement` / `blockViewportClip`); the inner `<table>`
1044
+ * keeps `width: auto` (theme-defined) so it sizes to its content and overflows.
1045
+ *
1046
+ * `width: fit-content` keeps the wrapper hugging the table's intrinsic width, so
1047
+ * a narrow table — and the active-block glow redirected onto the wrapper below —
1048
+ * stays as wide as the table (unchanged from before this wrapper existed).
1049
+ * `max-width: 100%` caps it at the content column, past which the table
1050
+ * overflows and scrolls locally. This is the standard responsive-table pattern
1051
+ * (cf. GitHub's own `width: max-content; max-width: 100%`).
1052
+ */
1053
+ .md-table-wrapper {
1054
+ overflow-x: auto;
1055
+ width: fit-content;
1056
+ max-width: 100%;
1057
+ }
1058
+
1059
+ /*
1060
+ * The active-block highlight is an *outset* glow (`box-shadow: 0 0 0 8px`).
1061
+ * Making the wrapper a scroll box (`overflow-x: auto`, which also forces
1062
+ * `overflow-y: auto`) clips descendant paint to its padding box, so the glow on
1063
+ * the inner active `<table>` would be cut off (the table has no horizontal
1064
+ * margin to give the shadow room). Render the generic active chrome on the
1065
+ * wrapper instead — a scroll box's own shadow is never clipped by its own
1066
+ * overflow, exactly like a code block carries the glow on its own scroller —
1067
+ * and drop it from the table, which keeps `md-block-active` purely for the
1068
+ * per-theme source-pipe styling.
1069
+ */
1070
+ .md-table-wrapper:has(> .md-table.md-block-active) {
1071
+ background: var(--md-block-active-background, #f8f8f8);
1072
+ border-radius: 4px;
1073
+ box-shadow: 0 0 0 8px var(--md-block-active-background, #f8f8f8);
1074
+ }
1075
+
1076
+ .md-table.md-block-active {
1077
+ background: none;
1078
+ box-shadow: none;
1079
+ }
1080
+
263
1081
  .md-selection-layer {
264
1082
  position: absolute;
265
1083
  top: 0;
@@ -274,6 +1092,54 @@
274
1092
  fill: rgba(59, 130, 246, 0.25);
275
1093
  }
276
1094
 
1095
+ /*
1096
+ * Gutter markers (source-control style change indicators). The layer fills the
1097
+ * content box; each marker is an absolutely-positioned bar pinned to the left
1098
+ * gutter (inside `.md-editor-content`'s 48px padding). The view sets only
1099
+ * `top`/`height`; horizontal placement, width and color live here so themes can
1100
+ * tune them without touching layout. Like the other overlays it never eats
1101
+ * pointer events.
1102
+ */
1103
+ .md-gutter-layer {
1104
+ position: absolute;
1105
+ top: 0;
1106
+ left: 0;
1107
+ width: 100%;
1108
+ height: 100%;
1109
+ pointer-events: none;
1110
+ overflow: visible;
1111
+ }
1112
+
1113
+ .md-gutter-marker {
1114
+ position: absolute;
1115
+ left: var(--md-gutter-marker-left, 18px);
1116
+ width: var(--md-gutter-marker-width, 3px);
1117
+ border-radius: 2px;
1118
+ }
1119
+
1120
+ .md-gutter-marker-added {
1121
+ background: var(--md-gutter-added, #2ea043);
1122
+ }
1123
+
1124
+ .md-gutter-marker-modified {
1125
+ background: var(--md-gutter-modified, #0969da);
1126
+ }
1127
+
1128
+ /*
1129
+ * A deletion has no lines to span, so it is drawn as a downward-pointing
1130
+ * triangle centered on the seam where the removed text used to be (the top of
1131
+ * the line that now follows it), matching the git deleted-lines affordance.
1132
+ */
1133
+ .md-gutter-marker-deleted {
1134
+ width: 0;
1135
+ height: 0;
1136
+ border-radius: 0;
1137
+ border-left: var(--md-gutter-marker-width, 3px) solid var(--md-gutter-deleted, #cf222e);
1138
+ border-top: 4px solid transparent;
1139
+ border-bottom: 4px solid transparent;
1140
+ transform: translateY(-4px);
1141
+ }
1142
+
277
1143
  /* Source markers occupy the gutter so toggling them never shifts content. */
278
1144
  .md-heading {
279
1145
  position: relative;
@@ -327,9 +1193,26 @@
327
1193
 
328
1194
  .md-blockquote>.md-marker-blockQuoteMarker {
329
1195
  position: absolute;
330
- right: calc(100% - var(--md-blockquote-pad, 0px));
1196
+ right: calc(100% - var(--md-blockquote-pad, 0px) - 1ch);
331
1197
  top: auto;
1198
+ /*
1199
+ * Reserve the optional-space column so adding it cannot move the `>` glyph,
1200
+ * then shift and scale every active quote marker consistently to leave a
1201
+ * virtual gap before body text without consuming source width. These tuned
1202
+ * properties are shared by ordinary and marker-only quote lines.
1203
+ */
1204
+ --md-blockquote-marker-shift: -0.18ch;
1205
+ --md-blockquote-marker-scale: 0.9;
1206
+ display: inline-flex;
1207
+ min-width: 2ch;
1208
+ font-size: inherit;
1209
+ line-height: inherit;
1210
+ height: 1lh;
1211
+ align-items: center;
1212
+ text-align: left;
332
1213
  white-space: pre;
1214
+ transform: translateX(var(--md-blockquote-marker-shift)) scale(var(--md-blockquote-marker-scale));
1215
+ transform-origin: left center;
333
1216
  }
334
1217
 
335
1218
  /* Inactive: gone entirely (the gutter is empty, the text stays put). */
@@ -337,6 +1220,16 @@
337
1220
  display: none;
338
1221
  }
339
1222
 
1223
+ /* Collapsed block-gap newlines still need one flow box per marker-only line. */
1224
+ .md-blockquote-line-anchor {
1225
+ display: block;
1226
+ }
1227
+
1228
+ /* A trailing marker-only source line follows the preceding quoted line directly. */
1229
+ .md-blockquote-marker-only-line>.md-paragraph:last-of-type {
1230
+ margin-bottom: 0;
1231
+ }
1232
+
340
1233
  /* Code/math blocks scroll horizontally; their look is theme-defined. */
341
1234
  .md-code-block {
342
1235
  overflow-x: auto;
@@ -346,14 +1239,7 @@
346
1239
  overflow-x: auto;
347
1240
  }
348
1241
 
349
- /*
350
- * Paragraphs inside list items render inline so the item's content sits on
351
- * the same line as the list counter / source marker instead of wrapping
352
- * below it. Block-level <p> here would push the text down even with zero
353
- * margin, because the counter sits at the start of the principal box.
354
- */
355
1242
  .md-list li>.md-paragraph {
356
- display: inline;
357
1243
  margin: 0;
358
1244
  }
359
1245
 
@@ -376,19 +1262,50 @@
376
1262
  * before the marker. Gutter-positioning keeps the marker out of the inline
377
1263
  * flow so toggling it never shifts the item's text horizontally.
378
1264
  *
379
- * `line-height: inherit` makes the marker share the item's line box (its own
380
- * `.md-marker` rule shrinks it to `line-height: 1`, which floats the glyph to
381
- * the top of the taller text line); matching the line box vertically centres
382
- * the `-` with the rendered text.
1265
+ * Vertical centring makes the marker box exactly the item's first line box and
1266
+ * centres the glyph in it. Getting that box right is the whole trick: an
1267
+ * inherited UNITLESS line-height is re-resolved against the element's own
1268
+ * font-size, so a marker shrunk by `--md-marker-font-scale` also gets a
1269
+ * proportionally shorter line box which, pinned at `top: 0`, floats the glyph
1270
+ * above the text. Dividing `1lh` by that same scale cancels the shrink exactly,
1271
+ * without touching the painted size and without a `transform` (which would
1272
+ * shrink the box the caret geometry is measured from).
383
1273
  */
384
1274
  .md-list-item-active>.md-marker-listItemMarker {
385
1275
  position: absolute;
386
1276
  right: 100%;
387
1277
  top: 0;
388
1278
  line-height: inherit;
1279
+ height: calc(1lh / var(--md-marker-font-scale));
1280
+ display: inline-flex;
1281
+ align-items: center;
1282
+ justify-content: flex-end;
389
1283
  white-space: pre;
390
1284
  }
391
1285
 
1286
+ /*
1287
+ * `display: inline-flex` above outranks the plain `.md-marker-hidden`
1288
+ * (`display: none`), so — exactly as for headings — re-hide the marker here for
1289
+ * the states that ask for it, otherwise the bullet could never be hidden.
1290
+ */
1291
+ .md-list-item-active>.md-marker-listItemMarker.md-marker-hidden {
1292
+ display: none;
1293
+ }
1294
+
1295
+ /*
1296
+ * An inactive ordered item uses the browser's native `::marker`. Match its
1297
+ * typography when revealing the source marker so switching the active item
1298
+ * does not change the number's width or horizontal position: an ordered marker
1299
+ * opts out of the muted size step entirely, which also makes the `1lh`
1300
+ * compensation above a no-op for it. Keep unordered source markers in the
1301
+ * standard muted monospace source style.
1302
+ */
1303
+ ol.md-list>.md-list-item-active>.md-marker-listItemMarker,
1304
+ ol.md-list>.md-list-item-active>.md-list-gutter>.md-marker-listItemMarker {
1305
+ font-family: inherit;
1306
+ --md-marker-font-scale: 1;
1307
+ }
1308
+
392
1309
  /*
393
1310
  * A nested item's source indentation precedes its bullet (`␣␣- text`). The
394
1311
  * indent glue and the bullet are mounted together in this gutter span, which is
@@ -421,6 +1338,25 @@
421
1338
  flex: 0 0 auto;
422
1339
  }
423
1340
 
1341
+ /*
1342
+ * A NESTED item's bullet is a flex child of the gutter, so the direct-child
1343
+ * rule above cannot reach it and it would otherwise stretch to the gutter's
1344
+ * full height with its glyph parked at the top. Centring is therefore done by
1345
+ * the gutter itself: it is statically positioned (hence aligned to the item's
1346
+ * first line), so making it one line box tall and centring its children puts
1347
+ * the bullet and the indentation dots on that line.
1348
+ *
1349
+ * The gutter carries body typography, so its `1lh` needs no compensation — and
1350
+ * the bullet inside keeps its own muted `font-size`, which is exactly what the
1351
+ * shrink-to-fit gutter reserves. Shrinking the bullet visually instead would
1352
+ * make the gutter reserve more width than the bullet paints and slide the whole
1353
+ * indentation column left.
1354
+ */
1355
+ .md-list-item-active>.md-list-gutter {
1356
+ height: 1lh;
1357
+ align-items: center;
1358
+ }
1359
+
424
1360
 
425
1361
  /*
426
1362
  * Re-attributed source indentation (the spaces after a line break that precede
@@ -433,20 +1369,73 @@
433
1369
  white-space: pre;
434
1370
  }
435
1371
 
1372
+ /*
1373
+ * A continuation-line indent inside a paragraph is source-only padding. When
1374
+ * inactive, the preceding soft-break newline already collapses to the single
1375
+ * rendered space Markdown requires; retaining the hidden indent would add the
1376
+ * tab/space run's width on top of it.
1377
+ */
1378
+ .md-paragraph>.md-glue-indent.md-glue-hidden {
1379
+ display: none;
1380
+ }
1381
+
1382
+ /*
1383
+ * A loose list item's later block (its second paragraph etc.) owns the source
1384
+ * continuation indent that precedes it as its `leadingTrivia`. Like a nested
1385
+ * list's gutter, that indent glue is pulled out of flow to the left so it never
1386
+ * widens the line: the block's text stays aligned with the first paragraph
1387
+ * above it, and the indent dots only appear in the left margin when the block is
1388
+ * active (the footprint is identical in both states, so the text never shifts).
1389
+ */
1390
+ .md-list li>.md-block,
1391
+ .md-task-list-item>.md-block {
1392
+ position: relative;
1393
+ }
1394
+
1395
+ .md-list li>.md-block>.md-glue-indent:first-child,
1396
+ .md-task-list-item>.md-block>.md-glue-indent:first-child {
1397
+ position: absolute;
1398
+ right: 100%;
1399
+ top: 0;
1400
+ }
1401
+
436
1402
  .md-task-list-item {
437
1403
  list-style: none;
438
1404
  position: relative;
1405
+ /*
1406
+ * Width of the checkbox / `[x]` source column. Single-sourced so the marker
1407
+ * reservation on the first paragraph and the left indent of any following
1408
+ * block (loose task items) stay in lockstep — keeping every block's text in
1409
+ * one vertical column under the marker.
1410
+ */
1411
+ --md-task-marker-width: 1.75em;
1412
+ }
1413
+
1414
+ /*
1415
+ * Reserve the marker column on the paragraph rather than only on its first
1416
+ * inline child. This gives every wrapped line the same content edge. The
1417
+ * source marker glue is positioned over that reserved column, as is the
1418
+ * rendered checkbox, so activating the item does not shift its text (see the
1419
+ * compare fixture's `checkMarkedTextX` assertion).
1420
+ */
1421
+ .md-task-list-item>.md-paragraph {
1422
+ padding-left: var(--md-task-marker-width);
1423
+ }
1424
+
1425
+ .md-task-list-item>.md-paragraph>.md-glue:first-child {
1426
+ position: absolute;
1427
+ top: 0;
1428
+ left: 0;
1429
+ width: var(--md-task-marker-width);
439
1430
  }
440
1431
 
441
1432
  /*
442
- * Reserve extra width after the `[x]`/`[ ]` source marker (the first glue in a
443
- * task item's paragraph) so the rendered checkbox widget overlaid on it has a
444
- * comfortable gap before the text. The padding applies in both active and
445
- * inactive states, so the first text character does not drift horizontally when
446
- * markers toggle (see the compare fixture's `checkMarkedTextX` assertion).
1433
+ * Following blocks in a loose task item (the second paragraph etc.) carry no
1434
+ * marker glue, so indent them by the marker column to line their text up under
1435
+ * the first paragraph's text rather than under the checkbox.
447
1436
  */
448
- .md-task-list-item .md-paragraph>.md-glue:first-child {
449
- padding-right: 0.7em;
1437
+ .md-task-list-item>.md-block+.md-block {
1438
+ padding-left: var(--md-task-marker-width);
450
1439
  }
451
1440
 
452
1441
  .md-checkbox {
@@ -461,6 +1450,7 @@
461
1450
  position: absolute;
462
1451
  left: 0;
463
1452
  top: 0.25em;
1453
+ z-index: 1;
464
1454
  cursor: pointer;
465
1455
  transition: background-color 0.15s ease, border-color 0.15s ease;
466
1456
  }
@@ -473,8 +1463,8 @@
473
1463
  .md-checkbox:checked::after {
474
1464
  content: '';
475
1465
  position: absolute;
476
- left: 3px;
477
- top: 0px;
1466
+ left: 2.5px;
1467
+ top: -1px;
478
1468
  width: 5px;
479
1469
  height: 9px;
480
1470
  border: solid white;
@@ -486,6 +1476,39 @@
486
1476
  border-color: #888;
487
1477
  }
488
1478
 
1479
+ /*
1480
+ * The rotating "broken rounded-square" progress ring for an inactive task item
1481
+ * whose text begins with the hidden `:running:` marker (see
1482
+ * `ListItemViewData.isRunning`). Rendered as a conic-gradient ring — masked so
1483
+ * only the ring (not its center) paints — with a transparent gap that spins,
1484
+ * reading as a segmented spinner rather than a checked/unchecked box.
1485
+ */
1486
+ .md-checkbox-running,
1487
+ .md-checkbox-running:checked {
1488
+ padding: 2px;
1489
+ border: 0;
1490
+ border-radius: 4px;
1491
+ background: conic-gradient(
1492
+ transparent 0deg 42deg,
1493
+ #bbb 62deg 360deg
1494
+ );
1495
+ -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
1496
+ -webkit-mask-composite: xor;
1497
+ mask-composite: exclude;
1498
+ animation: md-checkbox-spin 0.8s linear infinite;
1499
+ opacity: 1;
1500
+ }
1501
+
1502
+ @keyframes md-checkbox-spin {
1503
+ to {
1504
+ transform: rotate(360deg);
1505
+ }
1506
+ }
1507
+
1508
+ .md-checkbox-running:hover {
1509
+ border-color: transparent;
1510
+ }
1511
+
489
1512
  .md-checkbox:checked:hover {
490
1513
  background-color: #3a73d4;
491
1514
  border-color: #3a73d4;
@@ -496,14 +1519,66 @@
496
1519
  opacity: 0.6;
497
1520
  }
498
1521
 
1522
+ .md-checkbox-running:disabled {
1523
+ opacity: 1;
1524
+ }
1525
+
1526
+ @media (prefers-reduced-motion: reduce) {
1527
+ .md-checkbox-running {
1528
+ animation: none !important;
1529
+ }
1530
+ }
1531
+
1532
+ /*
1533
+ * The `:running:` marker hidden from an inactive task item's rendered text
1534
+ * (see `TextViewData.hiddenPrefixLength`). It stays real, selectable source —
1535
+ * only visually hidden, per "Hidden markers remain real source" — so it takes
1536
+ * no layout space in either state.
1537
+ */
1538
+ .md-runner-marker {
1539
+ display: none;
1540
+ }
1541
+
499
1542
  .md-cursor {
500
1543
  position: absolute;
501
1544
  width: 2px;
502
- background: #000;
1545
+ background: var(--md-cursor-background, #000);
503
1546
  pointer-events: none;
1547
+ }
1548
+
1549
+ /*
1550
+ * The painted caret is only shown while the editor is genuinely focused — focus
1551
+ * rests inside it and its window is focused, mirrored onto the root as
1552
+ * `.md-focused`. When unfocused, hide the caret element but keep its layout box
1553
+ * (so caret geometry, selection and comment anchoring are unchanged) and stop
1554
+ * the blink. Adding the animation on focus restarts it from 0% (a solid caret).
1555
+ */
1556
+ .md-editor:not(.md-focused) .md-cursor {
1557
+ visibility: hidden;
1558
+ }
1559
+
1560
+ .md-editor.md-focused .md-cursor {
504
1561
  animation: md-cursor-blink 1s step-end infinite;
505
1562
  }
506
1563
 
1564
+ /*
1565
+ * Read-only mode retains the logical caret for selection and comment anchoring.
1566
+ * Hide only its painted element so unlocking can restore it in place.
1567
+ */
1568
+ .md-editor.md-readonly .md-cursor {
1569
+ visibility: hidden;
1570
+ }
1571
+
1572
+ .md-editor.md-readonly-editing-attempt {
1573
+ animation: md-readonly-editing-attempt 300ms ease-out;
1574
+ }
1575
+
1576
+ @keyframes md-readonly-editing-attempt {
1577
+ 50% {
1578
+ box-shadow: inset 0 0 0 2px var(--md-readonly-shine-glow, rgba(255, 255, 255, 0.58));
1579
+ }
1580
+ }
1581
+
507
1582
  @keyframes md-cursor-blink {
508
1583
 
509
1584
  0%,
@@ -514,4 +1589,201 @@
514
1589
  50% {
515
1590
  opacity: 0;
516
1591
  }
1592
+ }
1593
+
1594
+ /*
1595
+ * Edit / read-only lock toggle.
1596
+ *
1597
+ * The asymmetric content padding reserves a real rail for the control:
1598
+ * button width + gap + edge inset. The zero-height sticky host spans the
1599
+ * document column and that rail, keeping the button beside (never over) the
1600
+ * rendered document as it scrolls. Colors use local `--md-readonly-*` custom
1601
+ * properties with literal fallbacks so this base file stays theme-agnostic
1602
+ * (themes may override them).
1603
+ */
1604
+ .md-readonly-toggle-host {
1605
+ position: sticky;
1606
+ top: 0;
1607
+ width: calc(100% + var(--md-editor-content-inline-end-padding));
1608
+ height: 0;
1609
+ z-index: 10;
1610
+ pointer-events: none;
1611
+ }
1612
+
1613
+ .md-readonly-toggle {
1614
+ position: absolute;
1615
+ top: 4px;
1616
+ right: var(--md-readonly-toggle-inset);
1617
+ pointer-events: auto;
1618
+ display: inline-grid;
1619
+ grid-template-columns: repeat(2, 24px);
1620
+ align-items: center;
1621
+ justify-items: center;
1622
+ gap: 2px;
1623
+ box-sizing: border-box;
1624
+ width: var(--md-readonly-toggle-width);
1625
+ height: var(--md-readonly-toggle-height);
1626
+ padding: 3px;
1627
+ overflow: hidden;
1628
+ direction: ltr;
1629
+ appearance: none;
1630
+ border-radius: 999px;
1631
+ border: 1px solid var(--md-readonly-border, #b8b8b8);
1632
+ background: var(--md-readonly-background, #f3f3f3);
1633
+ color: var(--md-readonly-foreground, #444444);
1634
+ font-size: 16px;
1635
+ line-height: 1;
1636
+ cursor: pointer;
1637
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.08);
1638
+ transition: background-color 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease;
1639
+ }
1640
+
1641
+ /*
1642
+ * Below this width there is not enough document column for the side rail to be
1643
+ * useful. Give the host its own row and stop it from sticking, so neither long
1644
+ * unbreakable content nor later content scrolled through the viewport can ever
1645
+ * pass underneath the button.
1646
+ */
1647
+ .md-editor-narrow .md-readonly-toggle-host {
1648
+ position: relative;
1649
+ height: calc(var(--md-readonly-toggle-height) + var(--md-readonly-toggle-inset) + var(--md-readonly-toggle-inset));
1650
+ }
1651
+
1652
+ .md-readonly-toggle::after {
1653
+ content: '';
1654
+ position: absolute;
1655
+ z-index: 2;
1656
+ top: -8px;
1657
+ bottom: -8px;
1658
+ left: -30px;
1659
+ width: 24px;
1660
+ background: linear-gradient(90deg,
1661
+ transparent,
1662
+ var(--md-readonly-shine-edge, rgba(255, 255, 255, 0.16)) 24%,
1663
+ var(--md-readonly-shine, #ffffff) 50%,
1664
+ var(--md-readonly-shine-edge, rgba(255, 255, 255, 0.16)) 76%,
1665
+ transparent);
1666
+ box-shadow: 0 0 8px 2px var(--md-readonly-shine-glow, rgba(255, 255, 255, 0.58));
1667
+ opacity: 0;
1668
+ pointer-events: none;
1669
+ transform: skewX(-20deg);
1670
+ }
1671
+
1672
+ .md-readonly-toggle.md-readonly-toggle-shine::after {
1673
+ animation: md-readonly-toggle-shine 2s linear;
1674
+ will-change: transform, opacity;
1675
+ }
1676
+
1677
+ @keyframes md-readonly-toggle-shine {
1678
+ 0% {
1679
+ opacity: 0;
1680
+ transform: translateX(0) skewX(-20deg);
1681
+ }
1682
+
1683
+ 12%,
1684
+ 88% {
1685
+ opacity: 1;
1686
+ }
1687
+
1688
+ 100% {
1689
+ opacity: 0;
1690
+ transform: translateX(122px) skewX(-20deg);
1691
+ }
1692
+ }
1693
+
1694
+ .md-readonly-toggle:hover {
1695
+ border-color: var(--md-readonly-border-hover, #8d8d8d);
1696
+ background: var(--md-readonly-background-hover, #e9e9e9);
1697
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 6px 16px rgba(0, 0, 0, 0.1);
1698
+ }
1699
+
1700
+ .md-readonly-toggle:focus-visible {
1701
+ outline: 2px solid var(--md-readonly-accent, #4c8bf5);
1702
+ outline-offset: 1px;
1703
+ }
1704
+
1705
+ .md-readonly-toggle .md-readonly-toggle-indicator {
1706
+ position: absolute;
1707
+ top: 50%;
1708
+ left: 3px;
1709
+ width: 24px;
1710
+ height: 24px;
1711
+ border-radius: 50%;
1712
+ background: var(--md-readonly-accent, #4c8bf5);
1713
+ box-shadow: 0 0 3px rgba(0, 0, 0, 0.25);
1714
+ transform: translate(26px, -50%);
1715
+ transition: background-color 0.12s ease, transform 0.16s ease;
1716
+ }
1717
+
1718
+ .md-readonly-toggle .md-readonly-toggle-icon {
1719
+ position: relative;
1720
+ z-index: 1;
1721
+ display: block;
1722
+ width: 16px;
1723
+ height: 16px;
1724
+ color: var(--md-readonly-foreground, #444444);
1725
+ opacity: 0.62;
1726
+ pointer-events: none;
1727
+ transition: color 0.12s ease, opacity 0.12s ease;
1728
+ }
1729
+
1730
+ .md-readonly-toggle:not(.md-readonly-toggle-locked) .md-readonly-toggle-icon-editing,
1731
+ .md-readonly-toggle.md-readonly-toggle-locked .md-readonly-toggle-icon-locked {
1732
+ color: var(--md-readonly-accent-foreground, #ffffff);
1733
+ opacity: 1;
1734
+ }
1735
+
1736
+ .md-readonly-toggle.md-readonly-toggle-locked .md-readonly-toggle-indicator {
1737
+ transform: translate(0, -50%);
1738
+ }
1739
+
1740
+ @media (prefers-reduced-motion: reduce) {
1741
+
1742
+ .md-editor.md-readonly-editing-attempt,
1743
+ .md-readonly-toggle,
1744
+ .md-readonly-toggle .md-readonly-toggle-indicator,
1745
+ .md-readonly-toggle .md-readonly-toggle-icon,
1746
+ .md-readonly-toggle.md-readonly-toggle-shine::after {
1747
+ animation: none;
1748
+ transition: none;
1749
+ }
1750
+ }
1751
+
1752
+ @media (forced-colors: active) {
1753
+ .md-readonly-toggle {
1754
+ forced-color-adjust: none;
1755
+ border-color: ButtonText;
1756
+ background: ButtonFace;
1757
+ color: ButtonText;
1758
+ box-shadow: none;
1759
+ }
1760
+
1761
+ .md-readonly-toggle::after {
1762
+ display: none;
1763
+ }
1764
+
1765
+ .md-readonly-toggle:hover {
1766
+ border-color: Highlight;
1767
+ background: ButtonFace;
1768
+ box-shadow: none;
1769
+ }
1770
+
1771
+ .md-readonly-toggle:focus-visible {
1772
+ outline-color: Highlight;
1773
+ }
1774
+
1775
+ .md-readonly-toggle .md-readonly-toggle-indicator {
1776
+ background: Highlight;
1777
+ box-shadow: none;
1778
+ }
1779
+
1780
+ .md-readonly-toggle .md-readonly-toggle-icon {
1781
+ color: ButtonText;
1782
+ opacity: 1;
1783
+ }
1784
+
1785
+ .md-readonly-toggle:not(.md-readonly-toggle-locked) .md-readonly-toggle-icon-editing,
1786
+ .md-readonly-toggle.md-readonly-toggle-locked .md-readonly-toggle-icon-locked {
1787
+ color: HighlightText;
1788
+ }
517
1789
  }