@vmz/ui 0.3.5 → 0.3.6

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 (43) hide show
  1. package/README.md +51 -51
  2. package/package.json +2 -2
  3. package/presets/web-surface.v0.json +19 -7
  4. package/src/components/Accordion.vmz +94 -94
  5. package/src/components/AppShell.vmz +77 -33
  6. package/src/components/Autocomplete.vmz +154 -154
  7. package/src/components/Badge.vmz +70 -70
  8. package/src/components/Breadcrumb.vmz +72 -72
  9. package/src/components/BulkActions.vmz +51 -51
  10. package/src/components/Button.vmz +211 -192
  11. package/src/components/Callout.vmz +77 -77
  12. package/src/components/Card.vmz +120 -106
  13. package/src/components/Checkbox.vmz +55 -55
  14. package/src/components/CodeBlock.vmz +77 -18
  15. package/src/components/ConsoleShell.vmz +251 -251
  16. package/src/components/DataTable.vmz +194 -194
  17. package/src/components/DatePicker.vmz +674 -674
  18. package/src/components/Dialog.vmz +10 -7
  19. package/src/components/Drawer.vmz +427 -427
  20. package/src/components/Dropdown.vmz +135 -16
  21. package/src/components/Empty.vmz +54 -54
  22. package/src/components/Field.vmz +115 -115
  23. package/src/components/FormItem.vmz +79 -79
  24. package/src/components/Link.vmz +34 -4
  25. package/src/components/List.vmz +102 -102
  26. package/src/components/Menu.vmz +243 -243
  27. package/src/components/Pagination.vmz +69 -69
  28. package/src/components/Popover.vmz +223 -223
  29. package/src/components/Prose.vmz +81 -81
  30. package/src/components/RadioGroup.vmz +124 -124
  31. package/src/components/Segmented.vmz +51 -51
  32. package/src/components/Select.vmz +533 -533
  33. package/src/components/Steps.vmz +103 -103
  34. package/src/components/Switch.vmz +98 -98
  35. package/src/components/Table.vmz +165 -133
  36. package/src/components/Tabs.vmz +110 -110
  37. package/src/components/Tag.vmz +43 -40
  38. package/src/components/TextArea.vmz +118 -118
  39. package/src/components/Timeline.vmz +76 -76
  40. package/src/components/Toc.vmz +74 -74
  41. package/src/components/Tooltip.vmz +58 -58
  42. package/src/components/Tree.vmz +191 -191
  43. package/src/components/Upload.vmz +1289 -1289
@@ -1,223 +1,223 @@
1
- <template>
2
- <div data-vmz-ui="popover" :data-vmz-overlay-open="open" class="vmz-ui-popover-root">
3
- <div v-if="open" data-vmz-overlay="popover" data-vmz-overlay-owner="popover" :data-vmz-overlay-stack="stackLevel" class="vmz-ui-popover">
4
- <button type="button" data-vmz-overlay-layer="backdrop" aria-label="Dismiss popover" @click="dismiss" class="vmz-ui-popover__backdrop" />
5
- <div role="dialog" aria-modal="false" :aria-labelledby="titleId" tabindex="-1" data-vmz-overlay-layer="panel" data-vmz-focus="enter" :onKeyDown="onPanelKeyDown" class="vmz-ui-popover__panel">
6
- <h2 :id="titleId" class="vmz-ui-popover__title">
7
- {{ title }}
8
- </h2>
9
- <div class="vmz-ui-popover__body">
10
- <slot />
11
- </div>
12
- <div class="vmz-ui-popover__actions">
13
- <button type="button" data-vmz-focus="close" @click="dismiss" class="vmz-ui-popover__close">
14
- Close
15
- </button>
16
- </div>
17
- </div>
18
- </div>
19
- </div>
20
- </template>
21
- <style>
22
- .vmz-ui-popover-root {
23
- display: block;
24
- }
25
-
26
- .vmz-ui-popover {
27
- position: fixed;
28
- inset: 0;
29
- z-index: 35;
30
- pointer-events: none;
31
- }
32
-
33
- .vmz-ui-popover[data-vmz-overlay-stack="1"] {
34
- z-index: 50;
35
- }
36
-
37
- .vmz-ui-popover[data-vmz-overlay-stack="2"] {
38
- z-index: 60;
39
- }
40
-
41
- .vmz-ui-popover[data-vmz-overlay-stack="3"] {
42
- z-index: 70;
43
- }
44
-
45
- .vmz-ui-popover__backdrop {
46
- position: absolute;
47
- inset: 0;
48
- border: 0;
49
- padding: 0;
50
- margin: 0;
51
- cursor: default;
52
- background: transparent;
53
- pointer-events: auto;
54
- }
55
-
56
- .vmz-ui-popover__panel {
57
- position: absolute;
58
- z-index: 1;
59
- top: 30%;
60
- left: 50%;
61
- transform: translateX(-50%);
62
- box-sizing: border-box;
63
- width: min(20rem, calc(100vw - 2rem));
64
- min-height: 8rem;
65
- padding: 0.85rem 1rem 1rem;
66
- border: 1px solid var(--vmz-line-default);
67
- border-radius: var(--vmz-radius-md, 6px);
68
- background: var(--vmz-action-primary-foreground);
69
- color: var(--vmz-action-primary-active);
70
- outline: none;
71
- pointer-events: auto;
72
- }
73
-
74
- .vmz-ui-popover__panel:focus-visible {
75
- box-shadow: 0 0 0 2px var(--vmz-focus-ring);
76
- }
77
-
78
- .vmz-ui-popover__title {
79
- margin: 0 0 0.5rem;
80
- font-size: 1rem;
81
- }
82
-
83
- .vmz-ui-popover__body {
84
- margin-bottom: 0.75rem;
85
- }
86
-
87
- .vmz-ui-popover__close {
88
- font: inherit;
89
- font-weight: 600;
90
- padding: 0.4rem 0.7rem;
91
- border: 1px solid transparent;
92
- border-radius: var(--vmz-radius-md, 6px);
93
- cursor: pointer;
94
- background: var(--vmz-action-primary-background);
95
- color: var(--vmz-action-primary-foreground);
96
- }
97
-
98
- .vmz-ui-popover__close:focus-visible {
99
- box-shadow: 0 0 0 2px var(--vmz-focus-ring);
100
- }
101
- </style>
102
- <script client>
103
- /**
104
- * VMZ UI — Popover (UI2).
105
- * Non-modal disclosure: Escape + outside dismiss + focus enter/restore.
106
- * Parent owns live `open`. Fixed min size for layout stability.
107
- * `stackLevel` raises z-index; Escape dismisses only the topmost stacked overlay.
108
- */
109
- export default class Popover {
110
- public open: boolean = false;
111
- public title: string = "Popover";
112
- public titleId: string = "vmz-popover-title";
113
- public stackLevel: string = "0";
114
- public onClose: (() => void) | null = null;
115
- _restoreFocus = null;
116
- _panel = null;
117
- _docKeyHandler = null;
118
- _observer = null;
119
- async onMount() {
120
- if (typeof document === "undefined" || typeof MutationObserver === "undefined") return;
121
- const root = this.__vmzDomRoot;
122
- if (!root || typeof root.querySelector !== "function") return;
123
- this._observer = new MutationObserver(() => this._syncFromDom());
124
- this._observer.observe(root, {
125
- childList: true,
126
- subtree: true,
127
- });
128
- this._syncFromDom();
129
- }
130
- onDestroy() {
131
- if (this._observer) {
132
- this._observer.disconnect();
133
- this._observer = null;
134
- }
135
- this._teardownDocKey();
136
- this._panel = null;
137
- this._restoreFocus = null;
138
- }
139
- dismiss() {
140
- this.emit("close");
141
- if (typeof this.onClose === "function") this.onClose();
142
- }
143
- _stackValue() {
144
- const n = Number(this.stackLevel);
145
- return Number.isFinite(n) ? n : 0;
146
- }
147
- _isTopmostStack() {
148
- if (typeof document === "undefined") return true;
149
- const root = this.__vmzDomRoot;
150
- const mine =
151
- root && typeof root.querySelector === "function"
152
- ? root.querySelector("[data-vmz-overlay][data-vmz-overlay-stack]")
153
- : null;
154
- const myStack = Number(
155
- mine?.getAttribute("data-vmz-overlay-stack") || this.stackLevel || "0",
156
- );
157
- const open = document.querySelectorAll("[data-vmz-overlay][data-vmz-overlay-stack]");
158
- let max = -Infinity;
159
- for (const el of open) {
160
- const n = Number(el.getAttribute("data-vmz-overlay-stack") || "0");
161
- if (Number.isFinite(n) && n > max) max = n;
162
- }
163
- if (!Number.isFinite(max)) return true;
164
- return (Number.isFinite(myStack) ? myStack : 0) >= max;
165
- }
166
- onPanelKeyDown(ev) {
167
- if (!ev || ev.key !== "Escape") return;
168
- if (!this._isTopmostStack()) return;
169
- ev.preventDefault();
170
- ev.stopPropagation();
171
- this.dismiss();
172
- }
173
- _syncFromDom() {
174
- const root = this.__vmzDomRoot;
175
- const panel =
176
- root && typeof root.querySelector === "function"
177
- ? root.querySelector('[data-vmz-overlay="popover"] [data-vmz-focus="enter"]')
178
- : null;
179
- if (panel && !this._panel) this._enterFocus(panel);
180
- else if (!panel && this._panel) this._exitFocus();
181
- }
182
- _enterFocus(panel) {
183
- if (typeof document === "undefined") return;
184
- const active = document.activeElement;
185
- if (!this._restoreFocus) {
186
- const root = this.__vmzDomRoot;
187
- const outside =
188
- active instanceof HTMLElement &&
189
- active !== document.body &&
190
- !(root && typeof root.contains === "function" && root.contains(active));
191
- if (outside) this._restoreFocus = active;
192
- }
193
- this._panel = panel instanceof HTMLElement ? panel : null;
194
- if (this._panel && typeof this._panel.focus === "function") this._panel.focus();
195
- if (!this._docKeyHandler) {
196
- this._docKeyHandler = (ev) => {
197
- if (ev.key !== "Escape") return;
198
- if (ev.defaultPrevented) return;
199
- if (!this._isTopmostStack()) return;
200
- ev.preventDefault();
201
- ev.stopPropagation();
202
- this.dismiss();
203
- };
204
- document.addEventListener("keydown", this._docKeyHandler);
205
- }
206
- }
207
- _exitFocus() {
208
- this._teardownDocKey();
209
- this._panel = null;
210
- const restore = this._restoreFocus;
211
- this._restoreFocus = null;
212
- if (restore && typeof restore.focus === "function" && document.contains(restore)) {
213
- restore.focus();
214
- }
215
- }
216
- _teardownDocKey() {
217
- if (typeof document !== "undefined" && this._docKeyHandler) {
218
- document.removeEventListener("keydown", this._docKeyHandler);
219
- }
220
- this._docKeyHandler = null;
221
- }
222
- }
223
- </script>
1
+ <template>
2
+ <div data-vmz-ui="popover" :data-vmz-overlay-open="open" class="vmz-ui-popover-root">
3
+ <div v-if="open" data-vmz-overlay="popover" data-vmz-overlay-owner="popover" :data-vmz-overlay-stack="stackLevel" class="vmz-ui-popover">
4
+ <button type="button" data-vmz-overlay-layer="backdrop" aria-label="Dismiss popover" @click="dismiss" class="vmz-ui-popover__backdrop" />
5
+ <div role="dialog" aria-modal="false" :aria-labelledby="titleId" tabindex="-1" data-vmz-overlay-layer="panel" data-vmz-focus="enter" :onKeyDown="onPanelKeyDown" class="vmz-ui-popover__panel">
6
+ <h2 :id="titleId" class="vmz-ui-popover__title">
7
+ {{ title }}
8
+ </h2>
9
+ <div class="vmz-ui-popover__body">
10
+ <slot />
11
+ </div>
12
+ <div class="vmz-ui-popover__actions">
13
+ <button type="button" data-vmz-focus="close" @click="dismiss" class="vmz-ui-popover__close">
14
+ Close
15
+ </button>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </template>
21
+ <style>
22
+ .vmz-ui-popover-root {
23
+ display: block;
24
+ }
25
+
26
+ .vmz-ui-popover {
27
+ position: fixed;
28
+ inset: 0;
29
+ z-index: 35;
30
+ pointer-events: none;
31
+ }
32
+
33
+ .vmz-ui-popover[data-vmz-overlay-stack="1"] {
34
+ z-index: 50;
35
+ }
36
+
37
+ .vmz-ui-popover[data-vmz-overlay-stack="2"] {
38
+ z-index: 60;
39
+ }
40
+
41
+ .vmz-ui-popover[data-vmz-overlay-stack="3"] {
42
+ z-index: 70;
43
+ }
44
+
45
+ .vmz-ui-popover__backdrop {
46
+ position: absolute;
47
+ inset: 0;
48
+ border: 0;
49
+ padding: 0;
50
+ margin: 0;
51
+ cursor: default;
52
+ background: transparent;
53
+ pointer-events: auto;
54
+ }
55
+
56
+ .vmz-ui-popover__panel {
57
+ position: absolute;
58
+ z-index: 1;
59
+ top: 30%;
60
+ left: 50%;
61
+ transform: translateX(-50%);
62
+ box-sizing: border-box;
63
+ width: min(20rem, calc(100vw - 2rem));
64
+ min-height: 8rem;
65
+ padding: 0.85rem 1rem 1rem;
66
+ border: 1px solid var(--vmz-line-default);
67
+ border-radius: var(--vmz-radius-md, 6px);
68
+ background: var(--vmz-action-primary-foreground);
69
+ color: var(--vmz-action-primary-active);
70
+ outline: none;
71
+ pointer-events: auto;
72
+ }
73
+
74
+ .vmz-ui-popover__panel:focus-visible {
75
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
76
+ }
77
+
78
+ .vmz-ui-popover__title {
79
+ margin: 0 0 0.5rem;
80
+ font-size: 1rem;
81
+ }
82
+
83
+ .vmz-ui-popover__body {
84
+ margin-bottom: 0.75rem;
85
+ }
86
+
87
+ .vmz-ui-popover__close {
88
+ font: inherit;
89
+ font-weight: 600;
90
+ padding: 0.375rem 0.7rem;
91
+ border: 1px solid transparent;
92
+ border-radius: var(--vmz-radius-md, 6px);
93
+ cursor: pointer;
94
+ background: var(--vmz-action-primary-background);
95
+ color: var(--vmz-action-primary-foreground);
96
+ }
97
+
98
+ .vmz-ui-popover__close:focus-visible {
99
+ box-shadow: 0 0 0 3px var(--vmz-focus-ring);
100
+ }
101
+ </style>
102
+ <script client>
103
+ /**
104
+ * VMZ UI — Popover (UI2).
105
+ * Non-modal disclosure: Escape + outside dismiss + focus enter/restore.
106
+ * Parent owns live `open`. Fixed min size for layout stability.
107
+ * `stackLevel` raises z-index; Escape dismisses only the topmost stacked overlay.
108
+ */
109
+ export default class Popover {
110
+ public open: boolean = false;
111
+ public title: string = "Popover";
112
+ public titleId: string = "vmz-popover-title";
113
+ public stackLevel: string = "0";
114
+ public onClose: (() => void) | null = null;
115
+ _restoreFocus = null;
116
+ _panel = null;
117
+ _docKeyHandler = null;
118
+ _observer = null;
119
+ async onMount() {
120
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return;
121
+ const root = this.__vmzDomRoot;
122
+ if (!root || typeof root.querySelector !== "function") return;
123
+ this._observer = new MutationObserver(() => this._syncFromDom());
124
+ this._observer.observe(root, {
125
+ childList: true,
126
+ subtree: true,
127
+ });
128
+ this._syncFromDom();
129
+ }
130
+ onDestroy() {
131
+ if (this._observer) {
132
+ this._observer.disconnect();
133
+ this._observer = null;
134
+ }
135
+ this._teardownDocKey();
136
+ this._panel = null;
137
+ this._restoreFocus = null;
138
+ }
139
+ dismiss() {
140
+ this.emit("close");
141
+ if (typeof this.onClose === "function") this.onClose();
142
+ }
143
+ _stackValue() {
144
+ const n = Number(this.stackLevel);
145
+ return Number.isFinite(n) ? n : 0;
146
+ }
147
+ _isTopmostStack() {
148
+ if (typeof document === "undefined") return true;
149
+ const root = this.__vmzDomRoot;
150
+ const mine =
151
+ root && typeof root.querySelector === "function"
152
+ ? root.querySelector("[data-vmz-overlay][data-vmz-overlay-stack]")
153
+ : null;
154
+ const myStack = Number(
155
+ mine?.getAttribute("data-vmz-overlay-stack") || this.stackLevel || "0",
156
+ );
157
+ const open = document.querySelectorAll("[data-vmz-overlay][data-vmz-overlay-stack]");
158
+ let max = -Infinity;
159
+ for (const el of open) {
160
+ const n = Number(el.getAttribute("data-vmz-overlay-stack") || "0");
161
+ if (Number.isFinite(n) && n > max) max = n;
162
+ }
163
+ if (!Number.isFinite(max)) return true;
164
+ return (Number.isFinite(myStack) ? myStack : 0) >= max;
165
+ }
166
+ onPanelKeyDown(ev) {
167
+ if (!ev || ev.key !== "Escape") return;
168
+ if (!this._isTopmostStack()) return;
169
+ ev.preventDefault();
170
+ ev.stopPropagation();
171
+ this.dismiss();
172
+ }
173
+ _syncFromDom() {
174
+ const root = this.__vmzDomRoot;
175
+ const panel =
176
+ root && typeof root.querySelector === "function"
177
+ ? root.querySelector('[data-vmz-overlay="popover"] [data-vmz-focus="enter"]')
178
+ : null;
179
+ if (panel && !this._panel) this._enterFocus(panel);
180
+ else if (!panel && this._panel) this._exitFocus();
181
+ }
182
+ _enterFocus(panel) {
183
+ if (typeof document === "undefined") return;
184
+ const active = document.activeElement;
185
+ if (!this._restoreFocus) {
186
+ const root = this.__vmzDomRoot;
187
+ const outside =
188
+ active instanceof HTMLElement &&
189
+ active !== document.body &&
190
+ !(root && typeof root.contains === "function" && root.contains(active));
191
+ if (outside) this._restoreFocus = active;
192
+ }
193
+ this._panel = panel instanceof HTMLElement ? panel : null;
194
+ if (this._panel && typeof this._panel.focus === "function") this._panel.focus();
195
+ if (!this._docKeyHandler) {
196
+ this._docKeyHandler = (ev) => {
197
+ if (ev.key !== "Escape") return;
198
+ if (ev.defaultPrevented) return;
199
+ if (!this._isTopmostStack()) return;
200
+ ev.preventDefault();
201
+ ev.stopPropagation();
202
+ this.dismiss();
203
+ };
204
+ document.addEventListener("keydown", this._docKeyHandler);
205
+ }
206
+ }
207
+ _exitFocus() {
208
+ this._teardownDocKey();
209
+ this._panel = null;
210
+ const restore = this._restoreFocus;
211
+ this._restoreFocus = null;
212
+ if (restore && typeof restore.focus === "function" && document.contains(restore)) {
213
+ restore.focus();
214
+ }
215
+ }
216
+ _teardownDocKey() {
217
+ if (typeof document !== "undefined" && this._docKeyHandler) {
218
+ document.removeEventListener("keydown", this._docKeyHandler);
219
+ }
220
+ this._docKeyHandler = null;
221
+ }
222
+ }
223
+ </script>
@@ -1,81 +1,81 @@
1
- <template>
2
- <article data-vmz-ui="prose" class="vmz-ui-prose">
3
- <slot />
4
- </article>
5
- </template>
6
- <style>
7
- .vmz-ui-prose {
8
- display: flex;
9
- flex-direction: column;
10
- gap: 1rem;
11
- max-width: 42rem;
12
- color: var(--vmz-text-ink);
13
- font-family: var(--vmz-font-sans);
14
- line-height: 1.65;
15
- }
16
-
17
- .vmz-ui-prose :where(h1, h2, h3) {
18
- margin: 0;
19
- font-family: var(--vmz-font-display);
20
- font-weight: 700;
21
- letter-spacing: -0.02em;
22
- line-height: 1.2;
23
- color: var(--vmz-text-ink);
24
- scroll-margin-top: 1.25rem;
25
- }
26
-
27
- .vmz-ui-prose :where(h1) {
28
- font-size: clamp(1.85rem, 4vw, 2.35rem);
29
- }
30
-
31
- .vmz-ui-prose :where(h2) {
32
- font-size: 1.35rem;
33
- margin-top: 0.5rem;
34
- }
35
-
36
- .vmz-ui-prose :where(h3) {
37
- font-size: 1.1rem;
38
- }
39
-
40
- .vmz-ui-prose :where(p) {
41
- margin: 0;
42
- color: var(--vmz-text-ink);
43
- }
44
-
45
- .vmz-ui-prose :where(p.lead) {
46
- font-size: 1.05rem;
47
- color: var(--vmz-text-steel);
48
- }
49
-
50
- .vmz-ui-prose :where(ul, ol) {
51
- margin: 0;
52
- padding-left: 1.25rem;
53
- color: var(--vmz-text-ink);
54
- }
55
-
56
- .vmz-ui-prose :where(li + li) {
57
- margin-top: 0.35rem;
58
- }
59
-
60
- .vmz-ui-prose :where(a) {
61
- color: var(--vmz-action-primary-background);
62
- text-underline-offset: 0.15em;
63
- }
64
-
65
- .vmz-ui-prose :where(a:hover) {
66
- color: var(--vmz-action-primary-hover);
67
- }
68
-
69
- .vmz-ui-prose :where(hr) {
70
- border: 0;
71
- border-top: 1px solid var(--vmz-line-default);
72
- margin: 0.5rem 0;
73
- }
74
- </style>
75
- <script client>
76
- /**
77
- * VMZ UI — Prose (Document/Product composition).
78
- * Typography measure for long-form content; values from Style Theme only.
79
- */
80
- export default class Prose {}
81
- </script>
1
+ <template>
2
+ <article data-vmz-ui="prose" class="vmz-ui-prose">
3
+ <slot />
4
+ </article>
5
+ </template>
6
+ <style>
7
+ .vmz-ui-prose {
8
+ display: flex;
9
+ flex-direction: column;
10
+ gap: 1rem;
11
+ max-width: 42rem;
12
+ color: var(--vmz-text-ink);
13
+ font-family: var(--vmz-font-sans);
14
+ line-height: 1.65;
15
+ }
16
+
17
+ .vmz-ui-prose :where(h1, h2, h3) {
18
+ margin: 0;
19
+ font-family: var(--vmz-font-display);
20
+ font-weight: 700;
21
+ letter-spacing: -0.02em;
22
+ line-height: 1.2;
23
+ color: var(--vmz-text-ink);
24
+ scroll-margin-top: 1.25rem;
25
+ }
26
+
27
+ .vmz-ui-prose :where(h1) {
28
+ font-size: clamp(1.85rem, 4vw, 2.35rem);
29
+ }
30
+
31
+ .vmz-ui-prose :where(h2) {
32
+ font-size: 1.35rem;
33
+ margin-top: 0.5rem;
34
+ }
35
+
36
+ .vmz-ui-prose :where(h3) {
37
+ font-size: 1.1rem;
38
+ }
39
+
40
+ .vmz-ui-prose :where(p) {
41
+ margin: 0;
42
+ color: var(--vmz-text-ink);
43
+ }
44
+
45
+ .vmz-ui-prose :where(p.lead) {
46
+ font-size: 1.05rem;
47
+ color: var(--vmz-text-steel);
48
+ }
49
+
50
+ .vmz-ui-prose :where(ul, ol) {
51
+ margin: 0;
52
+ padding-left: 1.25rem;
53
+ color: var(--vmz-text-ink);
54
+ }
55
+
56
+ .vmz-ui-prose :where(li + li) {
57
+ margin-top: 0.375rem;
58
+ }
59
+
60
+ .vmz-ui-prose :where(a) {
61
+ color: var(--vmz-action-primary-background);
62
+ text-underline-offset: 0.15em;
63
+ }
64
+
65
+ .vmz-ui-prose :where(a:hover) {
66
+ color: var(--vmz-action-primary-hover);
67
+ }
68
+
69
+ .vmz-ui-prose :where(hr) {
70
+ border: 0;
71
+ border-top: 1px solid var(--vmz-line-default);
72
+ margin: 0.5rem 0;
73
+ }
74
+ </style>
75
+ <script client>
76
+ /**
77
+ * VMZ UI — Prose (Document/Product composition).
78
+ * Typography measure for long-form content; values from Style Theme only.
79
+ */
80
+ export default class Prose {}
81
+ </script>