@veluai/velu 0.2.25 → 0.2.28

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 (114) hide show
  1. package/README.md +80 -80
  2. package/dist/cli.js +44 -44
  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 +125 -125
  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/ChangelogFilters.jsx +75 -75
  16. package/runtime/velu-ui/components/Chatbot.jsx +972 -972
  17. package/runtime/velu-ui/components/CodeBlock.jsx +375 -375
  18. package/runtime/velu-ui/components/Columns.jsx +56 -56
  19. package/runtime/velu-ui/components/ContextMenu.jsx +327 -327
  20. package/runtime/velu-ui/components/ErrorCard.jsx +138 -138
  21. package/runtime/velu-ui/components/Field.jsx +81 -81
  22. package/runtime/velu-ui/components/Image.jsx +163 -163
  23. package/runtime/velu-ui/components/Logo.jsx +31 -31
  24. package/runtime/velu-ui/components/MethodBadge.jsx +31 -31
  25. package/runtime/velu-ui/components/NavSelect.jsx +108 -108
  26. package/runtime/velu-ui/components/NotFound.jsx +63 -63
  27. package/runtime/velu-ui/components/PageFeedback.jsx +219 -219
  28. package/runtime/velu-ui/components/PageFooter.jsx +145 -145
  29. package/runtime/velu-ui/components/PageHeader.jsx +422 -422
  30. package/runtime/velu-ui/components/PageNav.jsx +77 -77
  31. package/runtime/velu-ui/components/PoweredBy.jsx +51 -51
  32. package/runtime/velu-ui/components/Prompt.jsx +115 -115
  33. package/runtime/velu-ui/components/Search.jsx +460 -460
  34. package/runtime/velu-ui/components/Sidebar.jsx +246 -246
  35. package/runtime/velu-ui/components/SocialLinks.jsx +90 -90
  36. package/runtime/velu-ui/components/Steps.jsx +65 -65
  37. package/runtime/velu-ui/components/ThemeToggle.jsx +48 -48
  38. package/runtime/velu-ui/components/Toc.jsx +537 -537
  39. package/runtime/velu-ui/components/TocBar.jsx +195 -195
  40. package/runtime/velu-ui/components/Tree.jsx +87 -87
  41. package/runtime/velu-ui/components/TryItBar.jsx +102 -102
  42. package/runtime/velu-ui/components/Update.jsx +92 -92
  43. package/runtime/velu-ui/components/accordion.css +92 -92
  44. package/runtime/velu-ui/components/api-page.css +208 -208
  45. package/runtime/velu-ui/components/api.css +635 -635
  46. package/runtime/velu-ui/components/ask-bar.css +103 -103
  47. package/runtime/velu-ui/components/card.css +105 -105
  48. package/runtime/velu-ui/components/changelog-filters.css +43 -43
  49. package/runtime/velu-ui/components/chatbot.css +687 -687
  50. package/runtime/velu-ui/components/code-block.css +263 -263
  51. package/runtime/velu-ui/components/context-menu.css +199 -199
  52. package/runtime/velu-ui/components/docs-layout.css +822 -822
  53. package/runtime/velu-ui/components/field.css +82 -82
  54. package/runtime/velu-ui/components/image.css +237 -237
  55. package/runtime/velu-ui/components/nav-select.css +157 -157
  56. package/runtime/velu-ui/components/not-found.css +94 -94
  57. package/runtime/velu-ui/components/page-feedback.css +261 -261
  58. package/runtime/velu-ui/components/page-footer.css +130 -130
  59. package/runtime/velu-ui/components/page-header.css +558 -558
  60. package/runtime/velu-ui/components/page-nav.css +50 -50
  61. package/runtime/velu-ui/components/powered-by.css +92 -92
  62. package/runtime/velu-ui/components/prompt.css +99 -99
  63. package/runtime/velu-ui/components/search.css +307 -307
  64. package/runtime/velu-ui/components/sidebar.css +205 -205
  65. package/runtime/velu-ui/components/steps.css +77 -77
  66. package/runtime/velu-ui/components/theme-toggle.css +102 -102
  67. package/runtime/velu-ui/components/toc-bar.css +234 -234
  68. package/runtime/velu-ui/components/tree.css +49 -49
  69. package/runtime/velu-ui/components/update.css +111 -111
  70. package/runtime/velu-ui/index.js +58 -58
  71. package/runtime/velu-ui/lib/api-send.js +118 -118
  72. package/runtime/velu-ui/lib/brand-icons.jsx +103 -103
  73. package/runtime/velu-ui/lib/component-schemas.js +100 -100
  74. package/runtime/velu-ui/lib/copyText.js +64 -64
  75. package/runtime/velu-ui/lib/docs-assistant.js +273 -273
  76. package/runtime/velu-ui/lib/lang-icons.jsx +147 -147
  77. package/runtime/velu-ui/lib/page-feedback.js +72 -72
  78. package/runtime/velu-ui/lib/pagefind.js +116 -116
  79. package/runtime/velu-ui/lib/prism-langs.js +957 -957
  80. package/runtime/velu-ui/lib/prism-loader.js +74 -74
  81. package/runtime/velu-ui/lib/resolveIcon.jsx +29 -29
  82. package/runtime/velu-ui/lib/scrollIntoNearestView.js +66 -66
  83. package/runtime/velu-ui/mdx-components.jsx +107 -107
  84. package/runtime/velu-ui/primitives/Cluster.jsx +49 -49
  85. package/runtime/velu-ui/primitives/Stack.jsx +63 -63
  86. package/runtime/velu-ui/primitives/Switcher.jsx +57 -57
  87. package/runtime/velu-ui/primitives/stack.css +3 -3
  88. package/runtime/velu-ui/primitives/switcher.css +25 -25
  89. package/runtime/velu-ui/styles.css +48 -48
  90. package/runtime/velu-ui/tokens.css +4 -4
  91. package/schema/velu.schema.json +419 -419
  92. package/src/lib/extract-mdx-error.js +170 -170
  93. package/src/lib/issues.js +159 -159
  94. package/src/lib/known-components.js +35 -35
  95. package/src/navigation.js +459 -459
  96. package/src/runtime/App.jsx +1754 -1754
  97. package/src/runtime/ErrorBoundary.jsx +54 -54
  98. package/src/runtime/client-entry.jsx +27 -27
  99. package/src/runtime/server-entry.jsx +24 -24
  100. package/src/template.html +48 -48
  101. package/templates/starter/ai-tools/claude-code.mdx +26 -26
  102. package/templates/starter/ai-tools/cursor.mdx +17 -17
  103. package/templates/starter/api-reference/introduction.mdx +43 -43
  104. package/templates/starter/development.mdx +19 -19
  105. package/templates/starter/essentials/code.mdx +29 -29
  106. package/templates/starter/essentials/images.mdx +29 -29
  107. package/templates/starter/essentials/markdown.mdx +25 -25
  108. package/templates/starter/essentials/navigation.mdx +39 -39
  109. package/templates/starter/essentials/settings.mdx +30 -30
  110. package/templates/starter/favicon.svg +6 -6
  111. package/templates/starter/index.mdx +31 -31
  112. package/templates/starter/openapi.json +160 -160
  113. package/templates/starter/quickstart.mdx +31 -31
  114. package/templates/starter/velu.json +40 -40
@@ -1,320 +1,320 @@
1
- /* Fonts are loaded via <link rel="preconnect"/"stylesheet"> in template.html
2
- (faster than an @import inside critical CSS — non-blocking, parallel). */
3
- :root {
4
- --ratio: 1.25;
5
- --s-6: calc(var(--s-5) / var(--ratio));
6
- --s-5: calc(var(--s-4) / var(--ratio));
7
- --s-4: calc(var(--s-3) / var(--ratio));
8
- --s-3: calc(var(--s-2) / var(--ratio));
9
- --s-2: calc(var(--s-1) / var(--ratio));
10
- --s-1: calc(var(--s0) / var(--ratio));
11
- --s0: 1rem;
12
- --s1: calc(var(--s0) * var(--ratio));
13
- --s2: calc(var(--s1) * var(--ratio));
14
- --s3: calc(var(--s2) * var(--ratio));
15
- --s4: calc(var(--s3) * var(--ratio));
16
- --s5: calc(var(--s4) * var(--ratio));
17
- }
18
-
19
- /* Semantic color tokens — verbatim from Figma (1:1 names, no translation).
20
- Components reference ONLY these (never raw hex), so theme switching =
21
- swapping this block (zero component changes).
22
- --page-bg is PROVISIONAL: Figma has no explicit page-background token yet
23
- (see note to Aravind) — replace once defined. */
24
- :root {
25
- --page-bg: #ffffff;
26
-
27
- --border-color: #dcdcde;
28
- --text-color: #000000;
29
- --accent-color: #dc143c;
30
- --muted-color: #7a7a7a;
31
- --surface-color: #f2f3f4;
32
-
33
- --note-bg-color: #f2f3f4;
34
- --note-stroke-color: #6b7280;
35
- --warning-bg-color: #fef3e2;
36
- --warning-stroke-color: #d97706;
37
- --info-bg-color: #e8f4fd;
38
- --info-stroke-color: #3b82f6;
39
- --tip-bg-color: #e8f5e9;
40
- --tip-stroke-color: #16a34a;
41
- --check-bg-color: #e6f9ed;
42
- --check-stroke-color: #22c55e;
43
- --danger-bg-color: #fde8e8;
44
- --danger-stroke-color: #dc2626;
45
- --callout-bg-color: #f3e8fd;
46
- --callout-stroke-color: #8b5cf6;
47
-
48
- --post-pill-color: #e8f4fd;
49
- --post-pill-stroke-color: #91bbf9;
50
- --post-cta-color: #3064e3;
51
- --get-pill-color: #e6f9ed;
52
- --get-pill-stroke-color: #22c55e;
53
- --get-cta-color: #22c55e;
54
- --put-pill-color: #fef3e2;
55
- --put-pill-stroke-color: #d97706;
56
- --put-cta-color: #d97706;
57
- --delete-pill-color: #fde8e8;
58
- --delete-pill-stroke-color: #dc2626;
59
- --delete-cta-color: #dc2626;
60
- --patch-pill-color: #f3e8fd;
61
- --patch-pill-stroke-color: #8b5cf6;
62
- --patch-cta-color: #8b5cf6;
63
- }
64
- :root[data-theme="dark"] {
65
- --page-bg: #0D0E10;
66
-
67
- --border-color: #262827;
68
- --text-color: #eeeff1;
69
- --accent-color: #dc143c;
70
- --muted-color: #7a7a7a;
71
- --surface-color: #323334;
72
-
73
- --note-bg-color: #1a1a1c;
74
- --note-stroke-color: #eeeff1;
75
- --warning-bg-color: #2a1f0d;
76
- --warning-stroke-color: #7a5a1f;
77
- --info-bg-color: #0d1f2a;
78
- --info-stroke-color: #1f5a7a;
79
- --tip-bg-color: #0d2a1a;
80
- --tip-stroke-color: #1f7a4a;
81
- --check-bg-color: #0d2a1a;
82
- --check-stroke-color: #1f7a4a;
83
- --danger-bg-color: #2a0d0d;
84
- --danger-stroke-color: #7a1f1f;
85
- --callout-bg-color: #1f0d2a;
86
- --callout-stroke-color: #5a1f7a;
87
-
88
- --post-pill-color: #1e3a8a;
89
- --post-pill-stroke-color: #3b82f6;
90
- --post-cta-color: #2563eb;
91
- --get-pill-color: #065f46;
92
- --get-pill-stroke-color: #10b981;
93
- --get-cta-color: #059669;
94
- --put-pill-color: #78350f;
95
- --put-pill-stroke-color: #f59e0b;
96
- --put-cta-color: #d97706;
97
- --delete-pill-color: #7f1d1d;
98
- --delete-pill-stroke-color: #ef4444;
99
- --delete-cta-color: #dc2626;
100
- --patch-pill-color: #4c1d95;
101
- --patch-pill-stroke-color: #8b5cf6;
102
- --patch-cta-color: #7c3aed;
103
- }
104
-
105
- :root {
106
- --measure: 66ch;
107
- --font-sans: "Google Sans Flex", sans-serif;
108
- --font-mono: "Google Sans Code", ui-monospace, SFMono-Regular, monospace;
109
- --font-brand: "Outfit", var(--font-sans);
110
- font-family: var(--font-sans);
111
-
112
- /* Approx height of the docs PageHeader (used as the offset for sticky
113
- sidebars / TOC so they stick BELOW the header, not behind it). */
114
- --velu-header-height: 7rem;
115
-
116
- /* Fluid font sizes — 375px → 1440px viewport */
117
- --f-body: 1rem; /* 16 → 16 */
118
- --f-h7: calc(var(--f-h6) / var(--ratio)); /* micro UI text — one modular step below h6 (chips, captions, kbd) */
119
- --f-h6: clamp(0.75rem, 0.188vw + 0.68rem, 0.875rem); /* 12 → 14 (reversed: mobile 14 → desktop 12, see note) */
120
- --f-h5: 1rem; /* 16 → 16 */
121
- --f-h4: clamp(1.125rem, 0.235vw + 1.07rem, 1.375rem); /* 18 → 22 */
122
- --f-h3: clamp(1.3125rem,0.423vw + 1.214rem, 1.75rem); /* 21 → 28 */
123
- --f-h2: clamp(1.5rem, 0.704vw + 1.335rem, 2.25rem); /* 24 → 36 */
124
- --f-h1: clamp(1.6875rem,1.972vw + 1.226rem, 3rem); /* 27 → 48 */
125
-
126
- /* Line-height tokens — unitless (height ÷ font-size from Figma). The
127
- single source of truth for leading; components reference these, never
128
- a hardcoded ratio. */
129
- --lh-body: 1.75;
130
- --lh-h1: 1.75;
131
- --lh-h2: 1.78;
132
- --lh-h3: 1.71;
133
- --lh-h4: 1.82;
134
- --lh-h5: 1.75;
135
- --lh-h6: 1.71;
136
- --lh-h7: 1.71;
137
-
138
- /* Hairline width — single source of truth for every box border, divider
139
- and rail. (Sub-pixel: crisp on hi-dpi; some 1x displays round it.) */
140
- --border-width: 0.5px;
141
-
142
- /* Icon stroke weight — single source of truth for every lucide icon. */
143
- --icon-stroke: 1.5;
144
-
145
- /* Icon size scale — em-relative so an icon next to text inherits the
146
- text size automatically. `--icon-size` matches surrounding text;
147
- `--icon-size-lg` is one modular step larger (for nav lists / trees
148
- where the icon should slightly outweigh the label). */
149
- --icon-size: 1em;
150
- --icon-size-lg: calc(1em * var(--ratio));
151
-
152
- /* Corner-radius scale, derived from --s0 (16px) — no raw literals.
153
- sm 8 / md 16 / lg 32. Components pick the right step. */
154
- --radius-sm: calc(var(--s0) / 2);
155
- --radius-md: var(--s0);
156
- --radius-lg: calc(var(--s0) * 2);
157
-
158
- /* Font-weight scale — single source of truth so components never
159
- write raw 300/400/500/600/700. Matches Google Sans Flex's
160
- variable-font axis stops. */
161
- --weight-light: 300;
162
- --weight-normal: 400;
163
- --weight-medium: 500;
164
- --weight-semibold: 600;
165
- --weight-bold: 700;
166
- }
167
-
168
- /* lucide-react adds class="lucide …" to every icon svg. This one rule
169
- tokenizes stroke weight app-wide (CSS overrides the svg's stroke-width
170
- attribute), so no component sets it per-icon. */
171
- .lucide {
172
- stroke-width: var(--icon-stroke);
173
- }
174
-
175
- /* Prose rhythm — wraps MDX content. MDX compiles to a flat list of
176
- sibling block elements (h1, p, the velu-ui components, etc.).
177
- Spacing is scaled by HEADING LEVEL so the document's structure is
178
- readable at a glance:
179
- - default sibling pair (paragraph rhythm): --s1
180
- - before any heading (section break): scaled by level
181
- - after a heading (heading → first child): one step under default
182
- The rules use adjacent-sibling selectors so every same-level heading
183
- gets the same lead-in regardless of what came before it (sibling
184
- equality), and the larger before-heading gap reads as the section
185
- break in every case. The owl rule sets the default; per-heading
186
- rules below override it via source order (same specificity). */
187
-
188
- /* Scroll-anchor offset for in-page links: when a TOC click lands on
189
- a heading, the browser scrolls so the heading sits at the viewport
190
- top — which would otherwise put it BEHIND the sticky chrome
191
- (header + TocBar). `scroll-margin-block-start` tells the scroll
192
- algorithm to leave that much space above the target.
193
-
194
- --velu-scroll-offset is published by App.jsx as
195
- `headerHeight + tocbarHeight + 1rem`, measured live via
196
- ResizeObserver. The scroll-spy reads the SAME variable as its
197
- trigger line, so scrollIntoView lands the heading exactly where
198
- the spy promotes it — no magic numbers, no drift. */
199
- .velu-hero h1,
200
- .velu-prose :is(h1, h2, h3, h4, h5, h6) {
201
- scroll-margin-block-start: var(--velu-scroll-offset, 5rem);
202
- }
203
-
204
- /* Default prose rhythm. */
205
- .velu-prose > * + * {
206
- margin-block-start: var(--s1);
207
- }
208
-
209
- /* Before-heading: progressively larger gap above higher-level headings.
210
- Same level → same gap → siblings read at equal intervals. */
211
- .velu-prose > * + h2 {
212
- margin-block-start: var(--s4);
213
- }
214
- .velu-prose > * + h3 {
215
- margin-block-start: var(--s3);
216
- }
217
- .velu-prose > * + h4 {
218
- margin-block-start: var(--s2);
219
- }
220
-
221
- /* After-heading: tighter, so the heading reads as "introducing" what
222
- follows rather than floating alone above a chasm. */
223
- .velu-prose > h1 + *,
224
- .velu-prose > h2 + *,
225
- .velu-prose > h3 + *,
226
- .velu-prose > h4 + *,
227
- .velu-prose > h5 + *,
228
- .velu-prose > h6 + * {
229
- margin-block-start: var(--s0);
230
- }
231
-
232
- /* Page hero — the frontmatter (title + description) is wrapped in
233
- `.velu-hero` so the title and description sit tight as a single
234
- unit, and a larger break separates the hero from the prose body. */
235
- .velu-hero > h1 + p {
236
- margin-block-start: var(--s-2);
237
- }
238
- /* hero → body is an h1 → h2 transition (level-down, not peer-to-peer),
239
- so the break is one modular step LARGER than the regular section
240
- break above an h2 (--s4). Keeps the scale strictly monotonic:
241
- level-down break > peer break. */
242
- .velu-hero + .velu-prose {
243
- margin-block-start: var(--s5);
244
- }
245
-
246
- /* Discreet thin scrollbar with a tokenised colour in every state — applied
247
- GLOBALLY (the `*` selector) so every scrollable element inherits it by
248
- default: the chatbot, dialogs, and any future component, with no
249
- per-component opt-in. Component-specific scrollbar rules win via
250
- specificity (e.g. the nav/TOC reveal-on-hover overrides below).
251
- `.velu-hide-scrollbar` stays as an explicit alias for existing markup.
252
-
253
- No transitions: Firefox doesn't honour CSS transitions on `scrollbar-color`
254
- consistently, and the in-between interpolation + its auto-derived
255
- hover/active colours can flash a yellow/amber accent (an OS / system accent
256
- when interpolating). Hard switches avoid that. Same reason every WebKit
257
- thumb pseudo-state is set explicitly — otherwise Chromium can fall back to
258
- the Windows 11 system accent on hover. */
259
- *,
260
- .velu-hide-scrollbar {
261
- scrollbar-width: thin;
262
- /* Single colour both at rest and on hover. Firefox auto-darkens on
263
- interaction, but starting from a defined light grey keeps the
264
- derived shade in the same family (no yellow flash). */
265
- scrollbar-color: var(--border-color) transparent;
266
- }
267
- *::-webkit-scrollbar,
268
- .velu-hide-scrollbar::-webkit-scrollbar {
269
- inline-size: 6px;
270
- block-size: 6px;
271
- }
272
- *::-webkit-scrollbar-track,
273
- .velu-hide-scrollbar::-webkit-scrollbar-track {
274
- background: transparent;
275
- }
276
- *::-webkit-scrollbar-thumb,
277
- .velu-hide-scrollbar::-webkit-scrollbar-thumb {
278
- background: var(--border-color);
279
- border-radius: 999px;
280
- }
281
- *::-webkit-scrollbar-thumb:hover,
282
- *::-webkit-scrollbar-thumb:active,
283
- .velu-hide-scrollbar::-webkit-scrollbar-thumb:hover,
284
- .velu-hide-scrollbar::-webkit-scrollbar-thumb:active {
285
- background: var(--muted-color);
286
- }
287
-
288
- /* Unitless line-height ratios (height ÷ font-size from Figma) */
289
- body {
290
- font-size: var(--f-body);
291
- line-height: var(--lh-body);
292
- font-weight: var(--weight-normal);
293
- background: var(--page-bg);
294
- color: var(--text-color);
295
- }
296
- h1 { font-size: var(--f-h1); line-height: var(--lh-h1); font-weight: var(--weight-semibold); }
297
- h2 { font-size: var(--f-h2); line-height: var(--lh-h2); font-weight: var(--weight-medium); }
298
- h3 { font-size: var(--f-h3); line-height: var(--lh-h3); font-weight: var(--weight-medium); }
299
- h4 { font-size: var(--f-h4); line-height: var(--lh-h4); font-weight: var(--weight-normal); }
300
- h5 { font-size: var(--f-h5); line-height: var(--lh-h5); font-weight: var(--weight-normal); }
301
- h6 { font-size: var(--f-h6); line-height: var(--lh-h6); font-weight: var(--weight-normal); }
302
-
303
- * {
304
- max-width: var(--measure);
305
- box-sizing: border-box;
306
- }
307
-
308
- html,
309
- body,
310
- div,
311
- header,
312
- nav,
313
- main,
314
- footer,
315
- pre,
316
- code,
317
- span,
318
- button {
319
- max-width: none;
320
- }
1
+ /* Fonts are loaded via <link rel="preconnect"/"stylesheet"> in template.html
2
+ (faster than an @import inside critical CSS — non-blocking, parallel). */
3
+ :root {
4
+ --ratio: 1.25;
5
+ --s-6: calc(var(--s-5) / var(--ratio));
6
+ --s-5: calc(var(--s-4) / var(--ratio));
7
+ --s-4: calc(var(--s-3) / var(--ratio));
8
+ --s-3: calc(var(--s-2) / var(--ratio));
9
+ --s-2: calc(var(--s-1) / var(--ratio));
10
+ --s-1: calc(var(--s0) / var(--ratio));
11
+ --s0: 1rem;
12
+ --s1: calc(var(--s0) * var(--ratio));
13
+ --s2: calc(var(--s1) * var(--ratio));
14
+ --s3: calc(var(--s2) * var(--ratio));
15
+ --s4: calc(var(--s3) * var(--ratio));
16
+ --s5: calc(var(--s4) * var(--ratio));
17
+ }
18
+
19
+ /* Semantic color tokens — verbatim from Figma (1:1 names, no translation).
20
+ Components reference ONLY these (never raw hex), so theme switching =
21
+ swapping this block (zero component changes).
22
+ --page-bg is PROVISIONAL: Figma has no explicit page-background token yet
23
+ (see note to Aravind) — replace once defined. */
24
+ :root {
25
+ --page-bg: #ffffff;
26
+
27
+ --border-color: #dcdcde;
28
+ --text-color: #000000;
29
+ --accent-color: #dc143c;
30
+ --muted-color: #7a7a7a;
31
+ --surface-color: #f2f3f4;
32
+
33
+ --note-bg-color: #f2f3f4;
34
+ --note-stroke-color: #6b7280;
35
+ --warning-bg-color: #fef3e2;
36
+ --warning-stroke-color: #d97706;
37
+ --info-bg-color: #e8f4fd;
38
+ --info-stroke-color: #3b82f6;
39
+ --tip-bg-color: #e8f5e9;
40
+ --tip-stroke-color: #16a34a;
41
+ --check-bg-color: #e6f9ed;
42
+ --check-stroke-color: #22c55e;
43
+ --danger-bg-color: #fde8e8;
44
+ --danger-stroke-color: #dc2626;
45
+ --callout-bg-color: #f3e8fd;
46
+ --callout-stroke-color: #8b5cf6;
47
+
48
+ --post-pill-color: #e8f4fd;
49
+ --post-pill-stroke-color: #91bbf9;
50
+ --post-cta-color: #3064e3;
51
+ --get-pill-color: #e6f9ed;
52
+ --get-pill-stroke-color: #22c55e;
53
+ --get-cta-color: #22c55e;
54
+ --put-pill-color: #fef3e2;
55
+ --put-pill-stroke-color: #d97706;
56
+ --put-cta-color: #d97706;
57
+ --delete-pill-color: #fde8e8;
58
+ --delete-pill-stroke-color: #dc2626;
59
+ --delete-cta-color: #dc2626;
60
+ --patch-pill-color: #f3e8fd;
61
+ --patch-pill-stroke-color: #8b5cf6;
62
+ --patch-cta-color: #8b5cf6;
63
+ }
64
+ :root[data-theme="dark"] {
65
+ --page-bg: #0D0E10;
66
+
67
+ --border-color: #262827;
68
+ --text-color: #eeeff1;
69
+ --accent-color: #dc143c;
70
+ --muted-color: #7a7a7a;
71
+ --surface-color: #323334;
72
+
73
+ --note-bg-color: #1a1a1c;
74
+ --note-stroke-color: #eeeff1;
75
+ --warning-bg-color: #2a1f0d;
76
+ --warning-stroke-color: #7a5a1f;
77
+ --info-bg-color: #0d1f2a;
78
+ --info-stroke-color: #1f5a7a;
79
+ --tip-bg-color: #0d2a1a;
80
+ --tip-stroke-color: #1f7a4a;
81
+ --check-bg-color: #0d2a1a;
82
+ --check-stroke-color: #1f7a4a;
83
+ --danger-bg-color: #2a0d0d;
84
+ --danger-stroke-color: #7a1f1f;
85
+ --callout-bg-color: #1f0d2a;
86
+ --callout-stroke-color: #5a1f7a;
87
+
88
+ --post-pill-color: #1e3a8a;
89
+ --post-pill-stroke-color: #3b82f6;
90
+ --post-cta-color: #2563eb;
91
+ --get-pill-color: #065f46;
92
+ --get-pill-stroke-color: #10b981;
93
+ --get-cta-color: #059669;
94
+ --put-pill-color: #78350f;
95
+ --put-pill-stroke-color: #f59e0b;
96
+ --put-cta-color: #d97706;
97
+ --delete-pill-color: #7f1d1d;
98
+ --delete-pill-stroke-color: #ef4444;
99
+ --delete-cta-color: #dc2626;
100
+ --patch-pill-color: #4c1d95;
101
+ --patch-pill-stroke-color: #8b5cf6;
102
+ --patch-cta-color: #7c3aed;
103
+ }
104
+
105
+ :root {
106
+ --measure: 66ch;
107
+ --font-sans: "Google Sans Flex", sans-serif;
108
+ --font-mono: "Google Sans Code", ui-monospace, SFMono-Regular, monospace;
109
+ --font-brand: "Outfit", var(--font-sans);
110
+ font-family: var(--font-sans);
111
+
112
+ /* Approx height of the docs PageHeader (used as the offset for sticky
113
+ sidebars / TOC so they stick BELOW the header, not behind it). */
114
+ --velu-header-height: 7rem;
115
+
116
+ /* Fluid font sizes — 375px → 1440px viewport */
117
+ --f-body: 1rem; /* 16 → 16 */
118
+ --f-h7: calc(var(--f-h6) / var(--ratio)); /* micro UI text — one modular step below h6 (chips, captions, kbd) */
119
+ --f-h6: clamp(0.75rem, 0.188vw + 0.68rem, 0.875rem); /* 12 → 14 (reversed: mobile 14 → desktop 12, see note) */
120
+ --f-h5: 1rem; /* 16 → 16 */
121
+ --f-h4: clamp(1.125rem, 0.235vw + 1.07rem, 1.375rem); /* 18 → 22 */
122
+ --f-h3: clamp(1.3125rem,0.423vw + 1.214rem, 1.75rem); /* 21 → 28 */
123
+ --f-h2: clamp(1.5rem, 0.704vw + 1.335rem, 2.25rem); /* 24 → 36 */
124
+ --f-h1: clamp(1.6875rem,1.972vw + 1.226rem, 3rem); /* 27 → 48 */
125
+
126
+ /* Line-height tokens — unitless (height ÷ font-size from Figma). The
127
+ single source of truth for leading; components reference these, never
128
+ a hardcoded ratio. */
129
+ --lh-body: 1.75;
130
+ --lh-h1: 1.75;
131
+ --lh-h2: 1.78;
132
+ --lh-h3: 1.71;
133
+ --lh-h4: 1.82;
134
+ --lh-h5: 1.75;
135
+ --lh-h6: 1.71;
136
+ --lh-h7: 1.71;
137
+
138
+ /* Hairline width — single source of truth for every box border, divider
139
+ and rail. (Sub-pixel: crisp on hi-dpi; some 1x displays round it.) */
140
+ --border-width: 0.5px;
141
+
142
+ /* Icon stroke weight — single source of truth for every lucide icon. */
143
+ --icon-stroke: 1.5;
144
+
145
+ /* Icon size scale — em-relative so an icon next to text inherits the
146
+ text size automatically. `--icon-size` matches surrounding text;
147
+ `--icon-size-lg` is one modular step larger (for nav lists / trees
148
+ where the icon should slightly outweigh the label). */
149
+ --icon-size: 1em;
150
+ --icon-size-lg: calc(1em * var(--ratio));
151
+
152
+ /* Corner-radius scale, derived from --s0 (16px) — no raw literals.
153
+ sm 8 / md 16 / lg 32. Components pick the right step. */
154
+ --radius-sm: calc(var(--s0) / 2);
155
+ --radius-md: var(--s0);
156
+ --radius-lg: calc(var(--s0) * 2);
157
+
158
+ /* Font-weight scale — single source of truth so components never
159
+ write raw 300/400/500/600/700. Matches Google Sans Flex's
160
+ variable-font axis stops. */
161
+ --weight-light: 300;
162
+ --weight-normal: 400;
163
+ --weight-medium: 500;
164
+ --weight-semibold: 600;
165
+ --weight-bold: 700;
166
+ }
167
+
168
+ /* lucide-react adds class="lucide …" to every icon svg. This one rule
169
+ tokenizes stroke weight app-wide (CSS overrides the svg's stroke-width
170
+ attribute), so no component sets it per-icon. */
171
+ .lucide {
172
+ stroke-width: var(--icon-stroke);
173
+ }
174
+
175
+ /* Prose rhythm — wraps MDX content. MDX compiles to a flat list of
176
+ sibling block elements (h1, p, the velu-ui components, etc.).
177
+ Spacing is scaled by HEADING LEVEL so the document's structure is
178
+ readable at a glance:
179
+ - default sibling pair (paragraph rhythm): --s1
180
+ - before any heading (section break): scaled by level
181
+ - after a heading (heading → first child): one step under default
182
+ The rules use adjacent-sibling selectors so every same-level heading
183
+ gets the same lead-in regardless of what came before it (sibling
184
+ equality), and the larger before-heading gap reads as the section
185
+ break in every case. The owl rule sets the default; per-heading
186
+ rules below override it via source order (same specificity). */
187
+
188
+ /* Scroll-anchor offset for in-page links: when a TOC click lands on
189
+ a heading, the browser scrolls so the heading sits at the viewport
190
+ top — which would otherwise put it BEHIND the sticky chrome
191
+ (header + TocBar). `scroll-margin-block-start` tells the scroll
192
+ algorithm to leave that much space above the target.
193
+
194
+ --velu-scroll-offset is published by App.jsx as
195
+ `headerHeight + tocbarHeight + 1rem`, measured live via
196
+ ResizeObserver. The scroll-spy reads the SAME variable as its
197
+ trigger line, so scrollIntoView lands the heading exactly where
198
+ the spy promotes it — no magic numbers, no drift. */
199
+ .velu-hero h1,
200
+ .velu-prose :is(h1, h2, h3, h4, h5, h6) {
201
+ scroll-margin-block-start: var(--velu-scroll-offset, 5rem);
202
+ }
203
+
204
+ /* Default prose rhythm. */
205
+ .velu-prose > * + * {
206
+ margin-block-start: var(--s1);
207
+ }
208
+
209
+ /* Before-heading: progressively larger gap above higher-level headings.
210
+ Same level → same gap → siblings read at equal intervals. */
211
+ .velu-prose > * + h2 {
212
+ margin-block-start: var(--s4);
213
+ }
214
+ .velu-prose > * + h3 {
215
+ margin-block-start: var(--s3);
216
+ }
217
+ .velu-prose > * + h4 {
218
+ margin-block-start: var(--s2);
219
+ }
220
+
221
+ /* After-heading: tighter, so the heading reads as "introducing" what
222
+ follows rather than floating alone above a chasm. */
223
+ .velu-prose > h1 + *,
224
+ .velu-prose > h2 + *,
225
+ .velu-prose > h3 + *,
226
+ .velu-prose > h4 + *,
227
+ .velu-prose > h5 + *,
228
+ .velu-prose > h6 + * {
229
+ margin-block-start: var(--s0);
230
+ }
231
+
232
+ /* Page hero — the frontmatter (title + description) is wrapped in
233
+ `.velu-hero` so the title and description sit tight as a single
234
+ unit, and a larger break separates the hero from the prose body. */
235
+ .velu-hero > h1 + p {
236
+ margin-block-start: var(--s-2);
237
+ }
238
+ /* hero → body is an h1 → h2 transition (level-down, not peer-to-peer),
239
+ so the break is one modular step LARGER than the regular section
240
+ break above an h2 (--s4). Keeps the scale strictly monotonic:
241
+ level-down break > peer break. */
242
+ .velu-hero + .velu-prose {
243
+ margin-block-start: var(--s5);
244
+ }
245
+
246
+ /* Discreet thin scrollbar with a tokenised colour in every state — applied
247
+ GLOBALLY (the `*` selector) so every scrollable element inherits it by
248
+ default: the chatbot, dialogs, and any future component, with no
249
+ per-component opt-in. Component-specific scrollbar rules win via
250
+ specificity (e.g. the nav/TOC reveal-on-hover overrides below).
251
+ `.velu-hide-scrollbar` stays as an explicit alias for existing markup.
252
+
253
+ No transitions: Firefox doesn't honour CSS transitions on `scrollbar-color`
254
+ consistently, and the in-between interpolation + its auto-derived
255
+ hover/active colours can flash a yellow/amber accent (an OS / system accent
256
+ when interpolating). Hard switches avoid that. Same reason every WebKit
257
+ thumb pseudo-state is set explicitly — otherwise Chromium can fall back to
258
+ the Windows 11 system accent on hover. */
259
+ *,
260
+ .velu-hide-scrollbar {
261
+ scrollbar-width: thin;
262
+ /* Single colour both at rest and on hover. Firefox auto-darkens on
263
+ interaction, but starting from a defined light grey keeps the
264
+ derived shade in the same family (no yellow flash). */
265
+ scrollbar-color: var(--border-color) transparent;
266
+ }
267
+ *::-webkit-scrollbar,
268
+ .velu-hide-scrollbar::-webkit-scrollbar {
269
+ inline-size: 6px;
270
+ block-size: 6px;
271
+ }
272
+ *::-webkit-scrollbar-track,
273
+ .velu-hide-scrollbar::-webkit-scrollbar-track {
274
+ background: transparent;
275
+ }
276
+ *::-webkit-scrollbar-thumb,
277
+ .velu-hide-scrollbar::-webkit-scrollbar-thumb {
278
+ background: var(--border-color);
279
+ border-radius: 999px;
280
+ }
281
+ *::-webkit-scrollbar-thumb:hover,
282
+ *::-webkit-scrollbar-thumb:active,
283
+ .velu-hide-scrollbar::-webkit-scrollbar-thumb:hover,
284
+ .velu-hide-scrollbar::-webkit-scrollbar-thumb:active {
285
+ background: var(--muted-color);
286
+ }
287
+
288
+ /* Unitless line-height ratios (height ÷ font-size from Figma) */
289
+ body {
290
+ font-size: var(--f-body);
291
+ line-height: var(--lh-body);
292
+ font-weight: var(--weight-normal);
293
+ background: var(--page-bg);
294
+ color: var(--text-color);
295
+ }
296
+ h1 { font-size: var(--f-h1); line-height: var(--lh-h1); font-weight: var(--weight-semibold); }
297
+ h2 { font-size: var(--f-h2); line-height: var(--lh-h2); font-weight: var(--weight-medium); }
298
+ h3 { font-size: var(--f-h3); line-height: var(--lh-h3); font-weight: var(--weight-medium); }
299
+ h4 { font-size: var(--f-h4); line-height: var(--lh-h4); font-weight: var(--weight-normal); }
300
+ h5 { font-size: var(--f-h5); line-height: var(--lh-h5); font-weight: var(--weight-normal); }
301
+ h6 { font-size: var(--f-h6); line-height: var(--lh-h6); font-weight: var(--weight-normal); }
302
+
303
+ * {
304
+ max-width: var(--measure);
305
+ box-sizing: border-box;
306
+ }
307
+
308
+ html,
309
+ body,
310
+ div,
311
+ header,
312
+ nav,
313
+ main,
314
+ footer,
315
+ pre,
316
+ code,
317
+ span,
318
+ button {
319
+ max-width: none;
320
+ }