mevebu 1.0.0 → 1.2.0

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.
@@ -0,0 +1,1172 @@
1
+ /* mevebu styles, authored in Tailwind CSS v4.
2
+
3
+ Owner decision, recorded in AGENTS.md section 3: the repo writes its styles with
4
+ Tailwind and builds one stylesheet that ships inside mevebu/. Nothing loads from a
5
+ CDN, so the app stays offline and makes no third-party request.
6
+
7
+ Source of truth: this file.
8
+ Built output: mevebu/app/tailwind.css (committed, never edit by hand)
9
+ Rebuild: npm run css
10
+
11
+ Component classes keep the mvb- prefix and the exact names the tools already pass,
12
+ so no tool file has to know how the design system is implemented. Every token lives
13
+ in the :root blocks below, so no rule hardcodes a colour. Raw Tailwind utilities are
14
+ welcome for one-off layout inside a single tool.
15
+
16
+ The five things this file is opinionated about:
17
+ 1. One place for actions. A tool's buttons sit on a card edge, never floating mid column.
18
+ 2. One spacing rhythm. 4px base, 16px inside a group, 24px between groups.
19
+ 3. Phone first. Two columns arrive at 60rem, never before.
20
+ 4. Dark mode is a real theme, not the light theme inverted.
21
+ 5. You type into a raised surface and read results on a recessed one. */
22
+
23
+ @import "tailwindcss" source(none);
24
+
25
+ @source "./index.html";
26
+ @source "./app";
27
+ @source "./libs/js";
28
+
29
+ /* The app switches theme with <html data-theme>, so dark: follows that attribute. */
30
+ @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
31
+
32
+ /* ---------- tokens ---------- */
33
+
34
+ :root {
35
+ --mvb-void: #eef1f7;
36
+ --mvb-deck: #ffffff;
37
+ --mvb-deck-2: #f1f4fa;
38
+ --mvb-ink: #151d2e;
39
+ --mvb-ink-2: #4b5871;
40
+ --mvb-ink-3: #69748c;
41
+ --mvb-orbit: #dfe4ef;
42
+ --mvb-orbit-hard: #c2cbdf;
43
+ --mvb-comet: #2456d6;
44
+ --mvb-comet-deep: #1a43ad;
45
+ --mvb-on-comet: #ffffff;
46
+ --mvb-nebula: #e3ebfd;
47
+ --mvb-aurora: #0d7a56;
48
+ --mvb-danger: #b3261e;
49
+ --mvb-star: #e6a100;
50
+ --mvb-track: #c2cbdf;
51
+ --mvb-scrim: rgb(6 10 24 / 0.5);
52
+
53
+ --mvb-r1: 10px;
54
+ --mvb-r2: 16px;
55
+ --mvb-r3: 24px;
56
+
57
+ --mvb-margin: clamp(20px, 5vw, 44px);
58
+ --mvb-gutter: clamp(14px, 2vw, 24px);
59
+ --mvb-bench: 1120px;
60
+ --mvb-bar: 60px;
61
+
62
+ --mvb-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
63
+ --mvb-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
64
+
65
+ --mvb-ease: cubic-bezier(0.22, 0.9, 0.28, 1);
66
+ --mvb-t: 150ms;
67
+
68
+ /* native controls and the select caret follow the theme through these */
69
+ --mvb-caret: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2369748c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
70
+ color-scheme: light;
71
+ }
72
+
73
+ :root[data-theme="dark"] {
74
+ --mvb-void: #05080f;
75
+ --mvb-deck: #0e1526;
76
+ --mvb-deck-2: #16203a;
77
+ --mvb-ink: #e9eefb;
78
+ --mvb-ink-2: #aeb9d2;
79
+ --mvb-ink-3: #8b97b3;
80
+ --mvb-orbit: #24324f;
81
+ --mvb-orbit-hard: #35476f;
82
+ --mvb-comet: #5f8bff;
83
+ --mvb-comet-deep: #7ba1ff;
84
+ --mvb-on-comet: #060b18;
85
+ --mvb-nebula: #131e3c;
86
+ --mvb-aurora: #4ad69c;
87
+ --mvb-danger: #ff8a80;
88
+ --mvb-star: #ffcf4d;
89
+ --mvb-track: #35476f;
90
+ --mvb-scrim: rgb(2 4 10 / 0.68);
91
+ --mvb-caret: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b97b3' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
92
+ color-scheme: dark;
93
+ }
94
+
95
+ /* The tokens above become Tailwind utilities: bg-deck, text-ink-2, border-orbit,
96
+ rounded-r2, ring-nebula. `inline` keeps them as var() references, so every utility
97
+ follows the theme switch without a second class. */
98
+ @theme inline {
99
+ --color-void: var(--mvb-void);
100
+ --color-deck: var(--mvb-deck);
101
+ --color-deck-2: var(--mvb-deck-2);
102
+ --color-ink: var(--mvb-ink);
103
+ --color-ink-2: var(--mvb-ink-2);
104
+ --color-ink-3: var(--mvb-ink-3);
105
+ --color-orbit: var(--mvb-orbit);
106
+ --color-orbit-hard: var(--mvb-orbit-hard);
107
+ --color-comet: var(--mvb-comet);
108
+ --color-comet-deep: var(--mvb-comet-deep);
109
+ --color-on-comet: var(--mvb-on-comet);
110
+ --color-nebula: var(--mvb-nebula);
111
+ --color-aurora: var(--mvb-aurora);
112
+ --color-danger: var(--mvb-danger);
113
+ --color-star: var(--mvb-star);
114
+
115
+ --radius-r1: var(--mvb-r1);
116
+ --radius-r2: var(--mvb-r2);
117
+ --radius-r3: var(--mvb-r3);
118
+
119
+ --font-sans: var(--mvb-sans);
120
+ --font-mono: var(--mvb-mono);
121
+ }
122
+
123
+ /* ---------- base ---------- */
124
+
125
+ @layer base {
126
+ html {
127
+ -webkit-text-size-adjust: 100%;
128
+ }
129
+
130
+ body {
131
+ margin: 0;
132
+ min-height: 100dvh;
133
+ display: flex;
134
+ flex-direction: column;
135
+ background: var(--mvb-void);
136
+ color: var(--mvb-ink);
137
+ font-family: var(--mvb-sans);
138
+ font-size: 16px;
139
+ line-height: 1.55;
140
+ -webkit-font-smoothing: antialiased;
141
+ }
142
+
143
+ h1, h2, h3, h4, h5, h6, p, ul, ol, pre, figure { margin: 0; }
144
+ ul, ol { list-style: none; padding: 0; }
145
+ button, input, textarea, select { font: inherit; color: inherit; }
146
+ a { color: inherit; }
147
+ img, svg, canvas, video { display: block; max-width: 100%; }
148
+
149
+ /* The card head and foot are rendered with a hidden attribute rather than removed,
150
+ and their own display rule would otherwise win over the browser default. */
151
+ [hidden] { display: none !important; }
152
+
153
+ :focus-visible {
154
+ outline: 2px solid var(--mvb-comet);
155
+ outline-offset: 2px;
156
+ border-radius: 6px;
157
+ }
158
+
159
+ ::selection { background: var(--mvb-nebula); }
160
+
161
+ @media (prefers-reduced-motion: reduce) {
162
+ *, *::before, *::after {
163
+ animation-duration: 0.01ms !important;
164
+ animation-iteration-count: 1 !important;
165
+ transition-duration: 0.01ms !important;
166
+ }
167
+ }
168
+ }
169
+
170
+ @layer components {
171
+ /* ---------- icons ---------- */
172
+
173
+ .mvb-ico { @apply block size-[18px] flex-none; }
174
+ .mvb-ico--lg { @apply size-[26px]; }
175
+ .mvb-ico--sm { @apply size-[15px]; }
176
+
177
+ /* ---------- masthead ---------- */
178
+
179
+ .mvb-bar {
180
+ @apply sticky top-0 z-30 border-b border-orbit;
181
+ background: color-mix(in srgb, var(--mvb-deck) 88%, transparent);
182
+ backdrop-filter: saturate(140%) blur(10px);
183
+ -webkit-backdrop-filter: saturate(140%) blur(10px);
184
+ }
185
+
186
+ .mvb-bar__in {
187
+ height: var(--mvb-bar);
188
+ margin-inline: var(--mvb-margin);
189
+ @apply flex items-center gap-[clamp(14px,3vw,32px)];
190
+ }
191
+
192
+ .mvb-mark {
193
+ @apply inline-flex flex-none items-center gap-2.5 text-lg font-bold tracking-[-0.01em] text-ink no-underline;
194
+ }
195
+
196
+ .mvb-mark img {
197
+ @apply block size-[30px] rounded-[9px];
198
+ box-shadow: 0 0 0 1px var(--mvb-orbit);
199
+ }
200
+
201
+ .mvb-nav {
202
+ @apply ms-auto flex flex-none gap-1 rounded-r2 border border-orbit bg-deck-2 p-1;
203
+ }
204
+
205
+ .mvb-nav__link {
206
+ @apply whitespace-nowrap rounded-lg px-3 py-[7px] text-[0.90625rem] font-semibold text-ink-2 no-underline transition-colors duration-150;
207
+ }
208
+
209
+ .mvb-nav__link:hover {
210
+ @apply bg-ink/6 text-ink;
211
+ }
212
+
213
+ .mvb-nav__link.mvb-on {
214
+ @apply bg-deck text-ink;
215
+ box-shadow: 0 0 0 1px var(--mvb-orbit);
216
+ }
217
+
218
+ .mvb-bar__end { @apply flex items-center gap-0.5; }
219
+
220
+ .mvb-icobtn {
221
+ @apply inline-flex size-10 cursor-pointer items-center justify-center rounded-r1 border border-transparent bg-transparent text-ink-2 transition-colors duration-150;
222
+ }
223
+
224
+ .mvb-icobtn:hover { @apply bg-deck-2 text-ink; }
225
+ .mvb-icobtn:focus-visible { @apply border-comet; }
226
+
227
+ .mvb-bar__menu { @apply hidden; }
228
+
229
+ /* search button that opens the palette */
230
+
231
+ .mvb-searchbtn {
232
+ @apply me-1 inline-flex h-10 min-w-[180px] cursor-pointer items-center gap-2 rounded-r1 border border-orbit bg-deck-2 ps-3 pe-2.5 text-sm font-medium text-ink-2 transition-colors duration-150;
233
+ }
234
+
235
+ .mvb-searchbtn:hover { @apply border-orbit-hard bg-deck text-ink; }
236
+ .mvb-searchbtn:focus-visible { @apply border-comet; }
237
+ .mvb-searchbtn .mvb-ico { @apply size-[15px] text-ink-3; }
238
+
239
+ .mvb-searchbtn__txt { @apply flex-1 text-start text-sm; }
240
+
241
+ /* nav sheet on a phone */
242
+
243
+ .mvb-sheet {
244
+ @apply grid border-t border-orbit bg-deck px-[var(--mvb-margin)] pt-1.5 pb-3.5;
245
+ }
246
+
247
+ .mvb-sheet__nav { @apply grid; }
248
+
249
+ .mvb-sheet__link {
250
+ @apply flex items-center gap-2 border-b border-orbit bg-transparent py-[13px] text-start text-[1.0625rem] font-medium text-ink no-underline;
251
+ }
252
+
253
+ .mvb-sheet__link:last-child { @apply border-b-0; }
254
+ .mvb-sheet__link .mvb-ico { @apply text-ink-3; }
255
+ .mvb-sheet__action { @apply text-comet; }
256
+
257
+ /* ---------- frame ---------- */
258
+
259
+ .mvb-main { @apply flex-1 outline-none; }
260
+
261
+ .mvb-page { @apply px-[var(--mvb-margin)]; }
262
+
263
+ .mvb-page--tool,
264
+ .mvb-page--narrow {
265
+ max-width: var(--mvb-bench);
266
+ @apply mx-auto;
267
+ }
268
+
269
+ .mvb-link { @apply text-comet underline-offset-[3px]; }
270
+
271
+ /* One key chip for the whole app: the search button, the filter, the palette
272
+ footer and the help modal all point at the same key. It sits on a raised and a
273
+ recessed surface in turn, so it carries its own border instead of a fill. */
274
+ .mvb-kbd {
275
+ @apply rounded-[5px] border border-orbit-hard px-[7px] py-px font-sans text-[0.8125rem] leading-[1.45] text-ink-3;
276
+ }
277
+
278
+ /* hero, only on the home page */
279
+
280
+ .mvb-hero {
281
+ @apply relative border-b border-orbit;
282
+ overflow: clip;
283
+ background:
284
+ radial-gradient(560px 300px at 12% -40px, var(--mvb-nebula), transparent 70%),
285
+ var(--mvb-deck);
286
+ }
287
+
288
+ .mvb-hero__in {
289
+ max-width: var(--mvb-bench);
290
+ @apply mx-auto grid items-center gap-[clamp(24px,5vw,72px)] px-[var(--mvb-margin)] pt-[clamp(48px,8vw,104px)] pb-[clamp(40px,6vw,80px)];
291
+ grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr);
292
+ }
293
+
294
+ .mvb-hero__title {
295
+ @apply text-balance text-[clamp(34px,6vw,60px)] font-bold leading-[1.02] tracking-[-0.03em];
296
+ }
297
+
298
+ .mvb-hero__cta { @apply mt-6 flex flex-wrap gap-2.5; }
299
+
300
+ .mvb-hero__orbit { @apply w-[min(300px,70vw)] justify-self-center; }
301
+ .mvb-hero__orbit img { @apply block h-auto w-full rounded-r3; }
302
+
303
+ /* index sections */
304
+
305
+ .mvb-section { @apply pt-[clamp(32px,5vw,60px)]; }
306
+
307
+ .mvb-section__head { @apply mb-4 flex items-baseline gap-3; }
308
+
309
+ .mvb-section__title {
310
+ @apply flex items-center gap-2.5 text-[clamp(21px,3vw,27px)] font-bold tracking-[-0.02em];
311
+ }
312
+
313
+ .mvb-section__title .mvb-ico { @apply size-[22px] text-comet; }
314
+
315
+ .mvb-section__count {
316
+ @apply ms-1.5 rounded-full bg-deck-2 px-2 py-px text-[0.8125rem] font-semibold tabular-nums text-ink-3;
317
+ }
318
+
319
+ .mvb-section__more {
320
+ @apply ms-auto whitespace-nowrap text-[0.90625rem] font-semibold text-comet no-underline;
321
+ }
322
+
323
+ .mvb-section__more:hover { @apply underline; }
324
+
325
+ /* ---------- column system ----------
326
+ Every grid climbs through three states, so a tablet gets a layout of its own
327
+ instead of a stretched stack or four crammed columns. */
328
+
329
+ .mvb-cols { @apply grid gap-[var(--mvb-gutter)]; }
330
+ .mvb-cols--2 { @apply grid-cols-1 sm:grid-cols-2; }
331
+ .mvb-cols--3 { @apply grid-cols-1 sm:grid-cols-2 lg:grid-cols-3; }
332
+ .mvb-cols--4 { @apply grid-cols-1 sm:grid-cols-2 lg:grid-cols-4; }
333
+ .mvb-cols--auto { grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); }
334
+ .mvb-cols--side { @apply grid-cols-1 min-[60rem]:grid-cols-[minmax(0,20rem)_minmax(0,1fr)]; }
335
+
336
+ .mvb-row { @apply flex min-w-0 flex-wrap items-center gap-2; }
337
+ .mvb-col { @apply min-w-0; }
338
+ .mvb-col--grow { @apply flex-1; }
339
+ .mvb-col--shrink { @apply flex-none; }
340
+
341
+ .mvb-grid { @apply grid grid-cols-1 gap-[var(--mvb-gutter)] sm:grid-cols-2 lg:grid-cols-3; }
342
+
343
+ .mvb-card {
344
+ @apply relative grid gap-1.5 rounded-r2 border border-orbit bg-deck p-5 no-underline transition-colors duration-150;
345
+ }
346
+
347
+ .mvb-card:hover { @apply border-comet; }
348
+
349
+ .mvb-card__top { @apply flex items-center gap-3; }
350
+
351
+ .mvb-card__sigil {
352
+ @apply grid size-[42px] flex-none place-items-center rounded-[13px] bg-nebula text-comet;
353
+ }
354
+
355
+ .mvb-card__sigil .mvb-ico { @apply size-[21px]; }
356
+
357
+ .mvb-card__name { @apply text-[1.0625rem] font-semibold tracking-[-0.01em]; }
358
+
359
+ .mvb-card__note { @apply min-h-11 text-pretty text-[0.90625rem] text-ink-2; }
360
+
361
+ .mvb-card__foot {
362
+ @apply mt-1.5 flex items-center gap-2 text-[0.84375rem] font-semibold text-ink-3;
363
+ }
364
+
365
+ /* ---------- tool list (category and favorites pages) ---------- */
366
+
367
+ .mvb-list {
368
+ @apply grid overflow-clip rounded-r2 border border-orbit bg-deck;
369
+ }
370
+
371
+ .mvb-listrow {
372
+ @apply flex items-center border-b border-orbit;
373
+ }
374
+
375
+ .mvb-listrow:last-child { @apply border-b-0; }
376
+
377
+ .mvb-listrow__link {
378
+ @apply grid min-w-0 flex-1 gap-px py-[13px] pe-1.5 ps-[18px] no-underline;
379
+ }
380
+
381
+ .mvb-listrow__link:hover .mvb-listrow__name { @apply text-comet; }
382
+
383
+ .mvb-listrow__name { @apply text-[1.03125rem] font-semibold tracking-[-0.01em]; }
384
+ .mvb-listrow__note { @apply text-sm text-ink-2; }
385
+
386
+ .mvb-star {
387
+ @apply me-2 inline-flex size-11 flex-none cursor-pointer items-center justify-center rounded-r1 border-0 bg-transparent text-orbit-hard transition-[color,transform] duration-150;
388
+ }
389
+
390
+ .mvb-star:hover { @apply text-ink-2; }
391
+ .mvb-star.mvb-on { @apply text-star; }
392
+ .mvb-star.mvb-on .mvb-ico { fill: var(--mvb-star); }
393
+ .mvb-star:active { @apply scale-[0.88]; }
394
+
395
+ /* ---------- filter ---------- */
396
+
397
+ .mvb-filter {
398
+ @apply mt-[clamp(22px,4vw,36px)] flex items-center gap-2.5 rounded-r2 border border-orbit bg-deck px-3.5 transition-colors duration-150;
399
+ }
400
+
401
+ .mvb-filter:focus-within { @apply border-comet; }
402
+
403
+ .mvb-filter__icon { @apply flex text-ink-3; }
404
+
405
+ .mvb-filter__in {
406
+ @apply min-w-0 flex-1 border-0 bg-transparent text-[1.0625rem];
407
+ height: 52px;
408
+ }
409
+
410
+ .mvb-filter__in:focus { @apply outline-none; }
411
+ .mvb-filter__in::placeholder { @apply text-ink-3; }
412
+
413
+ .mvb-filter__meta {
414
+ @apply mt-2.5 flex min-h-[22px] items-baseline gap-3.5 text-sm text-ink-3;
415
+ }
416
+
417
+ /* ---------- page headings ---------- */
418
+
419
+ .mvb-lead {
420
+ @apply mt-[clamp(28px,5vw,56px)] max-w-[20ch] text-balance text-[clamp(28px,5vw,44px)] font-bold leading-[1.06] tracking-[-0.025em];
421
+ }
422
+
423
+ .mvb-lede { @apply mt-3 max-w-[60ch] text-pretty text-[1.0625rem] text-ink-2; }
424
+
425
+ /* ---------- tool page ---------- */
426
+
427
+ .mvb-head { @apply my-[clamp(24px,4vw,44px)] mb-[clamp(22px,3vw,32px)]; }
428
+
429
+ .mvb-head__back {
430
+ @apply mb-4 inline-flex items-center gap-[7px] text-[0.9375rem] font-medium text-ink-2 no-underline;
431
+ }
432
+
433
+ .mvb-head__back:hover { @apply text-ink; }
434
+
435
+ .mvb-head__row { @apply flex items-start gap-2; }
436
+
437
+ .mvb-head__title {
438
+ @apply flex-1 text-balance text-[clamp(26px,4vw,36px)] font-bold leading-[1.1] tracking-[-0.025em];
439
+ }
440
+
441
+ .mvb-head__actions { @apply flex items-center gap-0.5 pt-1; }
442
+
443
+ .mvb-head__about { @apply mt-2 max-w-[58ch] text-pretty text-[1.0625rem] text-ink-2; }
444
+
445
+ .mvb-helpbtn {
446
+ @apply inline-flex size-[38px] cursor-pointer items-center justify-center rounded-full border border-orbit bg-deck-2 font-sans text-base font-bold text-ink-2 transition-colors duration-150;
447
+ }
448
+
449
+ .mvb-helpbtn:hover { @apply border-orbit-hard bg-deck text-ink; }
450
+ .mvb-helpbtn:focus-visible { @apply border-comet; }
451
+
452
+ .mvb-more { @apply mt-[clamp(40px,6vw,72px)]; }
453
+ .mvb-more__title { @apply mb-2.5 text-[0.9375rem] font-bold text-ink-3; }
454
+
455
+ /* ---------- tool card ----------
456
+ Head and foot are the only places a tool may put an action row, so the buttons
457
+ always land on a card edge. The body is the working surface. */
458
+
459
+ .mvb-toolcard {
460
+ @apply flex flex-col overflow-clip rounded-r2 border border-orbit bg-deck;
461
+ }
462
+
463
+ .mvb-toolcard__head {
464
+ @apply flex flex-wrap items-center gap-2 border-b border-orbit bg-deck-2 px-[clamp(20px,3vw,32px)] py-[clamp(12px,2vw,16px)];
465
+ }
466
+
467
+ .mvb-toolcard__body {
468
+ @apply flex-1 p-[clamp(20px,3vw,32px)];
469
+ }
470
+
471
+ .mvb-toolcard__foot {
472
+ @apply flex flex-wrap items-center justify-end gap-2 border-t border-orbit bg-deck-2 px-[clamp(20px,3vw,32px)] py-[clamp(12px,2vw,16px)];
473
+ }
474
+
475
+ /* ---------- bench ----------
476
+ One column until there is real room for two, so the phone reads top to bottom
477
+ and a tablet is not a stretched stack. */
478
+
479
+ .mvb-bench { @apply grid items-start gap-5; }
480
+
481
+ .mvb-bench__side,
482
+ .mvb-bench__main { @apply min-w-0; }
483
+
484
+ @media (min-width: 60rem) {
485
+ .mvb-bench {
486
+ @apply gap-6;
487
+ grid-template-columns: minmax(0, 21rem) minmax(0, 1fr);
488
+ }
489
+ }
490
+
491
+ .mvb-stage {
492
+ @apply mx-auto grid max-w-[560px] justify-items-center gap-4 text-center;
493
+ }
494
+
495
+ .mvb-stack { @apply grid content-start gap-4; }
496
+
497
+ /* ---------- field ---------- */
498
+
499
+ .mvb-field { @apply grid min-w-0 content-start gap-1.5; }
500
+ .mvb-field__label { @apply text-[0.875rem] font-semibold text-ink-2; }
501
+ .mvb-field__hint { @apply text-[0.8125rem] text-ink-3; }
502
+
503
+ .mvb-field--error .mvb-in,
504
+ .mvb-field--error .mvb-pick {
505
+ border-color: var(--mvb-danger);
506
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--mvb-danger) 14%, transparent);
507
+ }
508
+
509
+ .mvb-field--error .mvb-field__hint { @apply text-danger; }
510
+
511
+ .mvb-field--good .mvb-in,
512
+ .mvb-field--good .mvb-pick {
513
+ border-color: var(--mvb-aurora);
514
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--mvb-aurora) 14%, transparent);
515
+ }
516
+
517
+ .mvb-field--good .mvb-field__hint { @apply text-aurora; }
518
+
519
+ /* ---------- inputs ----------
520
+ You type into a raised surface. Results live in .mvb-out on a recessed one. */
521
+
522
+ .mvb-in {
523
+ @apply w-full min-w-0 rounded-r1 border border-orbit bg-deck px-3 py-2.5 text-ink transition-[border-color,box-shadow] duration-150;
524
+ }
525
+
526
+ .mvb-in:hover { @apply border-orbit-hard; }
527
+ .mvb-in:focus { @apply border-comet outline-none ring-3 ring-nebula; }
528
+ .mvb-in::placeholder { @apply text-ink-3; }
529
+
530
+ .mvb-in[disabled],
531
+ .mvb-in[readonly] { @apply cursor-default bg-deck-2 text-ink-3; }
532
+
533
+ .mvb-in[disabled] { @apply cursor-not-allowed opacity-70; }
534
+
535
+ .mvb-in--area {
536
+ @apply min-h-24 resize-y py-2.5 font-mono text-[0.875rem] leading-normal;
537
+ }
538
+
539
+ .mvb-in--num { width: 96px; }
540
+ .mvb-in--mono { @apply font-mono text-[0.875rem]; }
541
+
542
+ .mvb-in--select {
543
+ @apply cursor-pointer py-2.5 pe-9;
544
+ appearance: none;
545
+ -webkit-appearance: none;
546
+ background-image: var(--mvb-caret);
547
+ background-repeat: no-repeat;
548
+ background-position: right 12px center;
549
+ background-size: 14px;
550
+ }
551
+
552
+ .mvb-in--file { @apply p-1.5; }
553
+
554
+ .mvb-in--file::file-selector-button {
555
+ @apply me-2.5 cursor-pointer rounded-r1 border border-orbit-hard bg-deck-2 px-2.5 py-1 text-[0.8125rem] font-semibold text-ink;
556
+ }
557
+
558
+ .mvb-check {
559
+ @apply inline-flex cursor-pointer items-center gap-2 rounded-r1 border border-orbit bg-deck py-2 ps-2.5 pe-3 text-[0.9375rem] transition-[border-color,background-color] duration-150;
560
+ }
561
+
562
+ .mvb-check:has(.mvb-check__box:checked) { @apply border-comet bg-nebula; }
563
+
564
+ .mvb-check__box {
565
+ @apply m-0 size-4;
566
+ accent-color: var(--mvb-comet);
567
+ }
568
+
569
+ /* switch */
570
+
571
+ .mvb-switch {
572
+ @apply inline-flex cursor-pointer select-none items-center gap-2.5 text-[0.9375rem];
573
+ }
574
+
575
+ .mvb-switch__box { @apply pointer-events-none absolute opacity-0; }
576
+
577
+ .mvb-switch__track {
578
+ @apply relative h-[22px] w-[38px] rounded-full transition-colors duration-150;
579
+ background: var(--mvb-track);
580
+ }
581
+
582
+ .mvb-switch__thumb {
583
+ @apply absolute top-0.5 left-0.5 size-[18px] rounded-full bg-deck transition-transform duration-150;
584
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.18);
585
+ }
586
+
587
+ .mvb-switch__box:checked + .mvb-switch__track { background: var(--mvb-comet); }
588
+ .mvb-switch__box:checked + .mvb-switch__track .mvb-switch__thumb { @apply translate-x-4; }
589
+ .mvb-switch__box:focus-visible + .mvb-switch__track { box-shadow: 0 0 0 3px var(--mvb-nebula); }
590
+
591
+ .mvb-range {
592
+ @apply w-full;
593
+ accent-color: var(--mvb-comet);
594
+ }
595
+
596
+ .mvb-pick {
597
+ @apply h-10 w-[52px] flex-none cursor-pointer rounded-r1 border border-orbit bg-deck p-0.5;
598
+ }
599
+
600
+ .mvb-pick:hover { @apply border-orbit-hard; }
601
+ .mvb-pick:focus { @apply border-comet outline-none ring-3 ring-nebula; }
602
+
603
+ /* chips */
604
+
605
+ .mvb-chips { @apply flex flex-wrap gap-1.5; }
606
+
607
+ .mvb-chip {
608
+ @apply min-h-[38px] cursor-pointer rounded-r1 border border-orbit bg-deck px-[13px] text-sm font-medium text-ink-2 transition-colors duration-150;
609
+ }
610
+
611
+ .mvb-chip:hover { @apply border-orbit-hard text-ink; }
612
+ .mvb-chip.mvb-on { @apply border-comet bg-nebula text-ink; }
613
+
614
+ /* ---------- actions ----------
615
+ One row, one alignment, one gap. Third position is not an option: a tool's
616
+ actions belong on a card edge. */
617
+
618
+ .mvb-actions { @apply flex flex-wrap items-center justify-end gap-2; }
619
+
620
+ .mvb-toolcard__head .mvb-actions,
621
+ .mvb-toolcard__foot .mvb-actions { @apply w-full; }
622
+
623
+ /* An action row that ends a column keeps a small top gap; a card edge owns its own
624
+ padding instead. */
625
+ .mvb-stack > .mvb-actions { @apply mt-1; }
626
+
627
+ /* buttons */
628
+
629
+ .mvb-btn {
630
+ @apply inline-flex min-h-10 cursor-pointer items-center justify-center gap-[7px] rounded-r1 border border-transparent px-4 text-[0.9375rem] font-semibold no-underline transition-[background-color,border-color,color,transform] duration-150;
631
+ }
632
+
633
+ .mvb-btn:active { @apply scale-[0.97]; }
634
+
635
+ .mvb-btn--fill { @apply border-comet bg-comet text-on-comet; }
636
+ .mvb-btn--fill:hover { @apply border-comet-deep bg-comet-deep; }
637
+
638
+ .mvb-btn--plain { @apply border-orbit bg-deck text-ink; }
639
+ .mvb-btn--plain:hover { @apply border-orbit-hard; }
640
+
641
+ .mvb-btn--quiet { @apply bg-transparent px-2 text-ink-2; }
642
+ .mvb-btn--quiet:hover { @apply bg-deck-2 text-ink; }
643
+
644
+ .mvb-btn:disabled { @apply cursor-not-allowed opacity-45; }
645
+
646
+ /* readouts: the recessed half of the pair, so a result never reads as an input */
647
+
648
+ .mvb-out {
649
+ @apply m-0 max-h-[340px] w-full overflow-auto rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3 font-mono text-[0.875rem] leading-normal;
650
+ white-space: pre-wrap;
651
+ overflow-wrap: anywhere;
652
+ }
653
+
654
+ textarea.mvb-out { @apply resize-y; }
655
+
656
+ /* An empty readout is a waiting slot, not data. Dashed already means "nothing yet"
657
+ in this system (.mvb-blank, .mvb-drop), so an empty one says the same thing
658
+ instead of reading as a mysterious grey bar. Only <pre> can be matched safely:
659
+ a textarea holds its text in a property, so :empty would lie about it. */
660
+ pre.mvb-out:empty { @apply border-dashed bg-transparent; }
661
+
662
+ /* notices. A state is never colour alone: the rule marks it as well. */
663
+
664
+ .mvb-note { @apply border-s-[3px] border-transparent ps-2 text-sm text-ink-3; }
665
+
666
+ .mvb-note--error {
667
+ @apply border-s-danger text-danger;
668
+ }
669
+
670
+ .mvb-note--good {
671
+ @apply border-s-aurora text-aurora;
672
+ }
673
+
674
+ .mvb-blank {
675
+ @apply grid justify-items-center gap-2.5 rounded-r2 border border-dashed border-orbit-hard bg-deck-2 px-4 py-[clamp(28px,6vw,56px)] text-center text-ink-3;
676
+ }
677
+
678
+ .mvb-blank p { @apply max-w-[34ch]; }
679
+
680
+ .mvb-code {
681
+ @apply overflow-x-auto whitespace-pre-wrap rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3 font-mono text-[0.875rem];
682
+ }
683
+
684
+ :not(pre) > code {
685
+ @apply rounded-[4px] bg-deck-2 px-[5px] py-px font-mono text-[0.92em];
686
+ }
687
+
688
+ /* about blocks */
689
+
690
+ .mvb-about {
691
+ @apply mt-8 grid max-w-[62ch] gap-2.5 border-t border-orbit pt-6;
692
+ }
693
+
694
+ .mvb-about__title { @apply text-lg font-bold tracking-[-0.01em]; }
695
+ .mvb-about p { @apply text-pretty text-ink-2; }
696
+
697
+ /* ---------- modal ---------- */
698
+
699
+ .mvb-veil {
700
+ @apply fixed inset-0 z-80 grid items-start justify-items-center px-5 pt-[clamp(60px,10vh,120px)] pb-5;
701
+ background: var(--mvb-scrim);
702
+ opacity: 0;
703
+ transition: opacity 180ms ease;
704
+ }
705
+
706
+ .mvb-veil.mvb-open { opacity: 1; }
707
+ .mvb-veil.mvb-off { opacity: 0; }
708
+
709
+ .mvb-modal {
710
+ @apply w-[min(440px,100%)] rounded-r3 border border-orbit bg-deck p-7 text-center;
711
+ transform: translateY(14px) scale(0.96);
712
+ transition: transform 220ms var(--mvb-ease);
713
+ }
714
+
715
+ .mvb-veil.mvb-open .mvb-modal { transform: none; }
716
+ .mvb-veil.mvb-off .mvb-modal { transform: translateY(10px) scale(0.97); }
717
+
718
+ .mvb-modal__art img { @apply mx-auto block size-[88px] rounded-[22px]; }
719
+
720
+ .mvb-modal__title { @apply mt-3.5 text-[1.375rem] font-bold tracking-[-0.02em]; }
721
+ .mvb-modal__body p { @apply mt-2 text-pretty text-[0.96875rem] text-ink-2; }
722
+ .mvb-modal__actions { @apply mt-5 grid gap-2; }
723
+
724
+ /* version readout inside the update modal */
725
+ .mvb-vers { @apply mt-[18px] overflow-hidden rounded-r2 border border-orbit; }
726
+ .mvb-vers__row { @apply flex items-center justify-between gap-3 px-4 py-3; }
727
+ .mvb-vers__row + .mvb-vers__row { @apply border-t border-orbit; }
728
+ .mvb-vers__label { @apply text-sm text-ink-3; }
729
+ .mvb-vers__val { @apply font-mono text-[0.9375rem] font-semibold; }
730
+ .mvb-vers__row--new .mvb-vers__val { @apply text-comet; }
731
+ .mvb-vers__hint { @apply mt-3.5 text-sm; }
732
+
733
+ .mvb-cmd {
734
+ @apply mt-2.5 flex flex-wrap items-center gap-2 rounded-r2 border border-orbit bg-deck-2 py-2.5 pe-2.5 ps-4;
735
+ }
736
+
737
+ .mvb-cmd__text {
738
+ @apply min-w-0 flex-1 wrap-anywhere font-mono text-sm;
739
+ }
740
+
741
+ /* ---------- command palette ---------- */
742
+
743
+ .mvb-veil--pal { @apply pt-[clamp(60px,12vh,140px)]; }
744
+
745
+ .mvb-veil--pal .mvb-modal {
746
+ @apply w-[min(640px,100%)] overflow-hidden p-0 text-start;
747
+ }
748
+
749
+ .mvb-pal__head {
750
+ @apply flex items-center gap-3 border-b border-orbit px-[18px] py-4;
751
+ }
752
+
753
+ .mvb-pal__icon { @apply text-ink-3; }
754
+
755
+ .mvb-pal__in {
756
+ @apply h-10 min-w-0 flex-1 border-0 bg-transparent text-[1.0625rem];
757
+ }
758
+
759
+ .mvb-pal__in:focus { @apply outline-none; }
760
+ .mvb-pal__in::placeholder { @apply text-ink-3; }
761
+
762
+ .mvb-pal__count { @apply m-0 px-[18px] pt-2 text-[0.8125rem] text-ink-3; }
763
+
764
+ .mvb-pal__list {
765
+ @apply m-0 mt-1.5 max-h-[min(60vh,360px)] overflow-y-auto px-2 pb-2;
766
+ }
767
+
768
+ .mvb-pal__item {
769
+ @apply flex w-full cursor-pointer items-center gap-3 rounded-r1 border-0 bg-transparent px-3 py-2.5 text-start text-ink transition-colors duration-150;
770
+ }
771
+
772
+ .mvb-pal__item.mvb-on { @apply bg-nebula; }
773
+ .mvb-pal__item.mvb-on .mvb-pal__name { @apply text-comet; }
774
+
775
+ .mvb-pal__sigil {
776
+ @apply grid size-8 flex-none place-items-center rounded-lg bg-deck-2 text-comet;
777
+ }
778
+
779
+ .mvb-pal__sigil .mvb-ico { @apply size-4; }
780
+ .mvb-pal__text { @apply grid min-w-0 flex-1 gap-px; }
781
+ .mvb-pal__name { @apply text-[0.9375rem] font-semibold tracking-[-0.01em]; }
782
+ .mvb-pal__note { @apply overflow-hidden text-[0.84375rem] text-ellipsis whitespace-nowrap text-ink-2; }
783
+ .mvb-pal__cat { @apply whitespace-nowrap text-[0.8125rem] text-ink-3; }
784
+
785
+ .mvb-pal__empty { @apply p-[18px] text-sm text-ink-3; }
786
+
787
+ .mvb-pal__foot {
788
+ @apply m-0 flex flex-wrap items-center gap-2.5 border-t border-orbit px-[18px] py-2.5 text-[0.8125rem] text-ink-3;
789
+ }
790
+
791
+ /* ---------- help modal ---------- */
792
+
793
+ .mvb-veil--help { @apply pt-[clamp(60px,10vh,120px)]; }
794
+
795
+ .mvb-veil--help .mvb-modal {
796
+ @apply w-[min(560px,100%)] overflow-hidden p-7 text-start;
797
+ }
798
+
799
+ .mvb-help__head { @apply mb-3 flex items-center gap-3.5; }
800
+
801
+ .mvb-help__sigil {
802
+ @apply grid size-11 place-items-center rounded-xl bg-nebula text-comet;
803
+ }
804
+
805
+ .mvb-help__sigil .mvb-ico { @apply size-[22px]; }
806
+
807
+ .mvb-help__title { @apply text-xl font-bold tracking-[-0.02em]; }
808
+ .mvb-help__note { @apply mb-3.5 text-pretty text-[0.96875rem] leading-normal text-ink-2; }
809
+
810
+ .mvb-help__steps {
811
+ @apply m-0 grid list-none gap-2.5 p-0;
812
+ counter-reset: mvb-step;
813
+ }
814
+
815
+ .mvb-help__steps li {
816
+ @apply grid grid-cols-[22px_1fr] items-start gap-2 text-[0.90625rem] leading-normal text-ink;
817
+ }
818
+
819
+ .mvb-help__steps li::before {
820
+ content: counter(mvb-step);
821
+ counter-increment: mvb-step;
822
+ @apply grid size-[22px] place-items-center rounded-full bg-nebula text-[0.8125rem] font-bold tabular-nums text-comet;
823
+ }
824
+
825
+ /* ---------- footer ---------- */
826
+
827
+ .mvb-foot {
828
+ @apply mt-[clamp(56px,8vw,96px)] border-t border-orbit bg-deck-2;
829
+ }
830
+
831
+ .mvb-foot__in {
832
+ max-width: var(--mvb-bench);
833
+ @apply mx-auto px-[var(--mvb-margin)] pt-[clamp(36px,5vw,56px)] pb-[clamp(24px,3vw,36px)];
834
+ }
835
+
836
+ .mvb-foot__top {
837
+ @apply grid items-start gap-[clamp(20px,4vw,56px)] min-[60rem]:grid-cols-[minmax(0,1.4fr)_minmax(0,1fr)];
838
+ }
839
+
840
+ .mvb-foot__brand { @apply grid gap-2.5; }
841
+
842
+ .mvb-foot__mark {
843
+ @apply inline-flex items-center gap-2.5 text-[1.375rem] font-bold tracking-[-0.02em] text-ink no-underline;
844
+ }
845
+
846
+ .mvb-foot__mark img {
847
+ @apply size-[34px] rounded-[10px];
848
+ box-shadow: 0 0 0 1px var(--mvb-orbit);
849
+ }
850
+
851
+ .mvb-foot__tag { @apply max-w-[38ch] text-pretty text-sm text-ink-2; }
852
+
853
+ .mvb-foot__nav {
854
+ @apply grid grid-cols-2 gap-x-[clamp(20px,4vw,40px)] gap-y-1.5;
855
+ }
856
+
857
+ .mvb-foot__nav h4 { @apply m-0 mb-2 text-[0.8125rem] font-bold tracking-normal text-ink-3 normal-case; }
858
+ .mvb-foot__nav ul { @apply grid gap-1.5; }
859
+ .mvb-foot__nav a { @apply text-[0.90625rem] text-ink-2 no-underline; }
860
+ .mvb-foot__nav a:hover { @apply text-comet; }
861
+
862
+ .mvb-foot__bottom {
863
+ @apply mt-[clamp(24px,4vw,36px)] flex flex-wrap items-center gap-x-[clamp(14px,3vw,28px)] gap-y-1.5 border-t border-orbit pt-[18px];
864
+ }
865
+
866
+ .mvb-foot__legal { @apply flex items-center gap-[7px] text-[0.84375rem] text-ink-3; }
867
+ .mvb-foot__count { @apply tabular-nums; }
868
+ .mvb-foot__count:empty { @apply hidden; }
869
+
870
+ /* version chip in the footer; turns into an update button when npm has a newer one */
871
+ .mvb-version {
872
+ @apply inline-flex min-h-7 cursor-pointer items-center gap-1.5 rounded-full border border-orbit bg-transparent px-2.5 py-[3px] font-sans text-[0.8125rem] tabular-nums text-ink-3 transition-colors duration-150;
873
+ }
874
+
875
+ .mvb-version:hover { @apply border-orbit-hard text-ink; }
876
+ .mvb-version:focus-visible { @apply outline-2 outline-comet outline-offset-2; }
877
+
878
+ .mvb-version--new {
879
+ @apply border-comet bg-nebula font-semibold text-comet;
880
+ }
881
+
882
+ .mvb-version--new:hover { @apply bg-comet text-on-comet; }
883
+
884
+ .mvb-version .mvb-ico { @apply size-[15px]; }
885
+
886
+ /* ---------- toast ---------- */
887
+
888
+ .mvb-toast {
889
+ @apply pointer-events-none fixed bottom-6 left-1/2 z-90 rounded-r1 bg-ink px-4 py-2.5 text-sm font-semibold text-void;
890
+ transform: translate(-50%, 12px);
891
+ opacity: 0;
892
+ transition: opacity 150ms ease, transform 150ms ease;
893
+ }
894
+
895
+ .mvb-toast.mvb-on { opacity: 1; transform: translate(-50%, 0); }
896
+
897
+ /* ==========================================================================
898
+ Objects a tool renders itself
899
+ ========================================================================== */
900
+
901
+ /* ---------- wheel ---------- */
902
+
903
+ .mvb-wheel { @apply h-auto w-[min(320px,100%)]; }
904
+
905
+ .mvb-wheel__status {
906
+ @apply text-balance text-xl font-bold tracking-[-0.01em];
907
+ }
908
+
909
+ .mvb-wheel__history {
910
+ @apply flex max-w-[340px] flex-wrap justify-center gap-1.5;
911
+ }
912
+
913
+ .mvb-wheel__chip {
914
+ @apply rounded-full border border-orbit bg-deck-2 px-2.5 py-1 text-[0.8125rem] font-semibold;
915
+ }
916
+
917
+ /* ---------- coin ---------- */
918
+
919
+ .mvb-coin {
920
+ @apply grid size-32 select-none place-items-center rounded-full bg-comet text-[44px] font-bold text-on-comet;
921
+ }
922
+
923
+ .mvb-coin.mvb-toss { animation: mvb-toss 450ms ease; }
924
+
925
+ @keyframes mvb-toss {
926
+ 0% { transform: scale(1) rotate(0deg); }
927
+ 50% { transform: scale(1.12) rotate(180deg); }
928
+ 100% { transform: scale(1) rotate(360deg); }
929
+ }
930
+
931
+ .mvb-flip__result { @apply text-[1.1875rem] font-bold tracking-[-0.01em]; }
932
+
933
+ /* ---------- meter ---------- */
934
+
935
+ .mvb-meter { @apply h-2 overflow-hidden rounded-full bg-deck-2; }
936
+
937
+ .mvb-meter__fill {
938
+ @apply h-full w-0 rounded-full transition-[width,background-color] duration-150;
939
+ background: var(--mvb-orbit-hard);
940
+ }
941
+
942
+ .mvb-meter__fill.mvb-weak { background: var(--mvb-danger); }
943
+ .mvb-meter__fill.mvb-ok { background: var(--mvb-comet); }
944
+ .mvb-meter__fill.mvb-strong { background: var(--mvb-aurora); }
945
+
946
+ /* ---------- swatch and picker ---------- */
947
+
948
+ .mvb-swatch {
949
+ @apply h-14 rounded-r1 border border-orbit-hard bg-deck-2;
950
+ }
951
+
952
+ /* ---------- case list ---------- */
953
+
954
+ .mvb-cases { @apply grid gap-1; }
955
+
956
+ .mvb-case {
957
+ @apply flex w-full cursor-pointer items-baseline justify-between gap-3 rounded-r1 border border-transparent bg-transparent px-3 py-[9px] text-start transition-colors duration-150;
958
+ }
959
+
960
+ .mvb-case:hover { @apply bg-deck-2; }
961
+ .mvb-case.mvb-on { @apply border-comet bg-nebula; }
962
+
963
+ .mvb-case__name { @apply flex-none text-[0.8125rem] font-semibold text-ink-2; }
964
+ .mvb-case.mvb-on .mvb-case__name { @apply text-ink; }
965
+ .mvb-case__value { @apply wrap-anywhere text-end font-mono text-sm; }
966
+
967
+ /* ---------- dropzone and camera ---------- */
968
+
969
+ .mvb-drop {
970
+ @apply grid cursor-pointer justify-items-center gap-2 rounded-r2 border border-dashed border-orbit-hard px-4 py-7 text-[0.9375rem] text-ink-3 transition-colors duration-150;
971
+ }
972
+
973
+ .mvb-drop:hover,
974
+ .mvb-drop.mvb-drag { @apply border-comet bg-nebula; }
975
+
976
+ .mvb-qrview {
977
+ @apply w-[min(420px,100%)] rounded-r2 border border-orbit-hard bg-black;
978
+ }
979
+
980
+ .mvb-qrcode {
981
+ @apply h-auto w-[min(300px,100%)];
982
+ image-rendering: pixelated;
983
+ }
984
+
985
+ /* ---------- tables ---------- */
986
+
987
+ .mvb-scroll { @apply max-h-80 overflow-auto; }
988
+
989
+ .mvb-ttable {
990
+ @apply w-full border-collapse font-mono text-sm;
991
+ }
992
+
993
+ .mvb-ttable th,
994
+ .mvb-ttable td { @apply wrap-anywhere border-b border-orbit px-2.5 py-2 text-start; }
995
+
996
+ .mvb-ttable th { @apply font-sans text-[0.8125rem] font-semibold text-ink-2; }
997
+
998
+ .mvb-ttable tbody tr:last-child th,
999
+ .mvb-ttable tbody tr:last-child td { @apply border-b-0; }
1000
+
1001
+ /* ---------- secrets ---------- */
1002
+
1003
+ .mvb-secret { @apply grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2; }
1004
+
1005
+ /* ---------- stat tiles ---------- */
1006
+
1007
+ .mvb-stats {
1008
+ @apply grid gap-2.5;
1009
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
1010
+ }
1011
+
1012
+ .mvb-stat {
1013
+ @apply grid gap-0.5 rounded-r1 border border-orbit bg-deck-2 px-3.5 py-3;
1014
+ }
1015
+
1016
+ .mvb-stat__v { @apply wrap-anywhere text-[1.375rem] font-bold tracking-[-0.02em] tabular-nums; }
1017
+ .mvb-stat__k { @apply text-[0.8125rem] font-semibold text-ink-3; }
1018
+
1019
+ /* ---------- diff view ---------- */
1020
+
1021
+ .mvb-diff {
1022
+ @apply grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit;
1023
+ }
1024
+
1025
+ .mvb-diff__row {
1026
+ @apply grid bg-deck font-mono text-[0.84375rem];
1027
+ grid-template-columns: 34px minmax(0, 1fr);
1028
+ }
1029
+
1030
+ .mvb-diff__row > span { @apply wrap-anywhere px-2.5 py-[3px] whitespace-pre-wrap; }
1031
+
1032
+ .mvb-diff__sign {
1033
+ @apply border-e border-orbit text-center text-ink-3 select-none;
1034
+ }
1035
+
1036
+ .mvb-diff__row--add { background: color-mix(in srgb, var(--mvb-aurora) 14%, var(--mvb-deck)); }
1037
+ .mvb-diff__row--del { background: color-mix(in srgb, var(--mvb-danger) 12%, var(--mvb-deck)); }
1038
+ .mvb-diff__row--add .mvb-diff__sign { @apply text-aurora; }
1039
+ .mvb-diff__row--del .mvb-diff__sign { @apply text-danger; }
1040
+
1041
+ /* ---------- key/value list ---------- */
1042
+
1043
+ .mvb-kv {
1044
+ @apply grid gap-px overflow-hidden rounded-r1 border border-orbit bg-orbit;
1045
+ }
1046
+
1047
+ .mvb-kv__row {
1048
+ @apply grid gap-3 bg-deck px-3 py-[9px];
1049
+ grid-template-columns: minmax(90px, 34%) minmax(0, 1fr);
1050
+ }
1051
+
1052
+ .mvb-kv__k { @apply wrap-anywhere text-[0.84375rem] font-semibold text-ink-2; }
1053
+ .mvb-kv__v { @apply wrap-anywhere font-mono text-[0.84375rem]; }
1054
+
1055
+ /* ---------- preview pane and highlights ---------- */
1056
+
1057
+ .mvb-pane {
1058
+ @apply min-h-[120px] max-h-[380px] overflow-auto wrap-anywhere rounded-r1 border border-orbit bg-deck-2 px-4 py-3.5 leading-normal;
1059
+ }
1060
+
1061
+ .mvb-pane > :first-child { @apply mt-0; }
1062
+ .mvb-pane > :last-child { @apply mb-0; }
1063
+ .mvb-pane h1, .mvb-pane h2, .mvb-pane h3 { @apply my-4 tracking-[-0.01em]; }
1064
+ .mvb-pane p, .mvb-pane ul, .mvb-pane ol, .mvb-pane pre { @apply mb-2.5; }
1065
+ .mvb-pane ul, .mvb-pane ol { @apply ps-[22px]; }
1066
+ .mvb-pane code { @apply rounded-[5px] bg-deck px-[5px] py-px font-mono text-[0.8125rem]; }
1067
+ .mvb-pane pre { @apply overflow-auto rounded-r1 bg-deck px-3 py-2.5; }
1068
+ .mvb-pane pre code { @apply bg-transparent p-0; }
1069
+ .mvb-pane a { @apply text-comet; }
1070
+ .mvb-pane table { @apply border-collapse; }
1071
+ .mvb-pane th, .mvb-pane td { @apply border border-orbit px-[9px] py-1.5; }
1072
+
1073
+ .mvb-hl { background: color-mix(in srgb, var(--mvb-star) 40%, transparent); @apply rounded-[3px]; }
1074
+ .mvb-hl--on { @apply rounded-[3px] bg-comet text-on-comet; }
1075
+
1076
+ /* ---------- design previews ---------- */
1077
+
1078
+ .mvb-swatches {
1079
+ @apply grid gap-2;
1080
+ grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
1081
+ }
1082
+
1083
+ .mvb-swatchcard {
1084
+ @apply grid cursor-pointer gap-1.5 rounded-r1 border border-orbit bg-deck p-2 text-start transition-colors duration-150;
1085
+ }
1086
+
1087
+ .mvb-swatchcard:hover { @apply border-comet; }
1088
+ .mvb-swatchcard__chip { @apply h-[52px] rounded-lg border border-orbit-hard; }
1089
+ .mvb-swatchcard__code { @apply font-mono text-[0.8125rem] text-ink-2; }
1090
+
1091
+ .mvb-preview {
1092
+ @apply grid min-h-40 place-items-center overflow-hidden rounded-r1 border border-orbit bg-deck-2 p-[22px];
1093
+ }
1094
+
1095
+ .mvb-preview__box {
1096
+ @apply grid h-[120px] w-[min(200px,100%)] place-items-center bg-comet text-[0.8125rem] text-on-comet;
1097
+ }
1098
+
1099
+ .mvb-preview__sample {
1100
+ @apply w-full rounded-lg border border-orbit bg-deck px-[18px] py-4;
1101
+ }
1102
+
1103
+ .mvb-slider {
1104
+ @apply grid items-center gap-2.5;
1105
+ grid-template-columns: 88px minmax(0, 1fr) 62px;
1106
+ }
1107
+
1108
+ .mvb-slider__label { @apply text-[0.84375rem] font-semibold text-ink-2; }
1109
+ .mvb-slider__val { @apply text-end font-mono text-[0.8125rem] text-ink-2; }
1110
+
1111
+ /* ---------- narrow states ----------
1112
+ A phone is its own layout, not a narrowed desktop: one column, calmer gaps,
1113
+ full-width actions, and 16px inputs so the browser keyboard does not zoom. */
1114
+
1115
+ @media (max-width: 60rem) {
1116
+ .mvb-toolcard__head,
1117
+ .mvb-toolcard__foot { @apply px-[18px]; }
1118
+ .mvb-toolcard__body { @apply p-[18px]; }
1119
+
1120
+ /* The header is the tightest row in the app: mark, four links, the search pill
1121
+ and two buttons. Drop the search pill first, because the sheet still offers
1122
+ Search and the tools page has its own filter. Only below 45rem, when the
1123
+ links no longer fit either, do they move into the sheet. */
1124
+ .mvb-searchbtn { @apply hidden; }
1125
+ }
1126
+
1127
+ @media (max-width: 45rem) {
1128
+ .mvb-nav { @apply hidden; }
1129
+ .mvb-bar__menu { @apply inline-flex; }
1130
+ .mvb-bar__end { @apply ms-auto; }
1131
+
1132
+ .mvb-hero__in { grid-template-columns: minmax(0, 1fr); }
1133
+ .mvb-hero__orbit { @apply hidden; }
1134
+
1135
+ .mvb-card { @apply p-4; }
1136
+ .mvb-card__note { @apply min-h-0; }
1137
+
1138
+ .mvb-filter__in { height: 48px; }
1139
+
1140
+ .mvb-stage { @apply justify-items-stretch text-start; }
1141
+
1142
+ .mvb-btn { @apply min-h-11; }
1143
+ .mvb-chip { @apply min-h-11; }
1144
+
1145
+ /* The action row keeps the same right alignment as every wider width. Stretching
1146
+ every button to fill the bar instead would wrap a longer label such as
1147
+ "Copy Base64" onto two lines and make the footer taller than the buttons need. */
1148
+ .mvb-toolcard__foot .mvb-actions,
1149
+ .mvb-toolcard__head .mvb-actions { @apply gap-2; }
1150
+
1151
+ .mvb-slider { grid-template-columns: minmax(0, 1fr) 62px; }
1152
+ .mvb-slider__label { @apply col-span-2; }
1153
+
1154
+ /* 16px on every field and readout: below that the browser zooms the page when a
1155
+ field takes focus, and a table cell or a panel can otherwise shrink a control
1156
+ below its own scale. Inline text stays where it is; this is about controls. */
1157
+ .mvb-in,
1158
+ .mvb-out,
1159
+ .mvb-filter__in,
1160
+ select { @apply text-base; }
1161
+
1162
+ /* A colour swatch and a bare icon button are still tap targets. */
1163
+ .mvb-pick { @apply h-11; }
1164
+ .mvb-icobtn { @apply size-11; }
1165
+
1166
+ /* And so are a slider, a checkbox chip and a switch: on a phone they are the
1167
+ control, not a decoration beside a larger one. */
1168
+ .mvb-range { @apply min-h-11; }
1169
+ .mvb-check { @apply min-h-11; }
1170
+ .mvb-switch { @apply min-h-11; }
1171
+ }
1172
+ }