@caqophony/ui 0.3.0 → 0.4.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,711 @@
1
+ 'use client';
2
+ import {
3
+ IntentBadge
4
+ } from "./chunk-Y6LCXEXZ.js";
5
+ import {
6
+ Icon,
7
+ ScrollHintXMark
8
+ } from "./chunk-BAW3RIMF.js";
9
+ import {
10
+ cn
11
+ } from "./chunk-DP5WQAPO.js";
12
+
13
+ // src/material/tones.ts
14
+ var FILL = {
15
+ "night-0": "fill-night-0",
16
+ "night-1": "fill-night-1",
17
+ "night-2": "fill-night-2",
18
+ "sky-0": "fill-sky-0",
19
+ "sky-1": "fill-sky-1",
20
+ "sky-2": "fill-sky-2",
21
+ "sky-3": "fill-sky-3",
22
+ "sky-4": "fill-sky-4",
23
+ glow: "fill-glow",
24
+ "glow-soft": "fill-glow-soft",
25
+ "glow-pale": "fill-glow-pale",
26
+ canvas: "fill-canvas",
27
+ "mist-1": "fill-mist-1",
28
+ "mist-2": "fill-mist-2",
29
+ "mist-3": "fill-mist-3",
30
+ paper: "fill-paper",
31
+ ink: "fill-ink",
32
+ page: "fill-background"
33
+ };
34
+ var STROKE = {
35
+ "night-0": "stroke-night-0",
36
+ "night-1": "stroke-night-1",
37
+ "night-2": "stroke-night-2",
38
+ "sky-0": "stroke-sky-0",
39
+ "sky-1": "stroke-sky-1",
40
+ "sky-2": "stroke-sky-2",
41
+ "sky-3": "stroke-sky-3",
42
+ "sky-4": "stroke-sky-4",
43
+ glow: "stroke-glow",
44
+ "glow-soft": "stroke-glow-soft",
45
+ "glow-pale": "stroke-glow-pale",
46
+ canvas: "stroke-canvas",
47
+ "mist-1": "stroke-mist-1",
48
+ "mist-2": "stroke-mist-2",
49
+ "mist-3": "stroke-mist-3",
50
+ paper: "stroke-paper",
51
+ ink: "stroke-ink",
52
+ page: "stroke-background"
53
+ };
54
+ var BG = {
55
+ "night-0": "bg-night-0",
56
+ "night-1": "bg-night-1",
57
+ "night-2": "bg-night-2",
58
+ "sky-0": "bg-sky-0",
59
+ "sky-1": "bg-sky-1",
60
+ "sky-2": "bg-sky-2",
61
+ "sky-3": "bg-sky-3",
62
+ "sky-4": "bg-sky-4",
63
+ glow: "bg-glow",
64
+ "glow-soft": "bg-glow-soft",
65
+ "glow-pale": "bg-glow-pale",
66
+ canvas: "bg-canvas",
67
+ "mist-1": "bg-mist-1",
68
+ "mist-2": "bg-mist-2",
69
+ "mist-3": "bg-mist-3",
70
+ paper: "bg-paper",
71
+ ink: "bg-ink",
72
+ page: "bg-background"
73
+ };
74
+
75
+ // src/material/sky.tsx
76
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
77
+ function finite(piece, facts) {
78
+ for (const [name, value] of Object.entries(facts))
79
+ if (!Number.isFinite(value))
80
+ throw new Error(
81
+ `${piece}: \`${name}\` must be a finite number (got ${value})`
82
+ );
83
+ }
84
+ function aboveZero(piece, facts) {
85
+ for (const [name, value] of Object.entries(facts))
86
+ if (!Number.isFinite(value) || value <= 0)
87
+ throw new Error(
88
+ `${piece}: \`${name}\` must be a finite number above 0 (got ${value})`
89
+ );
90
+ }
91
+ function wholeWithin(piece, name, value, [low, high]) {
92
+ if (!Number.isInteger(value) || value < low || value > high)
93
+ throw new Error(
94
+ `${piece}: \`${name}\` must be a whole number from ${low} to ${high} (got ${value})`
95
+ );
96
+ }
97
+ var MIN_BUMP_RADIUS = 0.1;
98
+ var MAX_BUMPS = 2e3;
99
+ var MAX_SWELLS = 512;
100
+ var MAX_STARS = 5e3;
101
+ var ANCHOR = {
102
+ top: "xMidYMin slice",
103
+ center: "xMidYMid slice",
104
+ bottom: "xMidYMax slice",
105
+ right: "xMaxYMid slice"
106
+ };
107
+ function SkyField({
108
+ width,
109
+ height,
110
+ anchor,
111
+ only,
112
+ ground,
113
+ children
114
+ }) {
115
+ aboveZero("SkyField", { width, height });
116
+ return /* @__PURE__ */ jsxs(
117
+ "svg",
118
+ {
119
+ viewBox: `0 0 ${width} ${height}`,
120
+ preserveAspectRatio: ANCHOR[anchor],
121
+ "aria-hidden": "true",
122
+ className: cn(
123
+ "absolute inset-0 size-full",
124
+ only === "phone" && "md:hidden",
125
+ only === "desktop" && "hidden md:block"
126
+ ),
127
+ children: [
128
+ /* @__PURE__ */ jsx("rect", { width, height, className: FILL[ground] }),
129
+ children
130
+ ]
131
+ }
132
+ );
133
+ }
134
+ function Halo({ cx, cy, rings }) {
135
+ finite("Halo", { cx, cy });
136
+ rings.forEach((ring, i) => aboveZero("Halo", { [`rings[${i}].r`]: ring.r }));
137
+ return /* @__PURE__ */ jsx(Fragment, { children: rings.map((ring, i) => /* @__PURE__ */ jsx(
138
+ "circle",
139
+ {
140
+ cx,
141
+ cy,
142
+ r: ring.r,
143
+ className: FILL[ring.tone]
144
+ },
145
+ i
146
+ )) });
147
+ }
148
+ var RNG_MODULUS = 2147483647;
149
+ function rng(seed) {
150
+ let s = (Math.trunc(seed) % (RNG_MODULUS - 1) + RNG_MODULUS - 1) % (RNG_MODULUS - 1);
151
+ s += 1;
152
+ return () => {
153
+ s = s * 16807 % RNG_MODULUS;
154
+ return (s - 1) / (RNG_MODULUS - 1);
155
+ };
156
+ }
157
+ function CloudBank({
158
+ width,
159
+ height,
160
+ y,
161
+ min,
162
+ max,
163
+ climb = 0,
164
+ level = false,
165
+ seed,
166
+ tone
167
+ }) {
168
+ aboveZero("CloudBank", { width, height });
169
+ finite("CloudBank", { y, min, max, climb, seed });
170
+ if (min <= 0 || max < min)
171
+ throw new Error(
172
+ `CloudBank: the bump radius range must have min > 0 and max >= min (got min ${min}, max ${max}); a zero radius never reaches the field's edge`
173
+ );
174
+ if (min < MIN_BUMP_RADIUS)
175
+ throw new Error(
176
+ `CloudBank: \`min\` must be at least ${MIN_BUMP_RADIUS} (got ${min}); a smaller radius rounds to nothing in the path`
177
+ );
178
+ const bumps = Math.ceil((width + 2 * max) / (2 * min));
179
+ if (bumps > MAX_BUMPS)
180
+ throw new Error(
181
+ `CloudBank: ${width} wide at min ${min} and max ${max} can take ${bumps} bumps; a bank draws at most ${MAX_BUMPS} bumps`
182
+ );
183
+ const next = rng(seed);
184
+ let x = -max;
185
+ let drift = 0;
186
+ let d = `M${x} ${height}L${x} ${y}`;
187
+ while (x < width + max) {
188
+ const r = min + next() * (max - min);
189
+ const step = (next() - 0.5) * r * 0.5 - climb * r * 2 / width;
190
+ const lift = level ? step - drift : step;
191
+ drift += lift;
192
+ d += `a${r.toFixed(1)} ${r.toFixed(1)} 0 0 1 ${(r * 2).toFixed(1)} ${lift.toFixed(1)}`;
193
+ x += r * 2;
194
+ }
195
+ return /* @__PURE__ */ jsx("path", { d: `${d}L${x} ${height}Z`, className: FILL[tone] });
196
+ }
197
+ function Ridge({
198
+ width,
199
+ height,
200
+ y,
201
+ rise,
202
+ swells,
203
+ seed,
204
+ tone
205
+ }) {
206
+ aboveZero("Ridge", { width, height });
207
+ finite("Ridge", { y, rise, seed });
208
+ wholeWithin("Ridge", "swells", swells, [1, MAX_SWELLS]);
209
+ const next = rng(seed);
210
+ const step = width / swells;
211
+ let d = `M0 ${height}L0 ${y}`;
212
+ for (let i = 0; i < swells; i++) {
213
+ const cy = y - next() * rise;
214
+ d += `Q${(i + 0.5) * step} ${cy.toFixed(1)} ${(i + 1) * step} ${(y - next() * rise * 0.3).toFixed(1)}`;
215
+ }
216
+ return /* @__PURE__ */ jsx("path", { d: `${d}L${width} ${height}Z`, className: FILL[tone] });
217
+ }
218
+ function Stars({ width, height, count, seed, tone }) {
219
+ aboveZero("Stars", { width, height });
220
+ finite("Stars", { seed });
221
+ wholeWithin("Stars", "count", count, [0, MAX_STARS]);
222
+ const next = rng(seed);
223
+ return /* @__PURE__ */ jsx("g", { className: FILL[tone], children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx(
224
+ "circle",
225
+ {
226
+ cx: (next() * width).toFixed(1),
227
+ cy: (next() * height).toFixed(1),
228
+ r: (0.8 + next() * 1.4).toFixed(2)
229
+ },
230
+ i
231
+ )) });
232
+ }
233
+ function RouteLine({
234
+ points,
235
+ tone,
236
+ markTone,
237
+ labelSize
238
+ }) {
239
+ aboveZero("RouteLine", { labelSize });
240
+ points.forEach(
241
+ (p, i) => finite("RouteLine", { [`points[${i}].x`]: p.x, [`points[${i}].y`]: p.y })
242
+ );
243
+ const at = (i) => points[Math.max(0, Math.min(points.length - 1, i))];
244
+ let d = `M${points[0].x} ${points[0].y}`;
245
+ for (let i = 0; i < points.length - 1; i++) {
246
+ const [p0, p1, p2, p3] = [at(i - 1), at(i), at(i + 1), at(i + 2)];
247
+ d += `C${(p1.x + (p2.x - p0.x) / 6).toFixed(1)} ${(p1.y + (p2.y - p0.y) / 6).toFixed(1)} ${(p2.x - (p3.x - p1.x) / 6).toFixed(1)} ${(p2.y - (p3.y - p1.y) / 6).toFixed(1)} ${p2.x} ${p2.y}`;
248
+ }
249
+ const gap = labelSize * 1.1;
250
+ return /* @__PURE__ */ jsxs("g", { children: [
251
+ /* @__PURE__ */ jsx(
252
+ "path",
253
+ {
254
+ d,
255
+ fill: "none",
256
+ strokeWidth: labelSize * 0.16,
257
+ strokeDasharray: `${labelSize * 0.1} ${labelSize * 0.55}`,
258
+ strokeLinecap: "round",
259
+ className: STROKE[tone]
260
+ }
261
+ ),
262
+ points.map((p, i) => {
263
+ const side = p.side ?? "above";
264
+ const lx = side === "left" ? p.x - gap : side === "right" ? p.x + gap : p.x;
265
+ const ly = side === "above" ? p.y - gap : side === "below" ? p.y + gap * 1.5 : p.y + labelSize * 0.35;
266
+ const anchor = side === "left" ? "end" : side === "right" ? "start" : "middle";
267
+ return /* @__PURE__ */ jsxs("g", { children: [
268
+ p.state === "here" && /* @__PURE__ */ jsx(
269
+ "circle",
270
+ {
271
+ cx: p.x,
272
+ cy: p.y,
273
+ r: labelSize * 0.85,
274
+ className: cn(FILL[markTone], "opacity-30")
275
+ }
276
+ ),
277
+ /* @__PURE__ */ jsx(
278
+ "circle",
279
+ {
280
+ cx: p.x,
281
+ cy: p.y,
282
+ r: labelSize * 0.34,
283
+ strokeWidth: labelSize * 0.14,
284
+ className: cn(
285
+ STROKE[tone],
286
+ p.state === "ahead" ? FILL[markTone] : FILL[tone]
287
+ )
288
+ }
289
+ ),
290
+ p.label && /* @__PURE__ */ jsx(
291
+ "text",
292
+ {
293
+ x: lx,
294
+ y: ly,
295
+ textAnchor: anchor,
296
+ fontSize: labelSize,
297
+ fontWeight: 600,
298
+ className: FILL[tone],
299
+ children: p.label
300
+ }
301
+ )
302
+ ] }, i);
303
+ })
304
+ ] });
305
+ }
306
+
307
+ // src/material/band.tsx
308
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
309
+ var PAD = {
310
+ none: "",
311
+ tight: "pb-16 md:pb-24",
312
+ section: "py-20 md:py-28",
313
+ open: "py-24 md:py-40"
314
+ };
315
+ var EDGE_FIELD = { width: 3840, height: 240, seam: 120 };
316
+ function BandEdge({ via, tone, seed }) {
317
+ const { width, height, seam } = EDGE_FIELD;
318
+ const overlap = 8;
319
+ return /* @__PURE__ */ jsxs2(
320
+ "svg",
321
+ {
322
+ "aria-hidden": "true",
323
+ viewBox: `0 0 ${width} ${height}`,
324
+ preserveAspectRatio: "xMidYMid slice",
325
+ className: "pointer-events-none absolute inset-x-0 -top-16 h-32 w-full md:-top-[120px] md:h-[240px]",
326
+ children: [
327
+ via && /* @__PURE__ */ jsx2(
328
+ CloudBank,
329
+ {
330
+ width,
331
+ height: seam,
332
+ y: 82,
333
+ min: 24,
334
+ max: 56,
335
+ level: true,
336
+ seed: seed + 3,
337
+ tone: via
338
+ }
339
+ ),
340
+ /* @__PURE__ */ jsx2(
341
+ CloudBank,
342
+ {
343
+ width,
344
+ height: seam + overlap,
345
+ y: 100,
346
+ min: 22,
347
+ max: 58,
348
+ level: true,
349
+ seed,
350
+ tone
351
+ }
352
+ ),
353
+ /* @__PURE__ */ jsx2("g", { transform: `matrix(1 0 0 -1 0 ${height})`, children: /* @__PURE__ */ jsx2(
354
+ CloudBank,
355
+ {
356
+ width,
357
+ height: seam + overlap,
358
+ y: 72,
359
+ min: 22,
360
+ max: 58,
361
+ level: true,
362
+ seed: seed + 7,
363
+ tone
364
+ }
365
+ ) })
366
+ ]
367
+ }
368
+ );
369
+ }
370
+ function Band({
371
+ tone,
372
+ surface = "day",
373
+ pad = "section",
374
+ under = "none",
375
+ edge,
376
+ backdrop,
377
+ raised,
378
+ id,
379
+ children
380
+ }) {
381
+ return /* @__PURE__ */ jsxs2(
382
+ "section",
383
+ {
384
+ id,
385
+ "data-surface": surface,
386
+ className: cn(
387
+ "relative isolate scroll-mt-4",
388
+ BG[tone],
389
+ PAD[pad],
390
+ under === "overhang" && "pt-44 md:pt-[23rem]",
391
+ edge && "pt-28 md:pt-48",
392
+ raised && "z-10"
393
+ ),
394
+ children: [
395
+ backdrop && /* @__PURE__ */ jsx2(
396
+ "div",
397
+ {
398
+ "aria-hidden": "true",
399
+ className: "absolute inset-0 -z-10 overflow-hidden",
400
+ children: backdrop
401
+ }
402
+ ),
403
+ edge && /* @__PURE__ */ jsx2(BandEdge, { ...edge, tone }),
404
+ children
405
+ ]
406
+ }
407
+ );
408
+ }
409
+
410
+ // src/material/figure.tsx
411
+ import { jsx as jsx3 } from "react/jsx-runtime";
412
+ var ASPECT = {
413
+ "16:9": "aspect-video",
414
+ "8:5": "aspect-[8/5]",
415
+ "4:3": "aspect-[4/3]",
416
+ "3:2": "aspect-[3/2]",
417
+ "1:1": "aspect-square",
418
+ "4:5": "aspect-[4/5]",
419
+ "full-bleed": "h-full"
420
+ };
421
+ function recordable(spec) {
422
+ const blank = [
423
+ !spec.role.trim() && "`role`",
424
+ !spec.prompt.trim() && "`prompt`",
425
+ spec.palette.length === 0 && "`palette`"
426
+ ].filter(Boolean);
427
+ if (blank.length > 0)
428
+ throw new Error(
429
+ `Figure: ${blank.join(", ")} of the spec for "${spec.role}" must not be empty; the image step reads them`
430
+ );
431
+ }
432
+ function Figure({ spec, alt, children, fit = "aspect" }) {
433
+ recordable(spec);
434
+ return /* @__PURE__ */ jsx3(
435
+ "figure",
436
+ {
437
+ role: alt ? "img" : void 0,
438
+ "aria-label": alt || void 0,
439
+ "aria-hidden": alt ? void 0 : "true",
440
+ "data-figure-role": spec.role,
441
+ "data-figure-aspect": spec.aspect,
442
+ "data-figure-palette": spec.palette.join(" "),
443
+ "data-figure-prompt": spec.prompt,
444
+ className: cn(
445
+ "relative m-0 overflow-hidden [&>svg]:absolute [&>svg]:inset-0 [&>svg]:size-full",
446
+ fit === "fill" ? "h-full w-full" : ASPECT[spec.aspect]
447
+ ),
448
+ children
449
+ }
450
+ );
451
+ }
452
+
453
+ // src/material/layout.tsx
454
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
455
+ var GAP = {
456
+ 1: "gap-1",
457
+ 2: "gap-2",
458
+ 3: "gap-3",
459
+ 4: "gap-4",
460
+ 6: "gap-6",
461
+ 8: "gap-8",
462
+ 10: "gap-10",
463
+ 12: "gap-12",
464
+ 16: "gap-16"
465
+ };
466
+ function Stack({ gap, align = "stretch", children }) {
467
+ return /* @__PURE__ */ jsx4(
468
+ "div",
469
+ {
470
+ className: cn(
471
+ "flex min-w-0 flex-col",
472
+ GAP[gap],
473
+ align === "center" && "items-center",
474
+ align === "start" && "items-start"
475
+ ),
476
+ children
477
+ }
478
+ );
479
+ }
480
+ function Inline({
481
+ gap,
482
+ justify = "start",
483
+ align = "center",
484
+ fillOnPhone,
485
+ children
486
+ }) {
487
+ return /* @__PURE__ */ jsx4(
488
+ "div",
489
+ {
490
+ className: cn(
491
+ "flex min-w-0 flex-wrap",
492
+ GAP[gap],
493
+ align === "center" ? "items-center" : "items-start",
494
+ justify === "between" && "justify-between",
495
+ justify === "center" && "justify-center",
496
+ fillOnPhone && "max-sm:w-full max-sm:flex-col max-sm:items-stretch max-sm:[&>*]:w-full"
497
+ ),
498
+ children
499
+ }
500
+ );
501
+ }
502
+ var COUNT = {
503
+ 2: "md:grid-cols-2",
504
+ 3: "md:grid-cols-3",
505
+ 4: "md:grid-cols-4"
506
+ };
507
+ var CONNECT = "md:[&>*]:relative md:[&>*:not(:last-child,:has(+[data-scroll-hint]))]:after:absolute md:[&>*:not(:last-child,:has(+[data-scroll-hint]))]:after:left-[calc(50%+2.5rem)] md:[&>*:not(:last-child,:has(+[data-scroll-hint]))]:after:top-6 md:[&>*:not(:last-child,:has(+[data-scroll-hint]))]:after:h-0 md:[&>*:not(:last-child,:has(+[data-scroll-hint]))]:after:w-[calc(100%-3rem)] md:[&>*:not(:last-child,:has(+[data-scroll-hint]))]:after:border-t-2 md:[&>*:not(:last-child,:has(+[data-scroll-hint]))]:after:border-dashed md:[&>*:not(:last-child,:has(+[data-scroll-hint]))]:after:border-mist-3 md:[&>*:not(:last-child,:has(+[data-scroll-hint]))]:after:content-['']";
508
+ function Columns({
509
+ count,
510
+ gap,
511
+ phone,
512
+ connect,
513
+ children
514
+ }) {
515
+ return /* @__PURE__ */ jsxs3(
516
+ "div",
517
+ {
518
+ className: cn(
519
+ GAP[gap],
520
+ connect && CONNECT,
521
+ phone === "stack" ? cn("grid grid-cols-1", COUNT[count]) : cn(
522
+ "flex overflow-x-auto md:grid md:overflow-visible md:[&>[data-scroll-hint]]:hidden",
523
+ "[&>:not([data-scroll-hint])]:w-64 [&>:not([data-scroll-hint])]:shrink-0 md:[&>:not([data-scroll-hint])]:w-auto",
524
+ COUNT[count]
525
+ )
526
+ ),
527
+ children: [
528
+ children,
529
+ phone === "scroll" && /* @__PURE__ */ jsx4(ScrollHintXMark, {})
530
+ ]
531
+ }
532
+ );
533
+ }
534
+ function Split({ ratio, reverse, gap, children }) {
535
+ return /* @__PURE__ */ jsxs3(
536
+ "div",
537
+ {
538
+ className: cn(
539
+ "grid grid-cols-1 items-center",
540
+ GAP[gap],
541
+ ratio === "even" ? "md:grid-cols-2" : "md:grid-cols-[5fr_7fr]",
542
+ reverse && (ratio === "even" ? "md:[&>:first-child]:order-2" : "md:grid-cols-[7fr_5fr] md:[&>:first-child]:order-2")
543
+ ),
544
+ children: [
545
+ /* @__PURE__ */ jsx4("div", { className: "min-w-0", children: children[0] }),
546
+ /* @__PURE__ */ jsx4("div", { className: "min-w-0", children: children[1] })
547
+ ]
548
+ }
549
+ );
550
+ }
551
+ var SPACER = {
552
+ hero: "h-10 md:h-14",
553
+ section: "h-16 md:h-24",
554
+ "phone-sky": "h-40 md:hidden"
555
+ };
556
+ function Spacer({ size }) {
557
+ return /* @__PURE__ */ jsx4("div", { "aria-hidden": "true", className: SPACER[size] });
558
+ }
559
+ var INSET = { 3: "p-3", 4: "p-4", 6: "p-6" };
560
+ function Inset({ pad, children }) {
561
+ return /* @__PURE__ */ jsx4("div", { className: INSET[pad], children });
562
+ }
563
+
564
+ // src/material/type.tsx
565
+ import { jsx as jsx5 } from "react/jsx-runtime";
566
+ var LEVEL = {
567
+ poster: "text-display-poster",
568
+ headline: "text-display-headline",
569
+ title: "text-display-title"
570
+ };
571
+ var MEASURE = {
572
+ narrow: "max-w-[14ch]",
573
+ wide: "max-w-[22ch]",
574
+ none: ""
575
+ };
576
+ function Display({
577
+ level,
578
+ as: Tag,
579
+ align = "start",
580
+ measure = "none",
581
+ children
582
+ }) {
583
+ return /* @__PURE__ */ jsx5(
584
+ Tag,
585
+ {
586
+ className: cn(
587
+ "text-foreground",
588
+ LEVEL[level],
589
+ MEASURE[measure],
590
+ align === "center" && "mx-auto text-center"
591
+ ),
592
+ children
593
+ }
594
+ );
595
+ }
596
+ var SIZE = {
597
+ lede: "text-lede",
598
+ body: "text-base leading-relaxed",
599
+ small: "text-sm leading-snug",
600
+ micro: "text-xs leading-snug"
601
+ };
602
+ var TONE = {
603
+ default: "text-foreground",
604
+ muted: "text-muted-foreground",
605
+ accent: "text-primary-text"
606
+ };
607
+ var WEIGHT = {
608
+ normal: "font-normal",
609
+ medium: "font-medium",
610
+ bold: "font-semibold"
611
+ };
612
+ function Text({
613
+ size = "body",
614
+ tone = "default",
615
+ weight = "normal",
616
+ align = "start",
617
+ measure,
618
+ as: Tag = "p",
619
+ children
620
+ }) {
621
+ return /* @__PURE__ */ jsx5(
622
+ Tag,
623
+ {
624
+ className: cn(
625
+ SIZE[size],
626
+ TONE[tone],
627
+ WEIGHT[weight],
628
+ align === "center" && "mx-auto text-center",
629
+ measure && "max-w-[58ch]"
630
+ ),
631
+ children
632
+ }
633
+ );
634
+ }
635
+
636
+ // src/material/vignette.tsx
637
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
638
+ function Vignette({
639
+ title,
640
+ icon,
641
+ sampleLabel,
642
+ surface = "day",
643
+ placement = "inline",
644
+ crop = "none",
645
+ children
646
+ }) {
647
+ return /* @__PURE__ */ jsxs4(
648
+ "div",
649
+ {
650
+ "data-surface": surface,
651
+ className: cn(
652
+ "relative overflow-hidden rounded-2xl border border-border bg-background shadow-[0_2px_4px_-2px_hsl(var(--night-1)),0_30px_70px_-30px_hsl(var(--night-1))]",
653
+ placement === "hang" && "z-10 -mb-32 md:-mb-52"
654
+ ),
655
+ children: [
656
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 border-b border-border bg-card px-4 py-2.5", children: [
657
+ /* @__PURE__ */ jsx6("span", { className: "text-muted-foreground", children: /* @__PURE__ */ jsx6(Icon, { name: icon, size: "sm" }) }),
658
+ /* @__PURE__ */ jsx6("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-foreground", children: title }),
659
+ /* @__PURE__ */ jsx6(IntentBadge, { intent: "neutral", children: sampleLabel })
660
+ ] }),
661
+ /* @__PURE__ */ jsx6(
662
+ "div",
663
+ {
664
+ className: cn(
665
+ "bg-muted/50 p-3 md:p-4",
666
+ // a mask reads alpha only, so any opaque token draws the same crop
667
+ crop === "bottom" && "relative max-h-[24rem] overflow-hidden [mask-image:linear-gradient(to_bottom,hsl(var(--foreground))_70%,transparent)]"
668
+ ),
669
+ children
670
+ }
671
+ )
672
+ ]
673
+ }
674
+ );
675
+ }
676
+
677
+ // src/material/wordmark.tsx
678
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
679
+ function Wordmark({ name, mark, href }) {
680
+ return /* @__PURE__ */ jsxs5(
681
+ "a",
682
+ {
683
+ href,
684
+ className: "flex items-center gap-2 text-lg font-bold tracking-tight text-foreground [font-family:var(--font-heading,inherit)]",
685
+ children: [
686
+ /* @__PURE__ */ jsx7("span", { className: "text-primary-text size-6 shrink-0", children: mark }),
687
+ name
688
+ ]
689
+ }
690
+ );
691
+ }
692
+ export {
693
+ Band,
694
+ CloudBank,
695
+ Columns,
696
+ Display,
697
+ Figure,
698
+ Halo,
699
+ Inline,
700
+ Inset,
701
+ Ridge,
702
+ RouteLine,
703
+ SkyField,
704
+ Spacer,
705
+ Split,
706
+ Stack,
707
+ Stars,
708
+ Text,
709
+ Vignette,
710
+ Wordmark
711
+ };