@veluai/velu 0.2.13 → 0.2.15

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 (109) hide show
  1. package/README.md +80 -80
  2. package/dist/cli.js +37 -37
  3. package/package.json +64 -64
  4. package/runtime/velu-ui/base.css +320 -320
  5. package/runtime/velu-ui/components/Accordion.jsx +64 -64
  6. package/runtime/velu-ui/components/ApiClient.jsx +207 -207
  7. package/runtime/velu-ui/components/ApiField.jsx +87 -87
  8. package/runtime/velu-ui/components/ApiPath.jsx +63 -63
  9. package/runtime/velu-ui/components/ApiReferencePage.jsx +384 -384
  10. package/runtime/velu-ui/components/ApiSamples.jsx +36 -36
  11. package/runtime/velu-ui/components/ApiSidebar.jsx +122 -122
  12. package/runtime/velu-ui/components/AskBar.jsx +71 -71
  13. package/runtime/velu-ui/components/Callout.jsx +114 -114
  14. package/runtime/velu-ui/components/Card.jsx +131 -131
  15. package/runtime/velu-ui/components/Chatbot.jsx +885 -885
  16. package/runtime/velu-ui/components/CodeBlock.jsx +375 -375
  17. package/runtime/velu-ui/components/Columns.jsx +56 -56
  18. package/runtime/velu-ui/components/ContextMenu.jsx +298 -273
  19. package/runtime/velu-ui/components/ErrorCard.jsx +138 -138
  20. package/runtime/velu-ui/components/Field.jsx +81 -81
  21. package/runtime/velu-ui/components/Image.jsx +163 -163
  22. package/runtime/velu-ui/components/Logo.jsx +31 -31
  23. package/runtime/velu-ui/components/MethodBadge.jsx +31 -31
  24. package/runtime/velu-ui/components/NavSelect.jsx +108 -108
  25. package/runtime/velu-ui/components/NotFound.jsx +63 -63
  26. package/runtime/velu-ui/components/PageFeedback.jsx +219 -219
  27. package/runtime/velu-ui/components/PageFooter.jsx +145 -145
  28. package/runtime/velu-ui/components/PageHeader.jsx +422 -422
  29. package/runtime/velu-ui/components/PageNav.jsx +77 -77
  30. package/runtime/velu-ui/components/PoweredBy.jsx +51 -51
  31. package/runtime/velu-ui/components/Prompt.jsx +115 -115
  32. package/runtime/velu-ui/components/Search.jsx +460 -460
  33. package/runtime/velu-ui/components/Sidebar.jsx +254 -254
  34. package/runtime/velu-ui/components/SocialLinks.jsx +90 -90
  35. package/runtime/velu-ui/components/Steps.jsx +65 -65
  36. package/runtime/velu-ui/components/ThemeToggle.jsx +48 -48
  37. package/runtime/velu-ui/components/Toc.jsx +537 -537
  38. package/runtime/velu-ui/components/TocBar.jsx +195 -195
  39. package/runtime/velu-ui/components/Tree.jsx +87 -87
  40. package/runtime/velu-ui/components/TryItBar.jsx +102 -102
  41. package/runtime/velu-ui/components/accordion.css +92 -92
  42. package/runtime/velu-ui/components/api-page.css +208 -208
  43. package/runtime/velu-ui/components/api.css +635 -635
  44. package/runtime/velu-ui/components/ask-bar.css +94 -94
  45. package/runtime/velu-ui/components/card.css +105 -105
  46. package/runtime/velu-ui/components/chatbot.css +622 -622
  47. package/runtime/velu-ui/components/code-block.css +263 -263
  48. package/runtime/velu-ui/components/context-menu.css +173 -173
  49. package/runtime/velu-ui/components/docs-layout.css +822 -822
  50. package/runtime/velu-ui/components/field.css +82 -82
  51. package/runtime/velu-ui/components/image.css +237 -237
  52. package/runtime/velu-ui/components/nav-select.css +157 -157
  53. package/runtime/velu-ui/components/not-found.css +94 -94
  54. package/runtime/velu-ui/components/page-feedback.css +241 -241
  55. package/runtime/velu-ui/components/page-footer.css +130 -130
  56. package/runtime/velu-ui/components/page-header.css +558 -558
  57. package/runtime/velu-ui/components/page-nav.css +50 -50
  58. package/runtime/velu-ui/components/powered-by.css +92 -92
  59. package/runtime/velu-ui/components/prompt.css +99 -99
  60. package/runtime/velu-ui/components/search.css +307 -307
  61. package/runtime/velu-ui/components/sidebar.css +205 -205
  62. package/runtime/velu-ui/components/steps.css +77 -77
  63. package/runtime/velu-ui/components/theme-toggle.css +102 -102
  64. package/runtime/velu-ui/components/toc-bar.css +234 -234
  65. package/runtime/velu-ui/components/tree.css +49 -49
  66. package/runtime/velu-ui/index.js +54 -54
  67. package/runtime/velu-ui/lib/api-send.js +92 -92
  68. package/runtime/velu-ui/lib/brand-icons.jsx +103 -103
  69. package/runtime/velu-ui/lib/component-schemas.js +100 -100
  70. package/runtime/velu-ui/lib/copyText.js +64 -64
  71. package/runtime/velu-ui/lib/docs-assistant.js +250 -250
  72. package/runtime/velu-ui/lib/lang-icons.jsx +147 -147
  73. package/runtime/velu-ui/lib/pagefind.js +113 -113
  74. package/runtime/velu-ui/lib/prism-langs.js +957 -957
  75. package/runtime/velu-ui/lib/prism-loader.js +74 -74
  76. package/runtime/velu-ui/lib/resolveIcon.jsx +29 -29
  77. package/runtime/velu-ui/lib/scrollIntoNearestView.js +66 -66
  78. package/runtime/velu-ui/mdx-components.jsx +105 -105
  79. package/runtime/velu-ui/primitives/Cluster.jsx +49 -49
  80. package/runtime/velu-ui/primitives/Stack.jsx +63 -63
  81. package/runtime/velu-ui/primitives/Switcher.jsx +57 -57
  82. package/runtime/velu-ui/primitives/stack.css +3 -3
  83. package/runtime/velu-ui/primitives/switcher.css +25 -25
  84. package/runtime/velu-ui/styles.css +46 -46
  85. package/runtime/velu-ui/tokens.css +4 -4
  86. package/schema/velu.schema.json +423 -423
  87. package/src/lib/extract-mdx-error.js +170 -170
  88. package/src/lib/issues.js +159 -159
  89. package/src/lib/known-components.js +34 -34
  90. package/src/navigation.js +443 -443
  91. package/src/runtime/App.jsx +1669 -1668
  92. package/src/runtime/ErrorBoundary.jsx +54 -54
  93. package/src/runtime/client-entry.jsx +22 -22
  94. package/src/runtime/server-entry.jsx +16 -16
  95. package/src/template.html +48 -48
  96. package/templates/starter/ai-tools/claude-code.mdx +26 -26
  97. package/templates/starter/ai-tools/cursor.mdx +17 -17
  98. package/templates/starter/api-reference/introduction.mdx +43 -43
  99. package/templates/starter/development.mdx +19 -19
  100. package/templates/starter/essentials/code.mdx +29 -29
  101. package/templates/starter/essentials/images.mdx +29 -29
  102. package/templates/starter/essentials/markdown.mdx +25 -25
  103. package/templates/starter/essentials/navigation.mdx +39 -39
  104. package/templates/starter/essentials/settings.mdx +30 -30
  105. package/templates/starter/favicon.svg +6 -6
  106. package/templates/starter/index.mdx +31 -31
  107. package/templates/starter/openapi.json +160 -160
  108. package/templates/starter/quickstart.mdx +31 -31
  109. package/templates/starter/velu.json +41 -41
@@ -1,635 +1,635 @@
1
- /* API documentation components — MethodBadge / ApiPath / TryItBar /
2
- ApiClient. All values are tokens; light/dark via [data-theme].
3
- Method colors come from --<method>-pill-color / -stroke-color /
4
- -cta-color in base.css. */
5
-
6
- /* ── MethodBadge ────────────────────────────────────────────────────────── */
7
- /* 2px block / 8px inline padding — the pill hugs its label tightly so it
8
- reads as a token, not a button. */
9
- .velu-method-badge {
10
- display: inline-flex;
11
- align-items: center;
12
- padding-block: 2px;
13
- padding-inline: var(--s-3);
14
- background: var(--method-pill, var(--surface-color));
15
- border: var(--border-width) solid
16
- var(--method-stroke, var(--border-color));
17
- border-radius: var(--radius-sm);
18
- font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
19
- font-size: var(--f-h6);
20
- line-height: var(--lh-h6);
21
- font-weight: var(--weight-medium);
22
- /* Label stays in the theme's primary text color regardless of method
23
- so the pill reads cleanly against any tint. */
24
- color: var(--text-color);
25
- letter-spacing: 0.04em;
26
- text-transform: uppercase;
27
- }
28
- .velu-method-badge--get {
29
- --method-pill: var(--get-pill-color);
30
- --method-stroke: var(--get-pill-stroke-color);
31
- --method-cta: var(--get-cta-color);
32
- }
33
- .velu-method-badge--post {
34
- --method-pill: var(--post-pill-color);
35
- --method-stroke: var(--post-pill-stroke-color);
36
- --method-cta: var(--post-cta-color);
37
- }
38
- .velu-method-badge--put {
39
- --method-pill: var(--put-pill-color);
40
- --method-stroke: var(--put-pill-stroke-color);
41
- --method-cta: var(--put-cta-color);
42
- }
43
- .velu-method-badge--patch {
44
- --method-pill: var(--patch-pill-color);
45
- --method-stroke: var(--patch-pill-stroke-color);
46
- --method-cta: var(--patch-cta-color);
47
- }
48
- .velu-method-badge--delete {
49
- --method-pill: var(--delete-pill-color);
50
- --method-stroke: var(--delete-pill-stroke-color);
51
- --method-cta: var(--delete-cta-color);
52
- }
53
-
54
- /* ── ApiPath ───────────────────────────────────────────────────────────── */
55
- /* Layout (inline-flex + wrap + gap) is provided by <Cluster>; this rule
56
- only owns typography. min-inline-size:0 lets ApiPath shrink below
57
- its content's min-content width so its own internal Cluster wrap
58
- actually kicks in (default flex min-width is auto = content). */
59
- .velu-api-path {
60
- min-inline-size: 0;
61
- font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
62
- font-size: var(--f-h6);
63
- line-height: var(--lh-h6);
64
- color: var(--text-color);
65
- }
66
- /* Hardcoded chunks stay together at the segment boundary but can
67
- break mid-text when there's no other choice (very narrow container)
68
- so they never overflow horizontally. */
69
- .velu-api-path__segment {
70
- overflow-wrap: anywhere;
71
- }
72
- .velu-api-path__param {
73
- display: inline-flex;
74
- align-items: center;
75
- padding-block: 2px;
76
- padding-inline: var(--s-3);
77
- background: var(--method-pill, var(--surface-color));
78
- border: var(--border-width) solid
79
- var(--method-stroke, var(--border-color));
80
- border-radius: var(--radius-sm);
81
- color: var(--text-color);
82
- }
83
- .velu-api-path__param--get {
84
- --method-pill: var(--get-pill-color);
85
- --method-stroke: var(--get-pill-stroke-color);
86
- --method-cta: var(--get-cta-color);
87
- }
88
- .velu-api-path__param--post {
89
- --method-pill: var(--post-pill-color);
90
- --method-stroke: var(--post-pill-stroke-color);
91
- --method-cta: var(--post-cta-color);
92
- }
93
- .velu-api-path__param--put {
94
- --method-pill: var(--put-pill-color);
95
- --method-stroke: var(--put-pill-stroke-color);
96
- --method-cta: var(--put-cta-color);
97
- }
98
- .velu-api-path__param--patch {
99
- --method-pill: var(--patch-pill-color);
100
- --method-stroke: var(--patch-pill-stroke-color);
101
- --method-cta: var(--patch-cta-color);
102
- }
103
- .velu-api-path__param--delete {
104
- --method-pill: var(--delete-pill-color);
105
- --method-stroke: var(--delete-pill-stroke-color);
106
- --method-cta: var(--delete-cta-color);
107
- }
108
-
109
- /* ── TryItBar ──────────────────────────────────────────────────────────── */
110
- /* Radius chain — the Try It BUTTON is the fixed basis (--radius-sm):
111
- button --radius-sm (8px) ← basis, never changes
112
- outer calc(--radius-sm + --s-3) (16px) = button + --s-3
113
- inner --radius-sm (8px) = outer - --s-3
114
- pill --radius-sm (8px) ← keeps its own corner
115
- outer↔button and outer↔inner are strictly concentric (one --s-3 step
116
- apart). The pill keeps --radius-sm so it stays visibly rounded — a
117
- strict pill↔inner concentric would force it to 0 (8 - 8).
118
-
119
- Layout (flex-wrap + gap + justify/align) is provided by <Cluster>;
120
- this rule only owns the chrome (padding / border / radius / bg).
121
-
122
- --try-it-row-min: the inner row's minimum width (see __row below).
123
- ch-based so it scales with the monospace endpoint text; override
124
- per-instance if a longer/shorter endpoint needs a different floor. */
125
- .velu-try-it {
126
- --try-it-row-min: 24ch;
127
- padding: var(--s-3);
128
- border: var(--border-width) solid var(--border-color);
129
- border-radius: calc(var(--radius-sm) + var(--s-3));
130
- background: var(--page-bg);
131
- }
132
- /* Inner bordered row — flex, items aligned to the top so the copy
133
- button stays pinned up even when the endpoint group wraps onto
134
- multiple lines.
135
- min-inline-size gives the row a real floor (--try-it-row-min, capped
136
- at 100% so it never overflows a tiny container). Once row + Try It
137
- button can't both fit, the outer Cluster wraps the button to the
138
- next line — without the floor the row would just shrink forever and
139
- the button would never drop. */
140
- .velu-try-it__row {
141
- display: flex;
142
- align-items: flex-start;
143
- gap: var(--s-1);
144
- padding: var(--s-3);
145
- border: var(--border-width) solid var(--border-color);
146
- /* = outer (calc(--radius-sm + --s-3)) - --s-3 padding = --radius-sm */
147
- border-radius: var(--radius-sm);
148
- flex: 1;
149
- min-inline-size: min(var(--try-it-row-min, 24ch), 100%);
150
- background: var(--page-bg);
151
- }
152
- /* Method pill + path — wraps internally (Cluster), fills the row minus
153
- the copy button. */
154
- .velu-try-it__endpoint {
155
- flex: 1;
156
- min-inline-size: 0;
157
- }
158
- .velu-try-it__copy {
159
- display: inline-flex;
160
- align-items: center;
161
- justify-content: center;
162
- inline-size: 1.75em;
163
- block-size: 1.75em;
164
- padding: 0;
165
- background: transparent;
166
- border: 0;
167
- color: var(--muted-color);
168
- cursor: pointer;
169
- /* Non-shrinking; pinned to the top of the row so it stays on the
170
- first line when the endpoint group wraps below. */
171
- flex: none;
172
- align-self: flex-start;
173
- }
174
- .velu-try-it__copy:hover {
175
- color: var(--text-color);
176
- }
177
- .velu-try-it__cta {
178
- position: relative;
179
- overflow: hidden;
180
- display: inline-flex;
181
- align-items: center;
182
- justify-content: center;
183
- padding-block: var(--s-3);
184
- padding-inline: var(--s0);
185
- background: var(--method-cta, var(--accent-color));
186
- border: 0;
187
- /* The fixed basis of the concentric chain — never changes. */
188
- border-radius: var(--radius-sm);
189
- color: #fff;
190
- font: inherit;
191
- font-size: var(--f-h6);
192
- font-weight: var(--weight-medium);
193
- line-height: var(--lh-h6);
194
- cursor: pointer;
195
- }
196
- .velu-try-it__cta:hover {
197
- background: color-mix(in srgb, var(--method-cta, var(--accent-color)) 88%, #000);
198
- }
199
- .velu-try-it__cta:disabled {
200
- cursor: default;
201
- }
202
-
203
- /* Label (text + chevron) and the loading spinner are two stacked layers
204
- that swap with a vertical slide: when loading, the label slides DOWN and
205
- out the bottom while the spinner slides IN from the top. overflow:hidden
206
- on the button clips the off-screen states. The label stays in normal flow
207
- so it fixes the button's width; the spinner overlays it. */
208
- .velu-try-it__cta-label {
209
- display: inline-flex;
210
- align-items: center;
211
- gap: var(--s-2);
212
- transition: transform 0.22s ease, opacity 0.18s ease;
213
- }
214
- .velu-try-it__cta-spinner {
215
- position: absolute;
216
- inset: 0;
217
- display: inline-flex;
218
- align-items: center;
219
- justify-content: center;
220
- transform: translateY(-110%);
221
- opacity: 0;
222
- transition: transform 0.22s ease, opacity 0.18s ease;
223
- }
224
- .velu-try-it__cta[data-loading='true'] .velu-try-it__cta-label {
225
- transform: translateY(120%);
226
- opacity: 0;
227
- }
228
- .velu-try-it__cta[data-loading='true'] .velu-try-it__cta-spinner {
229
- transform: translateY(0);
230
- opacity: 1;
231
- }
232
- .velu-try-it__cta-spinner svg {
233
- animation: velu-cta-spin 0.7s linear infinite;
234
- }
235
- @keyframes velu-cta-spin {
236
- to {
237
- transform: rotate(360deg);
238
- }
239
- }
240
- @media (prefers-reduced-motion: reduce) {
241
- .velu-try-it__cta-label,
242
- .velu-try-it__cta-spinner {
243
- transition-duration: 0.01ms;
244
- }
245
- .velu-try-it__cta-spinner svg {
246
- animation-duration: 1.4s;
247
- }
248
- }
249
- .velu-try-it--get { --method-cta: var(--get-cta-color); }
250
- .velu-try-it--post { --method-cta: var(--post-cta-color); }
251
- .velu-try-it--put { --method-cta: var(--put-cta-color); }
252
- .velu-try-it--patch { --method-cta: var(--patch-cta-color); }
253
- .velu-try-it--delete{ --method-cta: var(--delete-cta-color); }
254
-
255
- /* ── ApiClient ─────────────────────────────────────────────────────────── */
256
- /* max-inline-size: 100% + min-inline-size: 0 keep the client contained
257
- when it's a flex/grid child (e.g. rendered inside a production
258
- modal) — without min-inline-size:0 a flex item's default
259
- `min-width: auto` lets wide content bleed past the container. */
260
- .velu-api-client {
261
- position: relative;
262
- border: var(--border-width) solid var(--border-color);
263
- border-radius: var(--radius-md);
264
- background: var(--page-bg);
265
- overflow: hidden;
266
- max-inline-size: 100%;
267
- min-inline-size: 0;
268
- /* Own query container so the body grid reflows to the client's width
269
- (it lives in a modal, outside the docs layout container). */
270
- container: api-client / inline-size;
271
- }
272
-
273
- /* Modal close button — sits in its own row at the top of the client,
274
- X aligned to the inline-end. */
275
- .velu-api-client__close-row {
276
- display: flex;
277
- justify-content: flex-end;
278
- padding: var(--s-3) var(--s-3) 0;
279
- }
280
- .velu-api-client__close {
281
- display: inline-flex;
282
- align-items: center;
283
- justify-content: center;
284
- inline-size: 1.75em;
285
- block-size: 1.75em;
286
- padding: 0;
287
- background: transparent;
288
- border: 0;
289
- border-radius: var(--radius-sm);
290
- color: var(--muted-color);
291
- cursor: pointer;
292
- }
293
- .velu-api-client__close:hover {
294
- color: var(--text-color);
295
- background: var(--surface-color);
296
- }
297
-
298
- /* base.css applies a global `* { max-width: var(--measure) }` (66ch
299
- text-measure cap). Inside ApiClient that would pin the non-excluded
300
- structural elements — <details>, <table>, <h3>, <p>, <summary> — to
301
- 66ch, making the whole client look fixed-width even in a wide modal.
302
- Reset it: every element here manages its own width via flex +
303
- wrapping, so the client fills whatever container it's given. */
304
- .velu-api-client * {
305
- max-inline-size: none;
306
- }
307
-
308
- /* Head row: operation dropdown + TryItBar. Layout (flex-wrap + gap +
309
- align) is provided by <Cluster>; this rule only owns the padding
310
- that insets both children from the ApiClient frame. */
311
- .velu-api-client__head {
312
- padding: var(--s-3);
313
- }
314
-
315
- /* Operation dropdown — same shape as TryItBar's inner row so the two
316
- read as a matched pair. flex: none → hugs its text (natural width
317
- AND natural height; the Cluster's align: flex-start keeps it from
318
- stretching to the taller TryItBar's height). */
319
- .velu-api-client__op {
320
- position: relative;
321
- display: flex;
322
- align-items: center;
323
- gap: var(--s-2);
324
- padding: var(--s-3);
325
- border: var(--border-width) solid var(--border-color);
326
- border-radius: var(--radius-md);
327
- background: var(--page-bg);
328
- color: var(--text-color);
329
- font-size: var(--f-h6);
330
- line-height: var(--lh-h6);
331
- flex: none;
332
- }
333
- /* The clickable trigger when the operation is switchable — a bare button
334
- that keeps the same layout as the static row. */
335
- .velu-api-client__op-btn {
336
- display: inline-flex;
337
- align-items: center;
338
- gap: var(--s-2);
339
- margin: 0;
340
- padding: 0;
341
- background: transparent;
342
- border: 0;
343
- color: inherit;
344
- font: inherit;
345
- cursor: pointer;
346
- }
347
- .velu-api-client__op-label {
348
- font-weight: var(--weight-medium);
349
- }
350
- .velu-api-client__op-chevron {
351
- display: inline-flex;
352
- align-items: center;
353
- color: var(--muted-color);
354
- transition: transform 0.15s ease;
355
- }
356
- .velu-api-client__op-btn[aria-expanded='true'] .velu-api-client__op-chevron {
357
- transform: rotate(180deg);
358
- }
359
-
360
- /* Operation switcher menu — lists every operation in the tab. */
361
- .velu-api-client__op-menu {
362
- position: absolute;
363
- inset-block-start: calc(100% + var(--s-3));
364
- inset-inline-start: 0;
365
- z-index: 5;
366
- display: flex;
367
- flex-direction: column;
368
- gap: 2px;
369
- margin: 0;
370
- padding: var(--s-3);
371
- list-style: none;
372
- min-inline-size: 16rem;
373
- max-block-size: 18rem;
374
- overflow-y: auto;
375
- background: var(--page-bg);
376
- border: var(--border-width) solid var(--border-color);
377
- border-radius: var(--radius-md);
378
- box-shadow: 0 12px 32px -12px rgba(0, 0, 0, 0.4);
379
- }
380
- .velu-api-client__op-item {
381
- display: flex;
382
- align-items: center;
383
- gap: var(--s-2);
384
- inline-size: 100%;
385
- padding: var(--s-3) var(--s-2);
386
- background: transparent;
387
- border: 0;
388
- border-radius: var(--radius-sm);
389
- color: var(--text-color);
390
- font: inherit;
391
- font-size: var(--f-h6);
392
- text-align: start;
393
- cursor: pointer;
394
- }
395
- .velu-api-client__op-item:hover,
396
- .velu-api-client__op-item--active {
397
- background: var(--surface-color);
398
- }
399
- .velu-api-client__op-item-label {
400
- white-space: nowrap;
401
- overflow: hidden;
402
- text-overflow: ellipsis;
403
- }
404
-
405
- /* Inside ApiClient the outer frame already supplies the box — strip
406
- the TryItBar's own outer border / radius / padding (the head's
407
- padding wraps both children). flex: 1 fills the head beside the
408
- natural-width dropdown; the min-width floor makes Cluster wrap the
409
- bar below the dropdown once it can't keep that width. */
410
- .velu-api-client__bar {
411
- flex: 1;
412
- min-inline-size: min(var(--try-it-row-min, 24ch), 100%);
413
- border: 0;
414
- border-radius: 0;
415
- padding: 0;
416
- background: transparent;
417
- }
418
-
419
- /* Body grid with named areas so the three slots — form / live response /
420
- code samples — can be placed AND reordered independently.
421
- Wide (the client is its own query container, set on .velu-api-client):
422
- form fills the left column; response sits top-right with the samples
423
- below it. When there's no response yet, the samples take the whole right
424
- column.
425
- Narrow (single column): the live response moves ABOVE the form so a Send
426
- result is visible without scrolling past the inputs; form then samples
427
- follow. */
428
- .velu-api-client__body {
429
- display: grid;
430
- grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
431
- grid-template-areas: 'form aside';
432
- align-items: start;
433
- gap: var(--s2);
434
- padding: var(--s2);
435
- }
436
- .velu-api-client__body[data-has-response='true'] {
437
- grid-template-areas:
438
- 'form response'
439
- 'form aside';
440
- }
441
- .velu-api-client__left {
442
- grid-area: form;
443
- }
444
- .velu-api-client__response {
445
- grid-area: response;
446
- }
447
- .velu-api-client__right {
448
- grid-area: aside;
449
- }
450
- .velu-api-client__left,
451
- .velu-api-client__right,
452
- .velu-api-client__response {
453
- display: flex;
454
- flex-direction: column;
455
- gap: var(--s1);
456
- min-inline-size: 0;
457
- }
458
-
459
- @container api-client (max-width: 40rem) {
460
- .velu-api-client__body,
461
- .velu-api-client__body[data-has-response='true'] {
462
- grid-template-columns: 1fr;
463
- grid-template-areas:
464
- 'form'
465
- 'aside';
466
- }
467
- .velu-api-client__body[data-has-response='true'] {
468
- grid-template-areas:
469
- 'response'
470
- 'form'
471
- 'aside';
472
- }
473
- }
474
-
475
- .velu-api-client__title {
476
- margin: 0;
477
- font-size: var(--f-h3);
478
- line-height: var(--lh-h3);
479
- font-weight: var(--weight-medium);
480
- color: var(--text-color);
481
- }
482
- .velu-api-client__description {
483
- margin: 0;
484
- color: var(--text-color);
485
- font-size: var(--f-body);
486
- line-height: var(--lh-body);
487
- }
488
-
489
- /* ── ApiField (input-bearing field inside an Accordion section) ─────────── */
490
- /* flex-wrap pair: info column (label + description) and the control
491
- column (input). Wraps to stacked on narrow widths — no media query. */
492
- .velu-api-field {
493
- display: flex;
494
- flex-wrap: wrap;
495
- gap: var(--s0);
496
- align-items: flex-start;
497
- }
498
- .velu-api-field__info {
499
- flex: 1 1 16ch;
500
- min-inline-size: 0;
501
- display: flex;
502
- flex-direction: column;
503
- gap: var(--s-2);
504
- }
505
- .velu-api-field__name {
506
- font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
507
- font-size: var(--f-h5);
508
- line-height: var(--lh-h5);
509
- font-weight: var(--weight-medium);
510
- color: var(--accent-color);
511
- }
512
- /* Chip + required pill — same recipe as Field's, kept local so ApiField
513
- doesn't depend on field.css. */
514
- .velu-api-field__chip {
515
- display: inline-flex;
516
- align-items: center;
517
- padding-block: 0;
518
- padding-inline: var(--s-3);
519
- background: var(--surface-color);
520
- border-radius: var(--radius-sm);
521
- font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
522
- font-size: var(--f-h6);
523
- line-height: var(--lh-h6);
524
- color: var(--muted-color);
525
- }
526
- .velu-api-field__required {
527
- display: inline-flex;
528
- align-items: center;
529
- padding-block: 0;
530
- padding-inline: var(--s-3);
531
- background: color-mix(in srgb, var(--accent-color) 18%, transparent);
532
- border-radius: var(--radius-sm);
533
- font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
534
- font-size: var(--f-h6);
535
- line-height: var(--lh-h6);
536
- color: var(--accent-color);
537
- }
538
- .velu-api-field__desc {
539
- color: var(--text-color);
540
- font-size: var(--f-h6);
541
- line-height: var(--lh-h6);
542
- }
543
-
544
- /* Control column — the actual <input>, optionally with a static prefix
545
- (e.g. "Bearer"). The whole thing reads as one bordered field. */
546
- .velu-api-field__control {
547
- flex: 1 1 16ch;
548
- min-inline-size: 0;
549
- display: flex;
550
- align-items: center;
551
- border: var(--border-width) solid var(--border-color);
552
- border-radius: var(--radius-sm);
553
- background: var(--page-bg);
554
- font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
555
- font-size: var(--f-h6);
556
- }
557
- .velu-api-field__control:focus-within {
558
- border-color: var(--text-color);
559
- }
560
- .velu-api-field__prefix {
561
- flex: none;
562
- padding-inline: var(--s-2);
563
- color: var(--muted-color);
564
- }
565
- .velu-api-field__input {
566
- flex: 1;
567
- min-inline-size: 0;
568
- padding-block: var(--s-3);
569
- padding-inline: var(--s-2);
570
- background: transparent;
571
- border: 0;
572
- font: inherit;
573
- color: var(--text-color);
574
- }
575
- .velu-api-field__input::placeholder {
576
- color: var(--muted-color);
577
- }
578
- .velu-api-field__input:focus {
579
- outline: none;
580
- }
581
-
582
- /* ── ApiSidebar ────────────────────────────────────────────────────────── */
583
- /* Vertical rhythm is the Stack primitive (set inline by ApiSidebar.jsx);
584
- this block holds only the rail, group header, row layout, active
585
- state, and icon sizing — same split as sidebar.css. */
586
- .velu-api-sidebar {
587
- border-inline-start: var(--border-width) solid var(--border-color);
588
- margin-inline-start: var(--s1);
589
- }
590
-
591
- .velu-api-sidebar__section {
592
- display: flex;
593
- align-items: center;
594
- gap: var(--s-2);
595
- padding-inline: var(--s-3);
596
- inline-size: fit-content;
597
- font-weight: var(--weight-medium);
598
- text-transform: uppercase;
599
- }
600
-
601
- .velu-api-sidebar__list {
602
- list-style: none;
603
- margin: 0;
604
- padding: 0;
605
- }
606
-
607
- /* Endpoint row — method pill + name. align-items: flex-start so the
608
- pill stays on the first line when a long name wraps. */
609
- .velu-api-sidebar__item {
610
- display: flex;
611
- align-items: flex-start;
612
- gap: var(--s-2);
613
- padding-inline: var(--s0);
614
- color: var(--text-color);
615
- text-decoration: none;
616
- }
617
- .velu-api-sidebar__item--active {
618
- color: var(--accent-color);
619
- border-inline-start: 2px solid var(--accent-color);
620
- }
621
- .velu-api-sidebar__label {
622
- font-size: var(--f-body);
623
- line-height: var(--lh-h6);
624
- }
625
-
626
- .velu-api-sidebar__icon {
627
- display: inline-flex;
628
- flex: none;
629
- inline-size: var(--f-body);
630
- block-size: var(--f-body);
631
- }
632
- .velu-api-sidebar__icon svg {
633
- inline-size: 100%;
634
- block-size: 100%;
635
- }
1
+ /* API documentation components — MethodBadge / ApiPath / TryItBar /
2
+ ApiClient. All values are tokens; light/dark via [data-theme].
3
+ Method colors come from --<method>-pill-color / -stroke-color /
4
+ -cta-color in base.css. */
5
+
6
+ /* ── MethodBadge ────────────────────────────────────────────────────────── */
7
+ /* 2px block / 8px inline padding — the pill hugs its label tightly so it
8
+ reads as a token, not a button. */
9
+ .velu-method-badge {
10
+ display: inline-flex;
11
+ align-items: center;
12
+ padding-block: 2px;
13
+ padding-inline: var(--s-3);
14
+ background: var(--method-pill, var(--surface-color));
15
+ border: var(--border-width) solid
16
+ var(--method-stroke, var(--border-color));
17
+ border-radius: var(--radius-sm);
18
+ font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
19
+ font-size: var(--f-h6);
20
+ line-height: var(--lh-h6);
21
+ font-weight: var(--weight-medium);
22
+ /* Label stays in the theme's primary text color regardless of method
23
+ so the pill reads cleanly against any tint. */
24
+ color: var(--text-color);
25
+ letter-spacing: 0.04em;
26
+ text-transform: uppercase;
27
+ }
28
+ .velu-method-badge--get {
29
+ --method-pill: var(--get-pill-color);
30
+ --method-stroke: var(--get-pill-stroke-color);
31
+ --method-cta: var(--get-cta-color);
32
+ }
33
+ .velu-method-badge--post {
34
+ --method-pill: var(--post-pill-color);
35
+ --method-stroke: var(--post-pill-stroke-color);
36
+ --method-cta: var(--post-cta-color);
37
+ }
38
+ .velu-method-badge--put {
39
+ --method-pill: var(--put-pill-color);
40
+ --method-stroke: var(--put-pill-stroke-color);
41
+ --method-cta: var(--put-cta-color);
42
+ }
43
+ .velu-method-badge--patch {
44
+ --method-pill: var(--patch-pill-color);
45
+ --method-stroke: var(--patch-pill-stroke-color);
46
+ --method-cta: var(--patch-cta-color);
47
+ }
48
+ .velu-method-badge--delete {
49
+ --method-pill: var(--delete-pill-color);
50
+ --method-stroke: var(--delete-pill-stroke-color);
51
+ --method-cta: var(--delete-cta-color);
52
+ }
53
+
54
+ /* ── ApiPath ───────────────────────────────────────────────────────────── */
55
+ /* Layout (inline-flex + wrap + gap) is provided by <Cluster>; this rule
56
+ only owns typography. min-inline-size:0 lets ApiPath shrink below
57
+ its content's min-content width so its own internal Cluster wrap
58
+ actually kicks in (default flex min-width is auto = content). */
59
+ .velu-api-path {
60
+ min-inline-size: 0;
61
+ font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
62
+ font-size: var(--f-h6);
63
+ line-height: var(--lh-h6);
64
+ color: var(--text-color);
65
+ }
66
+ /* Hardcoded chunks stay together at the segment boundary but can
67
+ break mid-text when there's no other choice (very narrow container)
68
+ so they never overflow horizontally. */
69
+ .velu-api-path__segment {
70
+ overflow-wrap: anywhere;
71
+ }
72
+ .velu-api-path__param {
73
+ display: inline-flex;
74
+ align-items: center;
75
+ padding-block: 2px;
76
+ padding-inline: var(--s-3);
77
+ background: var(--method-pill, var(--surface-color));
78
+ border: var(--border-width) solid
79
+ var(--method-stroke, var(--border-color));
80
+ border-radius: var(--radius-sm);
81
+ color: var(--text-color);
82
+ }
83
+ .velu-api-path__param--get {
84
+ --method-pill: var(--get-pill-color);
85
+ --method-stroke: var(--get-pill-stroke-color);
86
+ --method-cta: var(--get-cta-color);
87
+ }
88
+ .velu-api-path__param--post {
89
+ --method-pill: var(--post-pill-color);
90
+ --method-stroke: var(--post-pill-stroke-color);
91
+ --method-cta: var(--post-cta-color);
92
+ }
93
+ .velu-api-path__param--put {
94
+ --method-pill: var(--put-pill-color);
95
+ --method-stroke: var(--put-pill-stroke-color);
96
+ --method-cta: var(--put-cta-color);
97
+ }
98
+ .velu-api-path__param--patch {
99
+ --method-pill: var(--patch-pill-color);
100
+ --method-stroke: var(--patch-pill-stroke-color);
101
+ --method-cta: var(--patch-cta-color);
102
+ }
103
+ .velu-api-path__param--delete {
104
+ --method-pill: var(--delete-pill-color);
105
+ --method-stroke: var(--delete-pill-stroke-color);
106
+ --method-cta: var(--delete-cta-color);
107
+ }
108
+
109
+ /* ── TryItBar ──────────────────────────────────────────────────────────── */
110
+ /* Radius chain — the Try It BUTTON is the fixed basis (--radius-sm):
111
+ button --radius-sm (8px) ← basis, never changes
112
+ outer calc(--radius-sm + --s-3) (16px) = button + --s-3
113
+ inner --radius-sm (8px) = outer - --s-3
114
+ pill --radius-sm (8px) ← keeps its own corner
115
+ outer↔button and outer↔inner are strictly concentric (one --s-3 step
116
+ apart). The pill keeps --radius-sm so it stays visibly rounded — a
117
+ strict pill↔inner concentric would force it to 0 (8 - 8).
118
+
119
+ Layout (flex-wrap + gap + justify/align) is provided by <Cluster>;
120
+ this rule only owns the chrome (padding / border / radius / bg).
121
+
122
+ --try-it-row-min: the inner row's minimum width (see __row below).
123
+ ch-based so it scales with the monospace endpoint text; override
124
+ per-instance if a longer/shorter endpoint needs a different floor. */
125
+ .velu-try-it {
126
+ --try-it-row-min: 24ch;
127
+ padding: var(--s-3);
128
+ border: var(--border-width) solid var(--border-color);
129
+ border-radius: calc(var(--radius-sm) + var(--s-3));
130
+ background: var(--page-bg);
131
+ }
132
+ /* Inner bordered row — flex, items aligned to the top so the copy
133
+ button stays pinned up even when the endpoint group wraps onto
134
+ multiple lines.
135
+ min-inline-size gives the row a real floor (--try-it-row-min, capped
136
+ at 100% so it never overflows a tiny container). Once row + Try It
137
+ button can't both fit, the outer Cluster wraps the button to the
138
+ next line — without the floor the row would just shrink forever and
139
+ the button would never drop. */
140
+ .velu-try-it__row {
141
+ display: flex;
142
+ align-items: flex-start;
143
+ gap: var(--s-1);
144
+ padding: var(--s-3);
145
+ border: var(--border-width) solid var(--border-color);
146
+ /* = outer (calc(--radius-sm + --s-3)) - --s-3 padding = --radius-sm */
147
+ border-radius: var(--radius-sm);
148
+ flex: 1;
149
+ min-inline-size: min(var(--try-it-row-min, 24ch), 100%);
150
+ background: var(--page-bg);
151
+ }
152
+ /* Method pill + path — wraps internally (Cluster), fills the row minus
153
+ the copy button. */
154
+ .velu-try-it__endpoint {
155
+ flex: 1;
156
+ min-inline-size: 0;
157
+ }
158
+ .velu-try-it__copy {
159
+ display: inline-flex;
160
+ align-items: center;
161
+ justify-content: center;
162
+ inline-size: 1.75em;
163
+ block-size: 1.75em;
164
+ padding: 0;
165
+ background: transparent;
166
+ border: 0;
167
+ color: var(--muted-color);
168
+ cursor: pointer;
169
+ /* Non-shrinking; pinned to the top of the row so it stays on the
170
+ first line when the endpoint group wraps below. */
171
+ flex: none;
172
+ align-self: flex-start;
173
+ }
174
+ .velu-try-it__copy:hover {
175
+ color: var(--text-color);
176
+ }
177
+ .velu-try-it__cta {
178
+ position: relative;
179
+ overflow: hidden;
180
+ display: inline-flex;
181
+ align-items: center;
182
+ justify-content: center;
183
+ padding-block: var(--s-3);
184
+ padding-inline: var(--s0);
185
+ background: var(--method-cta, var(--accent-color));
186
+ border: 0;
187
+ /* The fixed basis of the concentric chain — never changes. */
188
+ border-radius: var(--radius-sm);
189
+ color: #fff;
190
+ font: inherit;
191
+ font-size: var(--f-h6);
192
+ font-weight: var(--weight-medium);
193
+ line-height: var(--lh-h6);
194
+ cursor: pointer;
195
+ }
196
+ .velu-try-it__cta:hover {
197
+ background: color-mix(in srgb, var(--method-cta, var(--accent-color)) 88%, #000);
198
+ }
199
+ .velu-try-it__cta:disabled {
200
+ cursor: default;
201
+ }
202
+
203
+ /* Label (text + chevron) and the loading spinner are two stacked layers
204
+ that swap with a vertical slide: when loading, the label slides DOWN and
205
+ out the bottom while the spinner slides IN from the top. overflow:hidden
206
+ on the button clips the off-screen states. The label stays in normal flow
207
+ so it fixes the button's width; the spinner overlays it. */
208
+ .velu-try-it__cta-label {
209
+ display: inline-flex;
210
+ align-items: center;
211
+ gap: var(--s-2);
212
+ transition: transform 0.22s ease, opacity 0.18s ease;
213
+ }
214
+ .velu-try-it__cta-spinner {
215
+ position: absolute;
216
+ inset: 0;
217
+ display: inline-flex;
218
+ align-items: center;
219
+ justify-content: center;
220
+ transform: translateY(-110%);
221
+ opacity: 0;
222
+ transition: transform 0.22s ease, opacity 0.18s ease;
223
+ }
224
+ .velu-try-it__cta[data-loading='true'] .velu-try-it__cta-label {
225
+ transform: translateY(120%);
226
+ opacity: 0;
227
+ }
228
+ .velu-try-it__cta[data-loading='true'] .velu-try-it__cta-spinner {
229
+ transform: translateY(0);
230
+ opacity: 1;
231
+ }
232
+ .velu-try-it__cta-spinner svg {
233
+ animation: velu-cta-spin 0.7s linear infinite;
234
+ }
235
+ @keyframes velu-cta-spin {
236
+ to {
237
+ transform: rotate(360deg);
238
+ }
239
+ }
240
+ @media (prefers-reduced-motion: reduce) {
241
+ .velu-try-it__cta-label,
242
+ .velu-try-it__cta-spinner {
243
+ transition-duration: 0.01ms;
244
+ }
245
+ .velu-try-it__cta-spinner svg {
246
+ animation-duration: 1.4s;
247
+ }
248
+ }
249
+ .velu-try-it--get { --method-cta: var(--get-cta-color); }
250
+ .velu-try-it--post { --method-cta: var(--post-cta-color); }
251
+ .velu-try-it--put { --method-cta: var(--put-cta-color); }
252
+ .velu-try-it--patch { --method-cta: var(--patch-cta-color); }
253
+ .velu-try-it--delete{ --method-cta: var(--delete-cta-color); }
254
+
255
+ /* ── ApiClient ─────────────────────────────────────────────────────────── */
256
+ /* max-inline-size: 100% + min-inline-size: 0 keep the client contained
257
+ when it's a flex/grid child (e.g. rendered inside a production
258
+ modal) — without min-inline-size:0 a flex item's default
259
+ `min-width: auto` lets wide content bleed past the container. */
260
+ .velu-api-client {
261
+ position: relative;
262
+ border: var(--border-width) solid var(--border-color);
263
+ border-radius: var(--radius-md);
264
+ background: var(--page-bg);
265
+ overflow: hidden;
266
+ max-inline-size: 100%;
267
+ min-inline-size: 0;
268
+ /* Own query container so the body grid reflows to the client's width
269
+ (it lives in a modal, outside the docs layout container). */
270
+ container: api-client / inline-size;
271
+ }
272
+
273
+ /* Modal close button — sits in its own row at the top of the client,
274
+ X aligned to the inline-end. */
275
+ .velu-api-client__close-row {
276
+ display: flex;
277
+ justify-content: flex-end;
278
+ padding: var(--s-3) var(--s-3) 0;
279
+ }
280
+ .velu-api-client__close {
281
+ display: inline-flex;
282
+ align-items: center;
283
+ justify-content: center;
284
+ inline-size: 1.75em;
285
+ block-size: 1.75em;
286
+ padding: 0;
287
+ background: transparent;
288
+ border: 0;
289
+ border-radius: var(--radius-sm);
290
+ color: var(--muted-color);
291
+ cursor: pointer;
292
+ }
293
+ .velu-api-client__close:hover {
294
+ color: var(--text-color);
295
+ background: var(--surface-color);
296
+ }
297
+
298
+ /* base.css applies a global `* { max-width: var(--measure) }` (66ch
299
+ text-measure cap). Inside ApiClient that would pin the non-excluded
300
+ structural elements — <details>, <table>, <h3>, <p>, <summary> — to
301
+ 66ch, making the whole client look fixed-width even in a wide modal.
302
+ Reset it: every element here manages its own width via flex +
303
+ wrapping, so the client fills whatever container it's given. */
304
+ .velu-api-client * {
305
+ max-inline-size: none;
306
+ }
307
+
308
+ /* Head row: operation dropdown + TryItBar. Layout (flex-wrap + gap +
309
+ align) is provided by <Cluster>; this rule only owns the padding
310
+ that insets both children from the ApiClient frame. */
311
+ .velu-api-client__head {
312
+ padding: var(--s-3);
313
+ }
314
+
315
+ /* Operation dropdown — same shape as TryItBar's inner row so the two
316
+ read as a matched pair. flex: none → hugs its text (natural width
317
+ AND natural height; the Cluster's align: flex-start keeps it from
318
+ stretching to the taller TryItBar's height). */
319
+ .velu-api-client__op {
320
+ position: relative;
321
+ display: flex;
322
+ align-items: center;
323
+ gap: var(--s-2);
324
+ padding: var(--s-3);
325
+ border: var(--border-width) solid var(--border-color);
326
+ border-radius: var(--radius-md);
327
+ background: var(--page-bg);
328
+ color: var(--text-color);
329
+ font-size: var(--f-h6);
330
+ line-height: var(--lh-h6);
331
+ flex: none;
332
+ }
333
+ /* The clickable trigger when the operation is switchable — a bare button
334
+ that keeps the same layout as the static row. */
335
+ .velu-api-client__op-btn {
336
+ display: inline-flex;
337
+ align-items: center;
338
+ gap: var(--s-2);
339
+ margin: 0;
340
+ padding: 0;
341
+ background: transparent;
342
+ border: 0;
343
+ color: inherit;
344
+ font: inherit;
345
+ cursor: pointer;
346
+ }
347
+ .velu-api-client__op-label {
348
+ font-weight: var(--weight-medium);
349
+ }
350
+ .velu-api-client__op-chevron {
351
+ display: inline-flex;
352
+ align-items: center;
353
+ color: var(--muted-color);
354
+ transition: transform 0.15s ease;
355
+ }
356
+ .velu-api-client__op-btn[aria-expanded='true'] .velu-api-client__op-chevron {
357
+ transform: rotate(180deg);
358
+ }
359
+
360
+ /* Operation switcher menu — lists every operation in the tab. */
361
+ .velu-api-client__op-menu {
362
+ position: absolute;
363
+ inset-block-start: calc(100% + var(--s-3));
364
+ inset-inline-start: 0;
365
+ z-index: 5;
366
+ display: flex;
367
+ flex-direction: column;
368
+ gap: 2px;
369
+ margin: 0;
370
+ padding: var(--s-3);
371
+ list-style: none;
372
+ min-inline-size: 16rem;
373
+ max-block-size: 18rem;
374
+ overflow-y: auto;
375
+ background: var(--page-bg);
376
+ border: var(--border-width) solid var(--border-color);
377
+ border-radius: var(--radius-md);
378
+ box-shadow: 0 12px 32px -12px rgba(0, 0, 0, 0.4);
379
+ }
380
+ .velu-api-client__op-item {
381
+ display: flex;
382
+ align-items: center;
383
+ gap: var(--s-2);
384
+ inline-size: 100%;
385
+ padding: var(--s-3) var(--s-2);
386
+ background: transparent;
387
+ border: 0;
388
+ border-radius: var(--radius-sm);
389
+ color: var(--text-color);
390
+ font: inherit;
391
+ font-size: var(--f-h6);
392
+ text-align: start;
393
+ cursor: pointer;
394
+ }
395
+ .velu-api-client__op-item:hover,
396
+ .velu-api-client__op-item--active {
397
+ background: var(--surface-color);
398
+ }
399
+ .velu-api-client__op-item-label {
400
+ white-space: nowrap;
401
+ overflow: hidden;
402
+ text-overflow: ellipsis;
403
+ }
404
+
405
+ /* Inside ApiClient the outer frame already supplies the box — strip
406
+ the TryItBar's own outer border / radius / padding (the head's
407
+ padding wraps both children). flex: 1 fills the head beside the
408
+ natural-width dropdown; the min-width floor makes Cluster wrap the
409
+ bar below the dropdown once it can't keep that width. */
410
+ .velu-api-client__bar {
411
+ flex: 1;
412
+ min-inline-size: min(var(--try-it-row-min, 24ch), 100%);
413
+ border: 0;
414
+ border-radius: 0;
415
+ padding: 0;
416
+ background: transparent;
417
+ }
418
+
419
+ /* Body grid with named areas so the three slots — form / live response /
420
+ code samples — can be placed AND reordered independently.
421
+ Wide (the client is its own query container, set on .velu-api-client):
422
+ form fills the left column; response sits top-right with the samples
423
+ below it. When there's no response yet, the samples take the whole right
424
+ column.
425
+ Narrow (single column): the live response moves ABOVE the form so a Send
426
+ result is visible without scrolling past the inputs; form then samples
427
+ follow. */
428
+ .velu-api-client__body {
429
+ display: grid;
430
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
431
+ grid-template-areas: 'form aside';
432
+ align-items: start;
433
+ gap: var(--s2);
434
+ padding: var(--s2);
435
+ }
436
+ .velu-api-client__body[data-has-response='true'] {
437
+ grid-template-areas:
438
+ 'form response'
439
+ 'form aside';
440
+ }
441
+ .velu-api-client__left {
442
+ grid-area: form;
443
+ }
444
+ .velu-api-client__response {
445
+ grid-area: response;
446
+ }
447
+ .velu-api-client__right {
448
+ grid-area: aside;
449
+ }
450
+ .velu-api-client__left,
451
+ .velu-api-client__right,
452
+ .velu-api-client__response {
453
+ display: flex;
454
+ flex-direction: column;
455
+ gap: var(--s1);
456
+ min-inline-size: 0;
457
+ }
458
+
459
+ @container api-client (max-width: 40rem) {
460
+ .velu-api-client__body,
461
+ .velu-api-client__body[data-has-response='true'] {
462
+ grid-template-columns: 1fr;
463
+ grid-template-areas:
464
+ 'form'
465
+ 'aside';
466
+ }
467
+ .velu-api-client__body[data-has-response='true'] {
468
+ grid-template-areas:
469
+ 'response'
470
+ 'form'
471
+ 'aside';
472
+ }
473
+ }
474
+
475
+ .velu-api-client__title {
476
+ margin: 0;
477
+ font-size: var(--f-h3);
478
+ line-height: var(--lh-h3);
479
+ font-weight: var(--weight-medium);
480
+ color: var(--text-color);
481
+ }
482
+ .velu-api-client__description {
483
+ margin: 0;
484
+ color: var(--text-color);
485
+ font-size: var(--f-body);
486
+ line-height: var(--lh-body);
487
+ }
488
+
489
+ /* ── ApiField (input-bearing field inside an Accordion section) ─────────── */
490
+ /* flex-wrap pair: info column (label + description) and the control
491
+ column (input). Wraps to stacked on narrow widths — no media query. */
492
+ .velu-api-field {
493
+ display: flex;
494
+ flex-wrap: wrap;
495
+ gap: var(--s0);
496
+ align-items: flex-start;
497
+ }
498
+ .velu-api-field__info {
499
+ flex: 1 1 16ch;
500
+ min-inline-size: 0;
501
+ display: flex;
502
+ flex-direction: column;
503
+ gap: var(--s-2);
504
+ }
505
+ .velu-api-field__name {
506
+ font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
507
+ font-size: var(--f-h5);
508
+ line-height: var(--lh-h5);
509
+ font-weight: var(--weight-medium);
510
+ color: var(--accent-color);
511
+ }
512
+ /* Chip + required pill — same recipe as Field's, kept local so ApiField
513
+ doesn't depend on field.css. */
514
+ .velu-api-field__chip {
515
+ display: inline-flex;
516
+ align-items: center;
517
+ padding-block: 0;
518
+ padding-inline: var(--s-3);
519
+ background: var(--surface-color);
520
+ border-radius: var(--radius-sm);
521
+ font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
522
+ font-size: var(--f-h6);
523
+ line-height: var(--lh-h6);
524
+ color: var(--muted-color);
525
+ }
526
+ .velu-api-field__required {
527
+ display: inline-flex;
528
+ align-items: center;
529
+ padding-block: 0;
530
+ padding-inline: var(--s-3);
531
+ background: color-mix(in srgb, var(--accent-color) 18%, transparent);
532
+ border-radius: var(--radius-sm);
533
+ font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
534
+ font-size: var(--f-h6);
535
+ line-height: var(--lh-h6);
536
+ color: var(--accent-color);
537
+ }
538
+ .velu-api-field__desc {
539
+ color: var(--text-color);
540
+ font-size: var(--f-h6);
541
+ line-height: var(--lh-h6);
542
+ }
543
+
544
+ /* Control column — the actual <input>, optionally with a static prefix
545
+ (e.g. "Bearer"). The whole thing reads as one bordered field. */
546
+ .velu-api-field__control {
547
+ flex: 1 1 16ch;
548
+ min-inline-size: 0;
549
+ display: flex;
550
+ align-items: center;
551
+ border: var(--border-width) solid var(--border-color);
552
+ border-radius: var(--radius-sm);
553
+ background: var(--page-bg);
554
+ font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
555
+ font-size: var(--f-h6);
556
+ }
557
+ .velu-api-field__control:focus-within {
558
+ border-color: var(--text-color);
559
+ }
560
+ .velu-api-field__prefix {
561
+ flex: none;
562
+ padding-inline: var(--s-2);
563
+ color: var(--muted-color);
564
+ }
565
+ .velu-api-field__input {
566
+ flex: 1;
567
+ min-inline-size: 0;
568
+ padding-block: var(--s-3);
569
+ padding-inline: var(--s-2);
570
+ background: transparent;
571
+ border: 0;
572
+ font: inherit;
573
+ color: var(--text-color);
574
+ }
575
+ .velu-api-field__input::placeholder {
576
+ color: var(--muted-color);
577
+ }
578
+ .velu-api-field__input:focus {
579
+ outline: none;
580
+ }
581
+
582
+ /* ── ApiSidebar ────────────────────────────────────────────────────────── */
583
+ /* Vertical rhythm is the Stack primitive (set inline by ApiSidebar.jsx);
584
+ this block holds only the rail, group header, row layout, active
585
+ state, and icon sizing — same split as sidebar.css. */
586
+ .velu-api-sidebar {
587
+ border-inline-start: var(--border-width) solid var(--border-color);
588
+ margin-inline-start: var(--s1);
589
+ }
590
+
591
+ .velu-api-sidebar__section {
592
+ display: flex;
593
+ align-items: center;
594
+ gap: var(--s-2);
595
+ padding-inline: var(--s-3);
596
+ inline-size: fit-content;
597
+ font-weight: var(--weight-medium);
598
+ text-transform: uppercase;
599
+ }
600
+
601
+ .velu-api-sidebar__list {
602
+ list-style: none;
603
+ margin: 0;
604
+ padding: 0;
605
+ }
606
+
607
+ /* Endpoint row — method pill + name. align-items: flex-start so the
608
+ pill stays on the first line when a long name wraps. */
609
+ .velu-api-sidebar__item {
610
+ display: flex;
611
+ align-items: flex-start;
612
+ gap: var(--s-2);
613
+ padding-inline: var(--s0);
614
+ color: var(--text-color);
615
+ text-decoration: none;
616
+ }
617
+ .velu-api-sidebar__item--active {
618
+ color: var(--accent-color);
619
+ border-inline-start: 2px solid var(--accent-color);
620
+ }
621
+ .velu-api-sidebar__label {
622
+ font-size: var(--f-body);
623
+ line-height: var(--lh-h6);
624
+ }
625
+
626
+ .velu-api-sidebar__icon {
627
+ display: inline-flex;
628
+ flex: none;
629
+ inline-size: var(--f-body);
630
+ block-size: var(--f-body);
631
+ }
632
+ .velu-api-sidebar__icon svg {
633
+ inline-size: 100%;
634
+ block-size: 100%;
635
+ }