@quillmark/svelte 0.2.0 → 0.3.1

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 (119) hide show
  1. package/NOTICE +6 -6
  2. package/README.md +3 -3
  3. package/THEMING.md +12 -8
  4. package/dist/core/address.d.ts +7 -7
  5. package/dist/core/address.js +6 -6
  6. package/dist/core/bloom.d.ts +3 -32
  7. package/dist/core/bloom.js +19 -51
  8. package/dist/core/codec/anchor.d.ts +1 -1
  9. package/dist/core/codec/anchor.js +1 -1
  10. package/dist/core/codec/atoms.d.ts +10 -0
  11. package/dist/core/codec/atoms.js +78 -0
  12. package/dist/core/codec/clipboard.d.ts +59 -0
  13. package/dist/core/codec/clipboard.js +202 -0
  14. package/dist/core/codec/code.d.ts +1 -1
  15. package/dist/core/codec/code.js +4 -4
  16. package/dist/core/codec/decode.d.ts +1 -1
  17. package/dist/core/codec/decode.js +8 -8
  18. package/dist/core/codec/encode.d.ts +4 -4
  19. package/dist/core/codec/encode.js +10 -10
  20. package/dist/core/codec/field.d.ts +21 -26
  21. package/dist/core/codec/field.js +33 -32
  22. package/dist/core/codec/index.js +5 -8
  23. package/dist/core/codec/inputrules.js +56 -18
  24. package/dist/core/codec/islands.d.ts +11 -7
  25. package/dist/core/codec/islands.js +16 -10
  26. package/dist/core/codec/keymap.d.ts +5 -6
  27. package/dist/core/codec/keymap.js +8 -7
  28. package/dist/core/codec/lists.d.ts +3 -3
  29. package/dist/core/codec/lists.js +32 -13
  30. package/dist/core/codec/marks.d.ts +1 -1
  31. package/dist/core/codec/marks.js +1 -1
  32. package/dist/core/codec/positions.js +1 -1
  33. package/dist/core/codec/prose.css +235 -221
  34. package/dist/core/codec/schema.js +4 -4
  35. package/dist/core/codec/slash.d.ts +39 -41
  36. package/dist/core/codec/slash.js +0 -0
  37. package/dist/core/codec/table-view.d.ts +12 -16
  38. package/dist/core/codec/table-view.js +488 -292
  39. package/dist/core/codec/table.d.ts +42 -15
  40. package/dist/core/codec/table.js +70 -26
  41. package/dist/core/errors.d.ts +5 -5
  42. package/dist/core/index.js +2 -2
  43. package/dist/core/lifecycle.js +1 -1
  44. package/dist/core/rebind.svelte.d.ts +2 -2
  45. package/dist/core/rebind.svelte.js +4 -4
  46. package/dist/core/teardown.d.ts +1 -1
  47. package/dist/core/teardown.js +1 -1
  48. package/dist/core/theme.css +170 -64
  49. package/dist/preset/index.css +1 -1
  50. package/dist/preset/recipes.css +31 -29
  51. package/dist/preset/scale.css +37 -26
  52. package/dist/preview/Preview.svelte +17 -27
  53. package/dist/preview/Preview.svelte.d.ts +4 -5
  54. package/dist/preview/bridge.js +6 -6
  55. package/dist/preview/controller.d.ts +8 -10
  56. package/dist/preview/controller.js +19 -44
  57. package/dist/preview/geometry.d.ts +8 -10
  58. package/dist/preview/geometry.js +8 -10
  59. package/dist/preview/index.js +4 -4
  60. package/dist/preview/paint.d.ts +1 -1
  61. package/dist/preview/paint.js +17 -19
  62. package/dist/visual/ArrayField.svelte +80 -66
  63. package/dist/visual/ArrayField.svelte.d.ts +1 -1
  64. package/dist/visual/BooleanField.svelte +8 -6
  65. package/dist/visual/BooleanField.svelte.d.ts +2 -2
  66. package/dist/visual/Card.svelte +160 -329
  67. package/dist/visual/Card.svelte.d.ts +2 -7
  68. package/dist/visual/CardControls.svelte +1 -1
  69. package/dist/visual/DateField.svelte +19 -19
  70. package/dist/visual/DateField.svelte.d.ts +3 -3
  71. package/dist/visual/DiagnosticList.svelte +1 -1
  72. package/dist/visual/EnumField.svelte +16 -16
  73. package/dist/visual/EnumField.svelte.d.ts +2 -2
  74. package/dist/visual/Field.svelte +128 -115
  75. package/dist/visual/Field.svelte.d.ts +1 -1
  76. package/dist/visual/FieldHint.svelte +24 -42
  77. package/dist/visual/FieldHint.svelte.d.ts +1 -1
  78. package/dist/visual/FieldLabel.svelte +8 -8
  79. package/dist/visual/FormatPopover.svelte +80 -35
  80. package/dist/visual/NumberField.svelte +5 -5
  81. package/dist/visual/NumberField.svelte.d.ts +1 -1
  82. package/dist/visual/ObjectField.svelte +9 -9
  83. package/dist/visual/ObjectField.svelte.d.ts +1 -1
  84. package/dist/visual/ProseArrayElement.svelte +11 -13
  85. package/dist/visual/ProseArrayElement.svelte.d.ts +1 -1
  86. package/dist/visual/ProseField.svelte +53 -87
  87. package/dist/visual/ProseField.svelte.d.ts +13 -19
  88. package/dist/visual/SlashMenu.svelte +42 -16
  89. package/dist/visual/TextField.svelte +5 -5
  90. package/dist/visual/TextField.svelte.d.ts +1 -1
  91. package/dist/visual/TipsCard.svelte +68 -56
  92. package/dist/visual/VisualEditor.svelte +6 -6
  93. package/dist/visual/VisualEditorInner.svelte +203 -290
  94. package/dist/visual/controls.css +74 -30
  95. package/dist/visual/diagnostics.d.ts +5 -5
  96. package/dist/visual/diagnostics.js +3 -3
  97. package/dist/visual/domid.js +3 -3
  98. package/dist/visual/ext.d.ts +1 -1
  99. package/dist/visual/ext.js +1 -1
  100. package/dist/visual/icons/nodes.d.ts +19 -0
  101. package/dist/visual/icons/nodes.js +13 -1
  102. package/dist/visual/index.js +4 -4
  103. package/dist/visual/leaves.d.ts +3 -3
  104. package/dist/visual/leaves.js +1 -1
  105. package/dist/visual/links.d.ts +24 -0
  106. package/dist/visual/links.js +67 -0
  107. package/dist/visual/props.d.ts +8 -8
  108. package/dist/visual/signals.d.ts +6 -6
  109. package/dist/visual/strings.d.ts +14 -19
  110. package/dist/visual/strings.js +5 -7
  111. package/dist/visual/structure.d.ts +24 -17
  112. package/dist/visual/structure.js +8 -8
  113. package/dist/visual/synced.svelte.d.ts +1 -1
  114. package/dist/visual/synced.svelte.js +4 -4
  115. package/dist/visual/tips.d.ts +2 -2
  116. package/dist/visual/tips.js +3 -3
  117. package/package.json +2 -2
  118. package/dist/preview/overlay.d.ts +0 -11
  119. package/dist/preview/overlay.js +0 -97
@@ -1,16 +1,13 @@
1
1
  <!--
2
- One card block: the header (composable cards only: an inline-editable title over
3
- a full-width rename region, and the reorder/
4
- delete controls), the grouped field list packed by `ui.group`/`ui.compact`, and
5
- the body prose leaf. `main` is headerless with no controls. Every prose leaf
6
- takes a parent-built LIVE address so a card reorder re-targets its commits
7
- without a remount.
2
+ One card block, its fields grouped by `ui.group`/`ui.compact`. `main` is headerless
3
+ and takes no controls. Every prose leaf takes a parent-built live address, so a card
4
+ reorder re-targets its commits without a remount.
8
5
  -->
9
6
  <script lang="ts">
10
7
  import { wording } from './strings.js';
11
8
 
12
- // The surface's words, ambient from the editor root; the package's English
13
- // off-tree, so this component renders standalone too.
9
+ // Ambient from the editor root, with the package's English off-tree, so this
10
+ // component renders standalone too.
14
11
  const t = wording();
15
12
  import { untrack } from 'svelte';
16
13
  import Icon from './icons/Icon.svelte';
@@ -44,30 +41,24 @@
44
41
  interface Props {
45
42
  card: CardModel;
46
43
  doc: Document;
47
- /** The schema a prose leaf reads its content through (`ProseField`). */
48
44
  quill: Quill;
49
- index: number;
50
45
  isFirst: boolean;
51
46
  isLast: boolean;
52
47
  kinds: string[];
53
48
  ops: CardOps;
54
- /** How an option `ops.enumAllowed` refuses draws. Nothing about it is per-card,
55
- * so it sits beside the bundle rather than in it. */
56
49
  enumDisallowed?: 'hide' | 'disable';
57
50
  onFocus?: (addr: Addr) => void;
58
51
  onCaretMove?: (addr: Addr, pos: number) => void;
59
52
  onChange?: (addr: Addr) => void;
60
53
  onError?: EditorErrorHandler;
61
- /** The editor's leaf registry (`leaves.ts`): every field in this card registers
62
- * its landing handle, which is what the editor's `focusField`/`setCaret`
63
- * resolve a `DocPath` to. */
54
+ /** Every field in this card registers its landing handle here, which is what the
55
+ * editor's `focusField`/`setCaret` resolve a `DocPath` to. */
64
56
  leaves?: LeafRegistry;
65
57
  }
66
58
  let {
67
59
  card,
68
60
  doc,
69
61
  quill,
70
- index,
71
62
  isFirst,
72
63
  isLast,
73
64
  kinds,
@@ -90,18 +81,15 @@
90
81
  });
91
82
  });
92
83
 
93
- // Inline-editable title: select-all on entry so a title reads as
94
- // text you replace, and Enter/Escape as commit/revert. Rename stays LIVE on
95
- // input: `titleAtFocus` is the pre-edit value Escape rolls back to.
84
+ // The pre-edit value Escape rolls back to; the rename itself stays live on input.
96
85
  let titleAtFocus = '';
97
86
  function onTitleFocus(e: FocusEvent): void {
98
87
  titleAtFocus = localTitle;
99
88
  (e.currentTarget as HTMLInputElement).select();
100
89
  }
101
- // A mouse press on an UNFOCUSED title would place a caret on mouseup, collapsing
102
- // the focus-time select-all. Take focus manually and suppress that caret so a
103
- // click-to-enter selects all too; a press while already focused stays normal, so
104
- // clicking mid-title to place the caret still works.
90
+ // A press on an unfocused title would place a caret on mouseup, collapsing the
91
+ // focus-time select-all. A press while already focused stays normal, so clicking
92
+ // mid-title to place the caret still works.
105
93
  function onTitleMousedown(e: MouseEvent): void {
106
94
  const el = e.currentTarget as HTMLInputElement;
107
95
  if (document.activeElement !== el) {
@@ -109,11 +97,8 @@
109
97
  el.focus();
110
98
  }
111
99
  }
112
- // The rename region extends the title's hit area to the header's free width.
113
- // A press on that empty space focuses the input (which selects all, the
114
- // same click-to-enter the title itself gets) and preventDefault keeps the press
115
- // from starting a text selection on the wrapper. A press ON the input is left to
116
- // `onTitleMousedown`, which owns the already-focused caret-placement case.
100
+ // A press on the region's empty width enters the title edit, and starts no text
101
+ // selection on the wrapper. A press on the input itself is `onTitleMousedown`'s.
117
102
  function onRenameMousedown(e: MouseEvent): void {
118
103
  const input = (e.currentTarget as HTMLElement).querySelector('input');
119
104
  if (!input || e.target === input) return;
@@ -135,36 +120,32 @@
135
120
  }
136
121
  }
137
122
 
138
- // Group accordion. Ungrouped fields (`group == null`) render above,
139
- // always visible; grouped sections collapse into a one-open-at-a-time accordion.
123
+ /** Not `--_qm-glyph-control`: that rung centres a glyph in a tap target, where this
124
+ * one stands in a run of text at the body rung and is sized to sit level with it. */
125
+ const CHEVRON = 16;
126
+
140
127
  const ungrouped = $derived(card.sections.filter((s) => s.group == null));
141
128
  const grouped = $derived(card.sections.filter((s) => s.group != null));
142
129
 
143
- // Whether there is a metadata block to bracket at all. A schema that
144
- // declares no fields still gets a body (`bodyEnabled` defaults true), and a bracket
145
- // around nothing is worse than none: with no content between them the two
146
- // horizontals land on one y and paint as a stroke of twice the width, which is the
147
- // one thing a figure claiming one width cannot do.
130
+ // A schema that declares no fields still gets a body, and a bracket around nothing is
131
+ // worse than none: with no content between them the two horizontals land on one y and
132
+ // paint as a single stroke of twice the width.
148
133
  const hasMeta = $derived(ungrouped.length > 0 || grouped.length > 0);
149
134
 
150
- // Ephemeral session state: the open group's id (`null` = all collapsed). Seeded
151
- // ONCE from the card's shape (structure.initialExpandedGroup); Card is keyed by
152
- // stable id, so this survives the VisualEditor re-derive that reassigns `card`
153
- // and resets only on a remount (reload). Not reconciled to later section changes:
154
- // a retype is the one reshape, and the open group stays where it still exists.
135
+ // Seeded once from the card's shape. Card is keyed by stable id, so this survives the
136
+ // VisualEditor re-derive that reassigns `card` and resets only on a remount. Not
137
+ // reconciled to later section changes: a retype is the one reshape, and the open
138
+ // group stays where it still exists.
155
139
  // svelte-ignore state_referenced_locally
156
140
  let expanded = $state<string | null>(initialExpandedGroup(card.sections));
157
- // The accordion's two elements per group, by group id. A closing panel goes
158
- // `inert` with whatever it held still focused, and `inert` does not say where
159
- // focus should go: the browser drops it on the body, losing the user's place in
160
- // the card. So the close hands focus to the header, which is what reopens the
161
- // section.
162
141
  let headers = $state<Record<string, HTMLButtonElement | undefined>>({});
163
142
  let panels = $state<Record<string, HTMLElement | undefined>>({});
164
143
  /**
165
- * Move to `next` (`null` = all closed), evacuating focus from the group this
166
- * closes. Every write to `expanded` goes through here: a group also closes when
167
- * ANOTHER opens, which is not a gesture the user aimed at the closing section.
144
+ * Move to `next` (`null` = all closed). A closing panel goes `inert` with whatever it
145
+ * held still focused, and `inert` does not say where focus should go — the browser
146
+ * drops it on the body — so the close hands focus to the header, which is what
147
+ * reopens the section. Every write to `expanded` goes through here: a group also
148
+ * closes when another opens.
168
149
  */
169
150
  function setExpanded(next: string | null): void {
170
151
  const closing = expanded;
@@ -177,13 +158,10 @@
177
158
  }
178
159
 
179
160
  /**
180
- * Open the group holding leaf `key`, if this card has one. A collapsed panel is
181
- * clipped to zero height and `inert` rather than unmounted, so a caret placed
182
- * inside it does not land at all and the arrival wash goes unseen.
183
- * `VisualEditor.setCaret` calls this on every card and then waits a flush before
184
- * landing: `inert` clears when the panel renders open, not when `expanded` is
185
- * assigned. The card keeps owning `expanded`, and a card that does not hold the
186
- * key does nothing.
161
+ * Open the group holding leaf `key`: a caret placed in a collapsed panel does not
162
+ * land at all. `VisualEditor.setCaret` calls this on every card and then waits a
163
+ * flush before landing, since `inert` clears when the panel renders open, not when
164
+ * `expanded` is assigned.
187
165
  *
188
166
  * A call, not a prop: a reveal is an event, and modelling it as state needs a
189
167
  * fresh-identity wrapper to re-fire and an `untrack` to keep the per-keystroke
@@ -196,13 +174,10 @@
196
174
 
197
175
  let el = $state<HTMLElement | undefined>(undefined);
198
176
  /**
199
- * Bring this card into view after the structure mutation that placed it:
200
- * `center` for an insert, `nearest` for a reorder that only needs to stay
201
- * on screen. `scrollIntoView` walks to its own scroll ancestor, so this is
202
- * indifferent to whether the package or the consumer owns the scroll container.
203
- *
204
- * The reduced-motion guard is JS rather than the CSS the accordion uses: a
205
- * scroll's behaviour is an argument, not a transition a media query can cancel.
177
+ * Bring this card into view after the structure mutation that placed it: `center` for
178
+ * an insert, `nearest` for a reorder. The reduced-motion guard is JS rather than the
179
+ * CSS the accordion uses: a scroll's behaviour is an argument, not a transition a
180
+ * media query can cancel.
206
181
  */
207
182
  export function scrollIntoViewCard(block: ScrollLogicalPosition): void {
208
183
  const reduce = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
@@ -210,9 +185,6 @@
210
185
  }
211
186
  </script>
212
187
 
213
- <!-- `qm-main` is a structural marker and carries no fill: a tone here would bet on
214
- what the consumer put behind the column, and structure already says which card
215
- this is. -->
216
188
  <section
217
189
  bind:this={el}
218
190
  class="qm-card"
@@ -224,19 +196,9 @@
224
196
  {:else}
225
197
  {#if !card.isMain}
226
198
  <header class="qm-card-header">
227
- <!-- The rename target is the header's whole free width, not the title's text
228
- box. The autosize keeps that box exactly as wide as its
229
- text; this wrapper makes the rest of the row enter the edit too. -->
230
199
  <!-- svelte-ignore a11y_no_static_element_interactions -->
231
200
  <div class="qm-card-rename" onmousedown={onRenameMousedown}>
232
- <!-- Autosize: the sizer span's ::after mirrors the text and dictates the grid
233
- cell width, so the overlaid input grows with content and reads as text,
234
- not a persistent box. `data-value` falls back to the
235
- placeholder so an empty title still reserves its resolved-title width. -->
236
201
  <span class="qm-card-title-sizer" data-value={localTitle || card.titlePlaceholder}>
237
- <!-- `qm-focus-ring` is this control's ONLY focus indicator: the ink step
238
- cannot be one, since hover already takes that step. `:focus-visible`, so
239
- a press enters the edit unringed while a tab into it draws one. -->
240
202
  <input
241
203
  class="qm-card-title qm-focus-ring"
242
204
  value={localTitle}
@@ -266,45 +228,25 @@
266
228
  {/if}
267
229
 
268
230
  <div class="qm-card-body">
269
- <!-- The metadata block, and the thing the bracket brackets: every
270
- field the card has, ungrouped and grouped alike, inside one element whose
271
- top and bottom EDGES are the bracket's two horizontals. Anchoring them here
272
- rather than on the header and on the accordion is what lets an open
273
- section's vertical actually reach them: a rule drawn in the card body's
274
- gap instead would stand clear of where that vertical stops, and the corner
275
- it exists to close would miss. It also survives the shapes the accordion
276
- does not have: a card with no groups still terminates above its body,
277
- because the rule belongs to the fields, not to the sections.
278
-
279
- Rendered only when there ARE fields: the bracket is a statement about a
280
- block, so with no block there is nothing to say, and an empty wrapper
281
- between two rules is what collapses them onto each other. -->
231
+ <!-- One element whose top and bottom edges are the bracket's two horizontals.
232
+ Anchored here rather than on the header and on the accordion so an open section's
233
+ vertical reaches them, and so a card with no groups still terminates above its
234
+ body. -->
282
235
  {#if hasMeta}
283
236
  <div
284
237
  class="qm-card-meta"
285
238
  class:qm-meta-top={!card.isMain}
286
239
  class:qm-meta-bottom={card.hasBody}
287
240
  >
288
- <!-- Ungrouped fields render above the accordion, always visible:
289
- a label-less section has no header to toggle, and these read as the card's
290
- primary fields. -->
291
241
  {#each ungrouped as section (section.group ?? '_ungrouped')}
292
242
  <div class="qm-section">
293
243
  {@render sectionFields(section.fields)}
294
244
  </div>
295
245
  {/each}
296
246
 
297
- <!-- Group accordion: each `ui.group` is a collapsible section,
298
- one open at a time. The header toggles; the panel slides via a
299
- 0fr↔1fr grid row (the `slow` duration rung). The sections share ONE wrapper
300
- with no gap of its own: each header's symmetric padding is the whole
301
- inter-group rhythm. The card body's gap still separates this
302
- block from the ungrouped fields and the body leaf.
303
-
304
- Rendered only when a card HAS groups, so an empty accordion is not the
305
- bracket's last child: the bottom rule's inset belongs to whichever block
306
- actually abuts it, and a zero-height wrapper standing there would take it
307
- from the ungrouped fields that do. -->
247
+ <!-- One open at a time. Rendered only when a card has groups, so an empty
248
+ accordion is not the bracket's last child: the bottom rule's inset belongs
249
+ to whichever block abuts it. -->
308
250
  {#if grouped.length}
309
251
  <div class="qm-groups">
310
252
  {#each grouped as section (section.group)}
@@ -320,13 +262,15 @@
320
262
  aria-controls={panelId}
321
263
  onclick={() => toggleGroup(group)}
322
264
  >
323
- <Icon name="chevron-right" class="qm-group-chevron" size={14} />{section.label}
265
+ <Icon
266
+ name="chevron-right"
267
+ class="qm-group-chevron"
268
+ size={CHEVRON}
269
+ />{section.label}
324
270
  </button>
325
- <!-- `inert` is what makes closed mean CLOSED: the panel is clipped, not
326
- unmounted, so without it every field
271
+ <!-- The panel is clipped, not unmounted, so without `inert` every field
327
272
  in a hidden section keeps its place in the tab order and in the a11y
328
- tree, under a header announcing `aria-expanded="false"`. Paint is
329
- untouched, so the 0fr↔1fr slide is the same slide. -->
273
+ tree, under a header announcing `aria-expanded="false"`. -->
330
274
  <div
331
275
  class="qm-group-panel"
332
276
  id={panelId}
@@ -344,13 +288,9 @@
344
288
  </div>
345
289
  {/if}
346
290
 
347
- <!-- The body: no label and no box. "Body" names the surface the
348
- card is printed on, so a label restates it; and the accessible name
349
- survives on the leaf itself, so the region
350
- is still announced. Unframed is the point rather than a saving: the body is
351
- the ONLY surface in the card without an edge, which is what makes it read
352
- as paper instead of as one more field, and the bracket's bottom rule
353
- already does the separating a box was doing. -->
291
+ <!-- Unframed: the body is the only surface at the card's own tone, where every
292
+ other typed value sits in a well cut into it, and that is what makes it read as
293
+ paper instead of as one more field. -->
354
294
  {#if card.hasBody}
355
295
  <div class="qm-body-leaf">
356
296
  <ProseField
@@ -374,10 +314,6 @@
374
314
  {/if}
375
315
  </section>
376
316
 
377
- <!-- A section's fields as ONE grid: shared by the ungrouped block and the accordion
378
- panels so both render a group's fields identically. Rows are the
379
- grid's business: fields carry a span and auto-place, so nothing here re-derives
380
- structure on resize and a prose leaf's key never moves. -->
381
317
  {#snippet sectionFields(fields: FieldModel[])}
382
318
  <div class="qm-fields">
383
319
  {#each placeFields(fields) as { field: f, span } (f.name)}
@@ -405,12 +341,10 @@
405
341
  </div>
406
342
  {/snippet}
407
343
 
408
- <!-- Recovery shell for an un-schemable card: a card whose `kind` has no
409
- schema (foreign kind, or a schema declaring no `card_kinds`). It stays VISIBLE and
410
- REMOVABLE (its fields/body/`$ext` remain in the Document) so it is never a data
411
- trap. Retyping to a declared kind projects it against that kind on the next
412
- derive: `setCardKind` swaps the kind and leaves payload and body untouched, so
413
- no field is dropped; with no kinds to offer, delete is the only exit. -->
344
+ <!-- A card whose `kind` has no schema stays visible and removable, its fields, body and
345
+ `$ext` intact in the Document, so it is never a data trap. `setCardKind` swaps the kind
346
+ and leaves payload and body untouched, so retyping drops no field; with no kinds to
347
+ offer, delete is the only exit. -->
414
348
  {#snippet recoveryShell()}
415
349
  <header class="qm-card-header">
416
350
  <span class="qm-card-title-static">{humanize(card.kind)}</span>
@@ -449,8 +383,6 @@
449
383
  </div>
450
384
  {/snippet}
451
385
 
452
- <!-- The declared card kinds as `<option>`s for the recovery shell's retype,
453
- the one place a card's kind changes after insert. -->
454
386
  {#snippet kindOptions()}
455
387
  {#each kinds as k (k)}
456
388
  <option value={k}>{humanize(k)}</option>
@@ -458,16 +390,14 @@
458
390
  {/snippet}
459
391
 
460
392
  <style>
393
+ /* An island, and the tone is the whole of what makes it one: the card is the base
394
+ plane and the column behind it is the sunken one (ARCHITECTURE §Styling). The inset
395
+ is the same rung as the gap, so what separates the header from the fields is what
396
+ separates the fields from the card's edge. */
461
397
  .qm-card {
462
- border: var(--_qm-border-width) solid var(--_qm-border);
463
398
  border-radius: var(--_qm-radius);
464
- /* Uniform inset on every side: a body-shown and a
465
- body-hidden card stay symmetric, every left edge on one gutter. The SAME rung
466
- as the gap between the card's stacked regions below: the card's inset and its
467
- internal rhythm are one number, so what separates the header from the fields is
468
- what separates the fields from the card's edge. */
469
399
  padding: var(--_qm-space-3);
470
- background: var(--_qm-surface-raised);
400
+ background: var(--_qm-surface);
471
401
  display: flex;
472
402
  flex-direction: column;
473
403
  gap: var(--_qm-space-3);
@@ -478,46 +408,25 @@
478
408
  justify-content: space-between;
479
409
  gap: var(--_qm-space-2);
480
410
  }
481
- /* The header's other end, hung so the row is balanced: the title's ink sits on the
482
- card's gutter, and this puts the control glyphs on the opposite one. What stands
483
- between a glyph and the region's edge is the tap target's own centring — half the
484
- difference between `--_qm-tap-min` and the glyph — which is a target, not a
485
- rhythm, and so is exactly what a gutter should not be measured from. Both ends
486
- therefore hang by the chrome they carry and by nothing else; the title's is now
487
- zero, and this one is the arithmetic of two rungs rather than a rung of its own,
488
- because the amount is off the space scale (5px at the shipped dials) and a scale
489
- that could express it would be a scale with a step nothing else uses.
490
-
491
- It is the fill, not the box, that overhangs the gutter here: an icon button rests
492
- unboxed and fills only under the pointer, so the
493
- thing crossing the line is a transient target wash, not an edge the card claims. */
411
+ /* The overhang is the tap target's own centring given back, so the glyphs sit on the
412
+ card's gutter rather than the targets around them. It is the fill that crosses the
413
+ line, not a box: an icon button rests unboxed and fills only under the pointer. */
494
414
  .qm-card-header-right {
495
415
  display: flex;
496
416
  align-items: center;
497
417
  gap: var(--_qm-space-2);
498
418
  margin-right: calc(-1 * (var(--_qm-tap-min) - var(--_qm-glyph-control)) / 2);
499
419
  }
500
- /* Reveal the reorder chevrons while the pointer or the caret is in the card
501
- (CardControls owns the default hidden state). Focus is read off the CARD, so a
502
- caret in any leaf, the title, or a chevron itself holds the reveal: hover
503
- alone would strand the pair on keyboard and touch. This is the card's whole
504
- active treatment; nothing marks the section itself. */
420
+ /* Focus as well as hover, so a caret in any leaf, the title, or a chevron holds the
421
+ reveal: hover alone would strand the pair on keyboard and touch. */
505
422
  .qm-card:hover :global(.qm-card-reorder),
506
423
  .qm-card:focus-within :global(.qm-card-reorder) {
507
424
  opacity: 1;
508
425
  }
509
- /* The rename hit region: the header's free width, full height, so a
510
- press anywhere left of the controls enters the title edit. `min-width: 0` lets
511
- it shrink past the title's intrinsic width; `align-self: stretch` beats the
512
- header's `align-items: center` so the region is the row's whole height rather
513
- than the input's.
514
-
515
- It hangs by NOTHING, which is the whole of what the title carrying no box buys:
516
- the first character lands on the card's gutter with the field list, the
517
- bracket's rules and the body's first character, because nothing stands between
518
- the region's edge and the glyph. The stretch is also what
519
- keeps the target legal with the padding gone: WCAG 2.5.8's floor is the ROW's,
520
- which the controls hold at `--_qm-tap-min`, so the input never carried it. */
426
+ /* The rename hit region is the header's free width at full height, so a press
427
+ anywhere left of the controls enters the title edit. `align-self: stretch` beats the
428
+ header's centring, which is also what keeps the target legal with no padding: WCAG
429
+ 2.5.8's floor is the row's, which the controls hold at `--_qm-tap-min`. */
521
430
  .qm-card-rename {
522
431
  flex: 1;
523
432
  min-width: 0;
@@ -526,25 +435,23 @@
526
435
  align-items: center;
527
436
  cursor: text;
528
437
  }
529
- /* Autosize sizer: an inline-grid whose ::after mirrors the text
530
- into the single cell, so the overlaid input tracks its content width. Bounded
531
- to the rename region's width (`min-width: 0` + `max-width: 100%`), which the
532
- header's space-between keeps clear of the controls. The input inherits the type
533
- tokens (`font: inherit`, leading included) so the mirror and the input measure
534
- alike; which is why the leading rung is declared here and not on the input. */
438
+ /* Autosize: the ::after mirrors the text into the same grid cell as the input, so the
439
+ overlaid input tracks its content width. Both carry the same nothing for a box model
440
+ and inherit the same type tokens, which is what makes the two measure alike.
441
+
442
+ The type is the group header's, down to the ink and its hover step below: a card
443
+ title and a section header both name a block of fields, so they read as one register
444
+ and what ranks them is position rather than a size step. */
535
445
  .qm-card-title-sizer {
536
446
  display: inline-grid;
537
447
  align-items: center;
538
448
  min-width: 0;
539
449
  max-width: 100%;
540
- font-size: var(--_qm-text-title);
541
- font-weight: var(--_qm-weight-label);
450
+ font-size: var(--_qm-text-body);
451
+ font-weight: var(--_qm-weight-mid);
542
452
  line-height: var(--_qm-leading-tight);
543
453
  font-family: inherit;
544
454
  }
545
- /* The mirror has no box model to match, because the input has none: with the
546
- padding and the hairline gone from both, the two measure alike by carrying the
547
- same nothing. */
548
455
  .qm-card-title-sizer::after {
549
456
  content: attr(data-value) ' ';
550
457
  grid-area: 1 / 1;
@@ -552,28 +459,17 @@
552
459
  white-space: pre;
553
460
  min-width: 2ch;
554
461
  }
555
- /* The title draws NO box, in any state. A box is
556
- what says "type here", and a card title is already the one line of a card that
557
- reads as its name; the region's `cursor: text` and the caret that lands on a
558
- press say the rest. A hover-summoned box was also the inverse of the recipe every
559
- other control follows, where the box rests drawn and hover changes nothing, and
560
- it filled to `--_qm-surface` — the page rung,
561
- BELOW the card it sits on, so the one hover on this surface that receded instead
562
- of lifting.
563
-
564
- What replaces it is an ink step, the same cue the group header takes for the same
565
- reason: a wide borderless target drawing no box has no other way to answer the
566
- pointer. Rest is `--_qm-ink-label`, which is where the recovery shell's static
567
- title already sits, so the editable title and its unschemable twin finally agree
568
- on tone as well as on the three type rungs they share. */
462
+ /* The title draws no box in any state: a card title is already the one line that
463
+ reads as the card's name, and the region's `cursor: text` says the rest. The ink step
464
+ replaces it, the same cue the group header takes — a wide borderless target has no
465
+ other way to answer the pointer. */
569
466
  .qm-card-title {
570
467
  grid-area: 1 / 1;
571
468
  width: 100%;
572
469
  min-width: 0;
573
470
  font: inherit;
574
- /* `font: inherit` does not carry colour: an actual form control, unlike this
575
- rule's neighbours, defaults to the UA's own text colour rather than the
576
- header's ink without this line. */
471
+ /* `font: inherit` does not carry colour: a form control defaults to the UA's own
472
+ text colour rather than the header's ink without this line. */
577
473
  color: var(--_qm-ink-label);
578
474
  border: none;
579
475
  padding: 0;
@@ -584,121 +480,79 @@
584
480
  .qm-card-title:focus {
585
481
  color: var(--_qm-ink);
586
482
  }
587
- /* One rhythm for the card's stacked regions and for the metadata block inside it:
588
- the gap between a field list and the body is the gap between two field lists. */
589
483
  .qm-card-body,
590
484
  .qm-card-meta {
591
485
  display: flex;
592
486
  flex-direction: column;
593
487
  gap: var(--_qm-space-3);
594
488
  }
595
- /* The metadata bracket: the card's chrome brackets its metadata, and
596
- the body is what falls outside it. Three strokes at ONE rung: the two
597
- horizontals here and the open section's vertical below; because a bracket whose
598
- sides disagree on width or tone reads as three unrelated lines rather than as
599
- one figure. That sameness is the whole effect; it is why the vertical takes
600
- `--_qm-border` and not `--_qm-accent`, which would be ornament with the chevron
601
- and the header's ink step already saying open.
489
+ /* The metadata bracket, in three strokes at one rung: these two horizontals and the
490
+ open section's vertical below. A bracket whose sides disagree on width or tone reads
491
+ as three unrelated lines rather than one figure, which is why the vertical takes
492
+ `--_qm-border` and not `--_qm-accent`.
602
493
 
603
- Both horizontals are conditional, and each condition is what the stroke means: a
604
- top rule is the line under a card title, so the headerless `main` has none and
605
- its bracket starts at the card's own top inset; a bottom rule divides fields from
606
- body, so a card with no body has nothing to divide. The bracket is therefore
607
- sometimes two strokes and sometimes one: an open figure by construction, which
608
- is what distinguishes it from a second box inside the card. */
494
+ Each condition is what its stroke means: a top rule is the line under a card title,
495
+ so the headerless `main` has none; a bottom rule divides fields from body, so a card
496
+ with no body has nothing to divide. Sometimes two strokes and sometimes one — an open
497
+ figure, which is what distinguishes it from a second box inside the card. */
609
498
  .qm-meta-top {
610
499
  border-top: var(--_qm-border-width) solid var(--_qm-border);
611
500
  }
612
501
  .qm-meta-bottom {
613
502
  border-bottom: var(--_qm-border-width) solid var(--_qm-border);
614
503
  }
615
- /* No inset between a horizontal and the accordion, deliberately: an open section's
616
- vertical has to REACH the rule to close a corner against it, and any padding here
617
- is the distance by which it would miss. The accordion needs none anyway: a group
618
- header's symmetric padding is the whole inter-group rhythm.
619
-
620
- A block of FIELDS has no padding of its own, so it takes the inset wherever it
621
- abuts a rule; three places, since three blocks can: an ungrouped block under the
622
- top rule, an ungrouped block over the bottom rule (only reachable because the
623
- accordion's `{#if}` keeps an empty wrapper out of last position), and the last
624
- section's panel when it is open, whose inset is otherwise zero at the bottom and
625
- would stand its final row of controls directly on the stroke. The panel's padding
626
- is inside `.qm-group`, so the vertical still runs the full height to the corner.
627
- Ungrouped fields always render first, so the top selector needs no qualifier. */
504
+ /* The inset sits on the fields rather than on the block that holds them: an open
505
+ section's vertical has to reach the rule to close a corner against it, and padding
506
+ between the two is the distance by which it would miss. Unqualified by open — a shut
507
+ panel clips it. */
628
508
  .qm-meta-top > .qm-section {
629
509
  padding-top: var(--_qm-space-3);
630
510
  }
631
511
  .qm-meta-bottom > .qm-section:last-child,
632
- .qm-meta-bottom .qm-group:last-child.qm-open .qm-group-panel-inner {
512
+ .qm-meta-bottom .qm-group:last-child .qm-group-panel-inner > .qm-fields {
633
513
  padding-bottom: var(--_qm-space-3);
634
514
  }
635
- /* The two query containers: an ungrouped section, and a group panel's inner. Each
636
- is its own, so capacity follows the width the fields actually get: a panel's
637
- inset makes that narrower than the card.
638
-
639
- The ACTION COLUMN is minted here and spent one level down, on the field
640
- (`Field.svelte` holds why it is the field's inset and not this container's). It
641
- is declared on the query container because both of its consumers hang off one:
642
- the fields inside, and the capacity ramp below, which carries the column in its
643
- own arithmetic because the query reads a box the reservation has not narrowed. */
515
+ /* Two query containers, one per kind of section, so capacity follows the width the
516
+ fields actually get: a panel's inset makes that narrower than the card. */
644
517
  .qm-section,
645
518
  .qm-group-panel-inner {
646
- --action-col: calc(var(--_qm-tap-min) + var(--_qm-space-2));
647
519
  container-type: inline-size;
648
520
  }
649
- /* One grid per section. Capacity is the container's, not JavaScript's:
650
- nothing measures, so there is no observer to loop, no pre-measure pass at the
651
- wrong capacity, and no re-packing to restructure the DOM under a prose leaf.
652
- Fields auto-place, which is what keeps a trailing orphan at its column width
653
- instead of growing to fill the line.
654
-
655
- Capacity steps 1 → 2 → 4, skipping 3: each rung is the width at which a track
656
- still clears the comfortable field minimum (2 needs 32rem, 4 needs 65rem), and
657
- an even capacity is what lets `lone`'s half land on a track boundary. Each rung
658
- pays for a track's own action column as well as the gutters between tracks, since
659
- the reservation is per field now: a rung is `n * (220px + action) + gaps`.
521
+ /* Capacity is the container's, not JavaScript's: nothing measures, so there is no
522
+ observer to loop and no re-packing to restructure the DOM under a prose leaf.
660
523
 
661
- A row-sharing field spans three implicit row tracks (Field.svelte), so `row-gap`
662
- here is the gutter BETWEEN field rows; the tighter one inside a field is the
663
- subgrid's own. The grid takes the container's full width; each field insets its
664
- own action column inside the track it lands in. */
524
+ It steps 1 → 2 → 4, skipping 3: each rung is the width at which a track still clears
525
+ the comfortable field minimum, and an even capacity is what lets `lone`'s half land
526
+ on a track boundary. A field ends on its track's own edge, so a rung is
527
+ `n * 220px + gaps`. */
665
528
  .qm-fields {
666
529
  --cols: 1;
667
530
  --cols-half: 1;
668
531
  display: grid;
669
532
  grid-template-columns: repeat(var(--cols), 1fr);
670
533
  column-gap: var(--_qm-space-2);
671
- row-gap: var(--_qm-space-2);
534
+ row-gap: var(--_qm-space-3);
672
535
  }
673
- @container (min-width: 32rem) {
536
+ @container (min-width: 28rem) {
674
537
  .qm-fields {
675
538
  --cols: 2;
676
539
  --cols-half: 1;
677
540
  }
678
541
  }
679
- @container (min-width: 65rem) {
542
+ @container (min-width: 57rem) {
680
543
  .qm-fields {
681
544
  --cols: 4;
682
545
  --cols-half: 2;
683
546
  }
684
547
  }
685
- /* Group accordion. The header is a toggle
686
- at the field-label rung; the panel slides via a 0fr↔1fr grid row so the height
687
- animates without a magic max-height. */
688
- /* The wrapper carries NO gap: the headers' own padding is the rhythm (see the
689
- markup note). */
690
548
  .qm-groups,
691
549
  .qm-group {
692
550
  display: flex;
693
551
  flex-direction: column;
694
552
  }
695
- /* The bracket's third stroke, on the SECTION rather than on its panel:
696
- spanning the header and the content is what gives it a corner to close into at
697
- the block's edge: a rule that starts below the header has nothing to meet there.
698
- One rung with the two horizontals, held there by `check:style`'s border-width axis.
699
-
700
- Drawn transparent when closed rather than absent, so the 1px it occupies is the
701
- same open or shut and a toggle moves no text. */
553
+ /* The bracket's third stroke, on the section rather than on its panel: spanning the
554
+ header is what gives it a corner to close into at the block's edge. Drawn transparent
555
+ when closed rather than absent, so a toggle moves no text. */
702
556
  .qm-group {
703
557
  border-left: var(--_qm-border-width) solid transparent;
704
558
  transition: border-color var(--_qm-duration-slow) var(--_qm-ease-reverse);
@@ -706,33 +560,17 @@
706
560
  .qm-group.qm-open {
707
561
  border-left-color: var(--_qm-border);
708
562
  }
709
- /* Vertical padding is symmetric and is the TIGHTEST rung that still clears WCAG
710
- 2.5.8's 24×24 floor over the label rung's line box: the header is the whole row,
711
- so adjacent labels share one rhythm with no dead strip outside the button, and a
712
- rung above the floor is a rung spent per section on a card whose scarce axis is
713
- vertical. Horizontal is one rung left and zero right. Left, because the section's
714
- vertical runs down this row: at zero the chevron stands on the stroke with only
715
- the icon box's own bearing between them, which is neither a rung nor a constant:
716
- the glyph's rotation swaps which bearing faces the stroke, so the clearance moves
717
- as the section opens. Right stays at zero because the row is the target and an
718
- inset there is target given back; the left one is inside the button and costs
719
- none.
720
-
721
- A button by tag and NEITHER button family by recipe: it reads no
722
- `--_qm-tap-min` (the padding above already clears the floor) and takes no hover
723
- fill (an ink step, below); so the type a family would have carried is declared
724
- here. `font: inherit` because a UA button inherits no face and `--qm-font` would
725
- stop at this row; then the field-label rung, at the tight leading a single line
726
- takes. Sentence case at that rung, reused rather than a fifth size minted: a
727
- section name is structurally a heading, and uppercase costs it twice: the word
728
- shape a column of them is scanned by, and apparent width, so a long label crowds
729
- sooner. Size, weight and leading all sit after `font`, which is a shorthand that
730
- carries `line-height`.
731
-
732
- On the BUTTON rather than on a span inside it: the row's type is one decision,
733
- and a wrapper that carries nothing else is indirection between the header and
734
- its own label. The label is a text run beside the chevron, and flex gives it an
735
- anonymous item either way. */
563
+ /* Symmetric vertical padding at the tightest rung that still clears WCAG 2.5.8's
564
+ 24×24 floor: the header is the whole row, so adjacent labels share one rhythm with no
565
+ dead strip outside the button. Horizontal is one rung left and zero right — left,
566
+ because at zero the chevron stands on the section's vertical with only the icon box's
567
+ own bearing between them, and the glyph's rotation swaps which bearing faces the
568
+ stroke; right, because the row is the target and an inset there is target given back.
569
+
570
+ `font: inherit` because a UA button inherits no face, then the body rung, one step
571
+ over the field labels beneath it: at the label rung the two read as one register and
572
+ the accordion stops looking like structure. Size, weight and leading sit after
573
+ `font`, a shorthand that carries `line-height`. */
736
574
  .qm-group-header {
737
575
  display: flex;
738
576
  align-items: center;
@@ -742,8 +580,8 @@
742
580
  background: transparent;
743
581
  padding: var(--_qm-space) 0 var(--_qm-space) var(--_qm-space);
744
582
  font: inherit;
745
- font-size: var(--_qm-text-label);
746
- font-weight: var(--_qm-weight-label);
583
+ font-size: var(--_qm-text-body);
584
+ font-weight: var(--_qm-weight-mid);
747
585
  line-height: var(--_qm-leading-tight);
748
586
  cursor: pointer;
749
587
  color: var(--_qm-ink-label);
@@ -752,28 +590,21 @@
752
590
  }
753
591
  .qm-group-header :global(.qm-group-chevron) {
754
592
  flex-shrink: 0;
593
+ display: block;
594
+ transform: rotate(0deg);
595
+ transform-origin: center;
755
596
  transition: transform var(--_qm-duration-slow) var(--_qm-ease-reverse);
756
597
  }
757
- /* An ink step, not a hue: the three status hues are the only exits from the
758
- greyscale, and a section standing open is not a status anyway.
759
-
760
- HOVER'S ALONE, though the step suits open as well. `color` is one transition
761
- declaration, and open is the accordion's gesture where hover is its own, so the two
762
- share a rung and one of them is wrong: an ink step at the slow rung lags the
763
- pointer, and at the fast one it settles 80ms before the panel it belongs to.
764
- Hover keeps the property because open has another cue in the
765
- chevron's rotation and hover has none, a big borderless target drawing no box. */
766
- .qm-group-header:hover {
598
+ /* Open shares hover's ink step: a big borderless target draws no box, so the ink is
599
+ the only cue an open section keeps once the pointer leaves it. The chevron's
600
+ rotation is the other cue, and stays open-only below. */
601
+ .qm-group-header:hover,
602
+ .qm-group.qm-open .qm-group-header {
767
603
  color: var(--_qm-ink);
768
604
  }
769
605
  .qm-group.qm-open .qm-group-header :global(.qm-group-chevron) {
770
606
  transform: rotate(90deg);
771
607
  }
772
- /* Sliding panel: the grid track goes 0fr→1fr; the inner clips at min-height 0.
773
- Clipping is the whole of what CSS does here: what a closed panel is OUT of is
774
- `inert`'s to say, on the element. The panel
775
- draws no rule of its own: the vertical is the section's (`.qm-group`), which is
776
- what spans the header too. */
777
608
  .qm-group-panel {
778
609
  display: grid;
779
610
  grid-template-rows: 0fr;
@@ -782,42 +613,41 @@
782
613
  .qm-group.qm-open .qm-group-panel {
783
614
  grid-template-rows: 1fr;
784
615
  }
785
- /* The grouped sections' query container (declared above): its left inset is
786
- exactly what makes a panel's usable width differ from the card's. */
616
+ /* Two boxes because the axes clip differently, and the track is the only thing that
617
+ animates: a field sits at its open position from the first frame of the reveal.
618
+
619
+ The clip box takes the inline inset, which costs a shut panel no height and holds the
620
+ queried width still. The block inset goes on the content, where a `0fr` track clips
621
+ it: declared one box out it collapses the content but not itself, and stands under a
622
+ shut header as dead space. Neither is animated, and neither is qualified by open.
623
+
624
+ A field ends on the clip box at the end edge, where no inset hides its ring the way
625
+ the start edge's does. The pad carries the clip past it and the margin takes the same
626
+ distance back, so the width the fields are packed and queried at is unmoved. */
787
627
  .qm-group-panel-inner {
788
- display: flex;
789
- flex-direction: column;
790
- gap: var(--_qm-space-2);
791
628
  min-height: 0;
792
629
  overflow: hidden;
793
- /* Zero when closed, so the insets arrive with the panel: a `0fr` track collapses
794
- the CONTENT, not the padding, and a top inset declared here stands under a
795
- closed header as dead space the header's symmetric padding cannot absorb. The
796
- panel animates its width along with them, and the capacity ramp reads that
797
- width: a closed panel is `inert` and unmeasured either way, so what a rung
798
- crosses mid-slide is a hidden grid. */
799
- padding: 0;
800
- transition: padding var(--_qm-duration-slow) var(--_qm-ease-reverse);
630
+ padding-inline-start: var(--_qm-space-4);
631
+ padding-inline-end: var(--_qm-ring-reach);
632
+ margin-inline-end: calc(-1 * var(--_qm-ring-reach));
801
633
  }
802
- .qm-group.qm-open .qm-group-panel-inner {
803
- padding: var(--_qm-space-2) 0 0 var(--_qm-space-3);
634
+ .qm-group-panel-inner > .qm-fields {
635
+ padding-block: var(--_qm-space-2);
804
636
  }
805
637
  .qm-body-leaf {
806
638
  display: flex;
807
639
  flex-direction: column;
808
640
  gap: var(--_qm-space);
809
641
  }
810
- /* Recovery shell: dashed edge marks an un-schemable card. The edge
811
- alone carries that: fill stays the card rung, content behind it intact. */
642
+ /* The one card that draws an edge at all: an ordinary card is a plane, so a stroke
643
+ around this one is a state rather than heavier chrome. */
812
644
  .qm-card.qm-unschemable {
813
- border-style: dashed;
645
+ border: var(--_qm-border-width) dashed var(--_qm-border);
814
646
  }
815
- /* One typographic role with the editable title above, so it reads the same three
816
- rungs: including the tight leading a card title takes over the root's reading
817
- rhythm. */
647
+ /* One typographic role with the editable title above. */
818
648
  .qm-card-title-static {
819
- font-size: var(--_qm-text-title);
820
- font-weight: var(--_qm-weight-label);
649
+ font-size: var(--_qm-text-body);
650
+ font-weight: var(--_qm-weight-mid);
821
651
  line-height: var(--_qm-leading-tight);
822
652
  color: var(--_qm-ink-label);
823
653
  }
@@ -841,11 +671,12 @@
841
671
  font-size: var(--_qm-text-label);
842
672
  color: var(--_qm-ink-label);
843
673
  }
674
+ /* The one native control the surface draws, on the box's own recipe (controls.css). */
844
675
  .qm-recovery-retype select {
845
676
  font: inherit;
846
- border: var(--_qm-border-width) solid var(--_qm-border);
677
+ border: none;
847
678
  border-radius: var(--_qm-radius-inner);
848
- background: var(--_qm-surface);
679
+ background: var(--_qm-surface-well);
849
680
  padding: var(--_qm-space-half) var(--_qm-space-2);
850
681
  }
851
682
  </style>