lmbchp 0.1.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.
package/dist/index.js ADDED
@@ -0,0 +1,2106 @@
1
+ "use client";
2
+
3
+ // src/lib/cn.ts
4
+ import { clsx } from "clsx";
5
+ import { twMerge } from "tailwind-merge";
6
+ function cn(...inputs) {
7
+ return twMerge(clsx(inputs));
8
+ }
9
+
10
+ // src/lib/use-chart-colors.ts
11
+ import * as React from "react";
12
+ var DARK_FALLBACK = {
13
+ grid: "#262626",
14
+ tick: "#787878",
15
+ tooltipBg: "#141414",
16
+ tooltipBorder: "#262626",
17
+ tooltipText: "#e6ddd0",
18
+ cursor: "#3a3a3a",
19
+ activeDot: "#e6ddd0",
20
+ barCursor: "rgba(255, 255, 255, 0.04)",
21
+ accent: "#fcd34d",
22
+ series: [
23
+ "#fcd34d",
24
+ "#d4574b",
25
+ "#5b9a8b",
26
+ "#9b7bd4",
27
+ "#e5903b",
28
+ "#4db8a4",
29
+ "#d47b9b",
30
+ "#7bc4d4",
31
+ "#e6ddd0"
32
+ ]
33
+ };
34
+ function readVar(el, name) {
35
+ return getComputedStyle(el).getPropertyValue(name).trim();
36
+ }
37
+ function useChartColors() {
38
+ const ref = React.useRef(DARK_FALLBACK);
39
+ const [, rerender] = React.useState(0);
40
+ const observerRef = React.useRef(null);
41
+ React.useEffect(() => {
42
+ function read() {
43
+ const el = document.documentElement;
44
+ const grid = readVar(el, "--chart-grid");
45
+ if (!grid) return;
46
+ ref.current = {
47
+ grid,
48
+ tick: readVar(el, "--chart-tick"),
49
+ tooltipBg: readVar(el, "--chart-tooltip-bg"),
50
+ tooltipBorder: readVar(el, "--chart-tooltip-border"),
51
+ tooltipText: readVar(el, "--chart-tooltip-text"),
52
+ cursor: readVar(el, "--chart-cursor"),
53
+ activeDot: readVar(el, "--chart-active-dot"),
54
+ barCursor: readVar(el, "--chart-bar-cursor"),
55
+ accent: readVar(el, "--accent"),
56
+ series: Array.from(
57
+ { length: 9 },
58
+ (_, i) => readVar(el, `--chart-${i + 1}`)
59
+ )
60
+ };
61
+ rerender((n) => n + 1);
62
+ }
63
+ read();
64
+ observerRef.current = new MutationObserver(read);
65
+ observerRef.current.observe(document.documentElement, {
66
+ attributes: true,
67
+ attributeFilter: ["class"]
68
+ });
69
+ return () => observerRef.current?.disconnect();
70
+ }, []);
71
+ return ref.current;
72
+ }
73
+
74
+ // src/components/sparkline.tsx
75
+ import { jsx, jsxs } from "react/jsx-runtime";
76
+ function Sparkline({
77
+ data,
78
+ width = 80,
79
+ height = 24,
80
+ color,
81
+ fillOpacity = 0.1,
82
+ className
83
+ }) {
84
+ const chartColors = useChartColors();
85
+ const resolvedColor = color ?? chartColors.accent;
86
+ if (data.length === 0) {
87
+ return /* @__PURE__ */ jsx(
88
+ "svg",
89
+ {
90
+ width,
91
+ height,
92
+ className: cn("inline-block", className)
93
+ }
94
+ );
95
+ }
96
+ const min = Math.min(...data);
97
+ const max = Math.max(...data);
98
+ const range = max - min || 1;
99
+ const padding = 1;
100
+ const viewWidth = width;
101
+ const viewHeight = height;
102
+ const plotWidth = viewWidth - padding * 2;
103
+ const plotHeight = viewHeight - padding * 2;
104
+ const points = data.map((value, index) => {
105
+ const x = padding + index / Math.max(data.length - 1, 1) * plotWidth;
106
+ const y = padding + plotHeight - (value - min) / range * plotHeight;
107
+ return { x, y };
108
+ });
109
+ const linePoints = points.map((p) => `${p.x},${p.y}`).join(" ");
110
+ const fillPoints = [
111
+ `${points[0].x},${padding + plotHeight}`,
112
+ ...points.map((p) => `${p.x},${p.y}`),
113
+ `${points[points.length - 1].x},${padding + plotHeight}`
114
+ ].join(" ");
115
+ return /* @__PURE__ */ jsxs(
116
+ "svg",
117
+ {
118
+ width,
119
+ height,
120
+ viewBox: `0 0 ${viewWidth} ${viewHeight}`,
121
+ className: cn("inline-block", className),
122
+ role: "img",
123
+ "aria-label": "Sparkline chart",
124
+ children: [
125
+ /* @__PURE__ */ jsx(
126
+ "polygon",
127
+ {
128
+ points: fillPoints,
129
+ fill: resolvedColor,
130
+ opacity: fillOpacity
131
+ }
132
+ ),
133
+ /* @__PURE__ */ jsx(
134
+ "polyline",
135
+ {
136
+ points: linePoints,
137
+ fill: "none",
138
+ stroke: resolvedColor,
139
+ strokeWidth: 1.5,
140
+ strokeLinecap: "round",
141
+ strokeLinejoin: "round"
142
+ }
143
+ )
144
+ ]
145
+ }
146
+ );
147
+ }
148
+
149
+ // src/components/kpi-card.tsx
150
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
151
+ function KpiCard({
152
+ label,
153
+ value,
154
+ trend,
155
+ sparklineData,
156
+ icon,
157
+ className
158
+ }) {
159
+ const colors = useChartColors();
160
+ return /* @__PURE__ */ jsxs2(
161
+ "div",
162
+ {
163
+ className: cn(
164
+ "rounded-card border border-surface-border bg-surface p-card-p shadow-card",
165
+ className
166
+ ),
167
+ children: [
168
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
169
+ icon && /* @__PURE__ */ jsx2("span", { className: "flex-shrink-0 text-text-tertiary", children: icon }),
170
+ /* @__PURE__ */ jsx2("span", { className: "text-sm text-text-secondary", children: label })
171
+ ] }),
172
+ /* @__PURE__ */ jsxs2("div", { className: "mt-2 flex items-end justify-between gap-4", children: [
173
+ /* @__PURE__ */ jsx2("div", { className: "text-3xl font-semibold text-text", children: value }),
174
+ sparklineData && sparklineData.length > 0 && /* @__PURE__ */ jsx2(
175
+ Sparkline,
176
+ {
177
+ data: sparklineData,
178
+ width: 80,
179
+ height: 28,
180
+ color: trend ? trend.isPositive ? colors.series[2] : colors.series[1] : void 0
181
+ }
182
+ )
183
+ ] }),
184
+ trend && /* @__PURE__ */ jsx2("div", { className: "mt-1 flex items-center gap-1", children: /* @__PURE__ */ jsxs2(
185
+ "span",
186
+ {
187
+ className: cn(
188
+ "text-sm font-medium",
189
+ trend.isPositive ? "text-revenue" : "text-loss"
190
+ ),
191
+ "aria-label": `${trend.isPositive ? "Up" : "Down"} ${Math.abs(trend.value).toFixed(1)}%`,
192
+ children: [
193
+ trend.isPositive ? "\u2191" : "\u2193",
194
+ " ",
195
+ Math.abs(trend.value).toFixed(1),
196
+ "%"
197
+ ]
198
+ }
199
+ ) })
200
+ ]
201
+ }
202
+ );
203
+ }
204
+
205
+ // src/components/data-table.tsx
206
+ import * as React2 from "react";
207
+ import {
208
+ useReactTable,
209
+ getCoreRowModel,
210
+ getSortedRowModel,
211
+ getPaginationRowModel,
212
+ getFilteredRowModel,
213
+ flexRender
214
+ } from "@tanstack/react-table";
215
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
216
+ function DataTable({
217
+ columns,
218
+ data,
219
+ pageSize = 20,
220
+ searchable = false,
221
+ searchPlaceholder = "Search...",
222
+ className
223
+ }) {
224
+ const [sorting, setSorting] = React2.useState([]);
225
+ const [globalFilter, setGlobalFilter] = React2.useState("");
226
+ const table = useReactTable({
227
+ data,
228
+ columns,
229
+ state: {
230
+ sorting,
231
+ globalFilter
232
+ },
233
+ onSortingChange: setSorting,
234
+ onGlobalFilterChange: setGlobalFilter,
235
+ getCoreRowModel: getCoreRowModel(),
236
+ getSortedRowModel: getSortedRowModel(),
237
+ getPaginationRowModel: getPaginationRowModel(),
238
+ getFilteredRowModel: getFilteredRowModel(),
239
+ initialState: {
240
+ pagination: {
241
+ pageSize
242
+ }
243
+ }
244
+ });
245
+ return /* @__PURE__ */ jsxs3("div", { className: cn("flex flex-col gap-3", className), children: [
246
+ searchable && /* @__PURE__ */ jsx3("div", { className: "flex items-center", children: /* @__PURE__ */ jsx3(
247
+ "input",
248
+ {
249
+ type: "text",
250
+ value: globalFilter,
251
+ onChange: (e) => setGlobalFilter(e.target.value),
252
+ placeholder: searchPlaceholder,
253
+ className: cn(
254
+ "w-full max-w-sm rounded-button border border-surface-border bg-surface px-3 py-1.5",
255
+ "text-sm text-text placeholder:text-text-muted",
256
+ "outline-none focus:border-accent focus:ring-1 focus:ring-accent"
257
+ )
258
+ }
259
+ ) }),
260
+ /* @__PURE__ */ jsx3("div", { className: "overflow-auto rounded-card border border-surface-border", children: /* @__PURE__ */ jsxs3("table", { className: "w-full border-collapse text-sm", children: [
261
+ /* @__PURE__ */ jsx3("thead", { className: "sticky top-0 z-10 bg-surface-secondary", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx3("tr", { children: headerGroup.headers.map((header) => {
262
+ const canSort = header.column.getCanSort();
263
+ const sorted = header.column.getIsSorted();
264
+ return /* @__PURE__ */ jsx3(
265
+ "th",
266
+ {
267
+ className: cn(
268
+ "border-b border-surface-border px-3 py-2 text-left font-medium text-text-secondary",
269
+ canSort && "cursor-pointer select-none"
270
+ ),
271
+ onClick: canSort ? header.column.getToggleSortingHandler() : void 0,
272
+ "aria-sort": sorted === "asc" ? "ascending" : sorted === "desc" ? "descending" : canSort ? "none" : void 0,
273
+ children: /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1", children: [
274
+ header.isPlaceholder ? null : flexRender(
275
+ header.column.columnDef.header,
276
+ header.getContext()
277
+ ),
278
+ canSort && /* @__PURE__ */ jsxs3("span", { className: "inline-flex flex-col text-2xs leading-none text-text-muted", children: [
279
+ /* @__PURE__ */ jsx3(
280
+ "span",
281
+ {
282
+ className: cn(
283
+ sorted === "asc" && "text-accent"
284
+ ),
285
+ children: "\u2191"
286
+ }
287
+ ),
288
+ /* @__PURE__ */ jsx3(
289
+ "span",
290
+ {
291
+ className: cn(
292
+ sorted === "desc" && "text-accent"
293
+ ),
294
+ children: "\u2193"
295
+ }
296
+ )
297
+ ] })
298
+ ] })
299
+ },
300
+ header.id
301
+ );
302
+ }) }, headerGroup.id)) }),
303
+ /* @__PURE__ */ jsx3("tbody", { children: table.getRowModel().rows.length === 0 ? /* @__PURE__ */ jsx3("tr", { children: /* @__PURE__ */ jsx3(
304
+ "td",
305
+ {
306
+ colSpan: columns.length,
307
+ className: "px-3 py-8 text-center text-text-tertiary",
308
+ children: "No results."
309
+ }
310
+ ) }) : table.getRowModel().rows.map((row, index) => /* @__PURE__ */ jsx3(
311
+ "tr",
312
+ {
313
+ className: cn(
314
+ "border-b border-surface-border transition-colors hover:bg-surface-hover",
315
+ index % 2 === 1 && "bg-surface-secondary"
316
+ ),
317
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx3("td", { className: "px-3 py-2 text-text", children: flexRender(
318
+ cell.column.columnDef.cell,
319
+ cell.getContext()
320
+ ) }, cell.id))
321
+ },
322
+ row.id
323
+ )) })
324
+ ] }) }),
325
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between px-1 text-sm text-text-secondary", children: [
326
+ /* @__PURE__ */ jsxs3("span", { children: [
327
+ "Page ",
328
+ table.getState().pagination.pageIndex + 1,
329
+ " of",
330
+ " ",
331
+ table.getPageCount() || 1
332
+ ] }),
333
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
334
+ /* @__PURE__ */ jsx3(
335
+ "button",
336
+ {
337
+ type: "button",
338
+ onClick: () => table.previousPage(),
339
+ disabled: !table.getCanPreviousPage(),
340
+ "aria-label": "Go to previous page",
341
+ className: cn(
342
+ "rounded-button border border-surface-border bg-surface px-3 py-1 text-sm",
343
+ "hover:bg-surface-hover",
344
+ "disabled:cursor-not-allowed disabled:text-text-muted disabled:border-surface-border/50"
345
+ ),
346
+ children: "Previous"
347
+ }
348
+ ),
349
+ /* @__PURE__ */ jsx3(
350
+ "button",
351
+ {
352
+ type: "button",
353
+ onClick: () => table.nextPage(),
354
+ disabled: !table.getCanNextPage(),
355
+ "aria-label": "Go to next page",
356
+ className: cn(
357
+ "rounded-button border border-surface-border bg-surface px-3 py-1 text-sm",
358
+ "hover:bg-surface-hover",
359
+ "disabled:cursor-not-allowed disabled:text-text-muted disabled:border-surface-border/50"
360
+ ),
361
+ children: "Next"
362
+ }
363
+ )
364
+ ] })
365
+ ] })
366
+ ] });
367
+ }
368
+
369
+ // src/components/metric-trend.tsx
370
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
371
+ var sizeStyles = {
372
+ sm: {
373
+ value: "text-base font-semibold",
374
+ delta: "text-xs",
375
+ label: "text-xs"
376
+ },
377
+ md: {
378
+ value: "text-xl font-semibold",
379
+ delta: "text-sm",
380
+ label: "text-sm"
381
+ },
382
+ lg: {
383
+ value: "text-3xl font-semibold",
384
+ delta: "text-base",
385
+ label: "text-base"
386
+ }
387
+ };
388
+ function MetricTrend({
389
+ value,
390
+ delta,
391
+ deltaLabel,
392
+ size = "md",
393
+ className
394
+ }) {
395
+ const styles = sizeStyles[size];
396
+ const isPositive = delta >= 0;
397
+ return /* @__PURE__ */ jsxs4("div", { className: cn("flex items-baseline gap-2", className), children: [
398
+ /* @__PURE__ */ jsx4("span", { className: cn(styles.value, "text-text"), children: value }),
399
+ /* @__PURE__ */ jsxs4(
400
+ "span",
401
+ {
402
+ className: cn(
403
+ styles.delta,
404
+ "font-medium",
405
+ isPositive ? "text-revenue" : "text-loss"
406
+ ),
407
+ children: [
408
+ isPositive ? "\u2191" : "\u2193",
409
+ " ",
410
+ Math.abs(delta).toFixed(1),
411
+ "%"
412
+ ]
413
+ }
414
+ ),
415
+ deltaLabel && /* @__PURE__ */ jsx4("span", { className: cn(styles.label, "text-text-muted"), children: deltaLabel })
416
+ ] });
417
+ }
418
+
419
+ // src/components/bar-chart.tsx
420
+ import {
421
+ ResponsiveContainer,
422
+ BarChart as RechartsBarChart,
423
+ Bar,
424
+ XAxis,
425
+ YAxis,
426
+ CartesianGrid,
427
+ Tooltip,
428
+ Legend
429
+ } from "recharts";
430
+ import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
431
+ function BarChart({
432
+ data,
433
+ xKey,
434
+ bars,
435
+ height = 300,
436
+ layout = "vertical",
437
+ className
438
+ }) {
439
+ const colors = useChartColors();
440
+ return /* @__PURE__ */ jsx5("div", { className: cn("w-full", className), role: "img", "aria-label": "Bar chart", children: /* @__PURE__ */ jsx5(ResponsiveContainer, { width: "100%", height, children: /* @__PURE__ */ jsxs5(
441
+ RechartsBarChart,
442
+ {
443
+ data,
444
+ layout: layout === "horizontal" ? "vertical" : "horizontal",
445
+ margin: { top: 8, right: 16, left: 0, bottom: 0 },
446
+ children: [
447
+ /* @__PURE__ */ jsx5(
448
+ CartesianGrid,
449
+ {
450
+ strokeDasharray: "3 3",
451
+ stroke: colors.grid,
452
+ vertical: false
453
+ }
454
+ ),
455
+ layout === "vertical" ? /* @__PURE__ */ jsxs5(Fragment, { children: [
456
+ /* @__PURE__ */ jsx5(
457
+ XAxis,
458
+ {
459
+ dataKey: xKey,
460
+ tick: { fontSize: 12, fill: colors.tick },
461
+ axisLine: { stroke: colors.grid },
462
+ tickLine: false
463
+ }
464
+ ),
465
+ /* @__PURE__ */ jsx5(
466
+ YAxis,
467
+ {
468
+ tick: { fontSize: 12, fill: colors.tick },
469
+ axisLine: false,
470
+ tickLine: false
471
+ }
472
+ )
473
+ ] }) : /* @__PURE__ */ jsxs5(Fragment, { children: [
474
+ /* @__PURE__ */ jsx5(
475
+ XAxis,
476
+ {
477
+ type: "number",
478
+ tick: { fontSize: 12, fill: colors.tick },
479
+ axisLine: false,
480
+ tickLine: false
481
+ }
482
+ ),
483
+ /* @__PURE__ */ jsx5(
484
+ YAxis,
485
+ {
486
+ dataKey: xKey,
487
+ type: "category",
488
+ tick: { fontSize: 12, fill: colors.tick },
489
+ axisLine: { stroke: colors.grid },
490
+ tickLine: false,
491
+ width: 100
492
+ }
493
+ )
494
+ ] }),
495
+ /* @__PURE__ */ jsx5(
496
+ Tooltip,
497
+ {
498
+ contentStyle: {
499
+ backgroundColor: colors.tooltipBg,
500
+ border: `1px solid ${colors.tooltipBorder}`,
501
+ borderRadius: "2px",
502
+ boxShadow: "none",
503
+ fontSize: 12,
504
+ color: colors.tooltipText
505
+ },
506
+ cursor: { fill: colors.barCursor }
507
+ }
508
+ ),
509
+ /* @__PURE__ */ jsx5(
510
+ Legend,
511
+ {
512
+ wrapperStyle: { fontSize: 12, paddingTop: 8 },
513
+ iconType: "circle",
514
+ iconSize: 8
515
+ }
516
+ ),
517
+ bars.map((bar, index) => /* @__PURE__ */ jsx5(
518
+ Bar,
519
+ {
520
+ dataKey: bar.key,
521
+ name: bar.label,
522
+ fill: bar.color ?? colors.series[index % colors.series.length],
523
+ radius: [2, 2, 0, 0],
524
+ maxBarSize: 48
525
+ },
526
+ bar.key
527
+ ))
528
+ ]
529
+ }
530
+ ) }) });
531
+ }
532
+
533
+ // src/components/line-chart.tsx
534
+ import {
535
+ ResponsiveContainer as ResponsiveContainer2,
536
+ LineChart as RechartsLineChart,
537
+ Line,
538
+ XAxis as XAxis2,
539
+ YAxis as YAxis2,
540
+ CartesianGrid as CartesianGrid2,
541
+ Tooltip as Tooltip2,
542
+ Legend as Legend2
543
+ } from "recharts";
544
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
545
+ function LineChart({
546
+ data,
547
+ xKey,
548
+ lines,
549
+ height = 300,
550
+ className
551
+ }) {
552
+ const colors = useChartColors();
553
+ return /* @__PURE__ */ jsx6("div", { className: cn("w-full", className), role: "img", "aria-label": "Line chart", children: /* @__PURE__ */ jsx6(ResponsiveContainer2, { width: "100%", height, children: /* @__PURE__ */ jsxs6(
554
+ RechartsLineChart,
555
+ {
556
+ data,
557
+ margin: { top: 8, right: 16, left: 0, bottom: 0 },
558
+ children: [
559
+ /* @__PURE__ */ jsx6(
560
+ CartesianGrid2,
561
+ {
562
+ strokeDasharray: "3 3",
563
+ stroke: colors.grid,
564
+ vertical: false
565
+ }
566
+ ),
567
+ /* @__PURE__ */ jsx6(
568
+ XAxis2,
569
+ {
570
+ dataKey: xKey,
571
+ tick: { fontSize: 12, fill: colors.tick },
572
+ axisLine: { stroke: colors.grid },
573
+ tickLine: false
574
+ }
575
+ ),
576
+ /* @__PURE__ */ jsx6(
577
+ YAxis2,
578
+ {
579
+ tick: { fontSize: 12, fill: colors.tick },
580
+ axisLine: false,
581
+ tickLine: false
582
+ }
583
+ ),
584
+ /* @__PURE__ */ jsx6(
585
+ Tooltip2,
586
+ {
587
+ contentStyle: {
588
+ backgroundColor: colors.tooltipBg,
589
+ border: `1px solid ${colors.tooltipBorder}`,
590
+ borderRadius: "2px",
591
+ boxShadow: "none",
592
+ fontSize: 12,
593
+ color: colors.tooltipText
594
+ },
595
+ cursor: { stroke: colors.cursor, strokeDasharray: "3 3" }
596
+ }
597
+ ),
598
+ /* @__PURE__ */ jsx6(
599
+ Legend2,
600
+ {
601
+ wrapperStyle: { fontSize: 12, paddingTop: 8 },
602
+ iconType: "circle",
603
+ iconSize: 8
604
+ }
605
+ ),
606
+ lines.map((line, index) => {
607
+ const color = line.color ?? colors.series[index % colors.series.length];
608
+ return /* @__PURE__ */ jsx6(
609
+ Line,
610
+ {
611
+ dataKey: line.key,
612
+ name: line.label,
613
+ type: "monotone",
614
+ stroke: color,
615
+ strokeWidth: 2,
616
+ dot: false,
617
+ activeDot: {
618
+ r: 4,
619
+ fill: color,
620
+ stroke: colors.activeDot,
621
+ strokeWidth: 2
622
+ }
623
+ },
624
+ line.key
625
+ );
626
+ })
627
+ ]
628
+ }
629
+ ) }) });
630
+ }
631
+
632
+ // src/components/area-chart.tsx
633
+ import * as React3 from "react";
634
+ import {
635
+ ResponsiveContainer as ResponsiveContainer3,
636
+ AreaChart as RechartsAreaChart,
637
+ Area,
638
+ XAxis as XAxis3,
639
+ YAxis as YAxis3,
640
+ CartesianGrid as CartesianGrid3,
641
+ Tooltip as Tooltip3,
642
+ Legend as Legend3
643
+ } from "recharts";
644
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
645
+ function AreaChart({
646
+ data,
647
+ xKey,
648
+ areas,
649
+ height = 300,
650
+ stacked = true,
651
+ className
652
+ }) {
653
+ const gradientId = React3.useId();
654
+ const colors = useChartColors();
655
+ return /* @__PURE__ */ jsx7("div", { className: cn("w-full", className), role: "img", "aria-label": "Area chart", children: /* @__PURE__ */ jsx7(ResponsiveContainer3, { width: "100%", height, children: /* @__PURE__ */ jsxs7(
656
+ RechartsAreaChart,
657
+ {
658
+ data,
659
+ margin: { top: 8, right: 16, left: 0, bottom: 0 },
660
+ children: [
661
+ /* @__PURE__ */ jsx7("defs", { children: areas.map((area, index) => {
662
+ const color = area.color ?? colors.series[index % colors.series.length];
663
+ return /* @__PURE__ */ jsxs7(
664
+ "linearGradient",
665
+ {
666
+ id: `${gradientId}-${area.key}`,
667
+ x1: "0",
668
+ y1: "0",
669
+ x2: "0",
670
+ y2: "1",
671
+ children: [
672
+ /* @__PURE__ */ jsx7("stop", { offset: "0%", stopColor: color, stopOpacity: 0.3 }),
673
+ /* @__PURE__ */ jsx7("stop", { offset: "95%", stopColor: color, stopOpacity: 0.02 })
674
+ ]
675
+ },
676
+ area.key
677
+ );
678
+ }) }),
679
+ /* @__PURE__ */ jsx7(
680
+ CartesianGrid3,
681
+ {
682
+ strokeDasharray: "3 3",
683
+ stroke: colors.grid,
684
+ vertical: false
685
+ }
686
+ ),
687
+ /* @__PURE__ */ jsx7(
688
+ XAxis3,
689
+ {
690
+ dataKey: xKey,
691
+ tick: { fontSize: 12, fill: colors.tick },
692
+ axisLine: { stroke: colors.grid },
693
+ tickLine: false
694
+ }
695
+ ),
696
+ /* @__PURE__ */ jsx7(
697
+ YAxis3,
698
+ {
699
+ tick: { fontSize: 12, fill: colors.tick },
700
+ axisLine: false,
701
+ tickLine: false
702
+ }
703
+ ),
704
+ /* @__PURE__ */ jsx7(
705
+ Tooltip3,
706
+ {
707
+ contentStyle: {
708
+ backgroundColor: colors.tooltipBg,
709
+ border: `1px solid ${colors.tooltipBorder}`,
710
+ borderRadius: "2px",
711
+ boxShadow: "none",
712
+ fontSize: 12,
713
+ color: colors.tooltipText
714
+ },
715
+ cursor: { stroke: colors.cursor, strokeDasharray: "3 3" }
716
+ }
717
+ ),
718
+ /* @__PURE__ */ jsx7(
719
+ Legend3,
720
+ {
721
+ wrapperStyle: { fontSize: 12, paddingTop: 8 },
722
+ iconType: "circle",
723
+ iconSize: 8
724
+ }
725
+ ),
726
+ areas.map((area, index) => {
727
+ const color = area.color ?? colors.series[index % colors.series.length];
728
+ return /* @__PURE__ */ jsx7(
729
+ Area,
730
+ {
731
+ dataKey: area.key,
732
+ name: area.label,
733
+ type: "monotone",
734
+ stroke: color,
735
+ strokeWidth: 2,
736
+ fill: `url(#${gradientId}-${area.key})`,
737
+ stackId: stacked ? "stack" : void 0,
738
+ dot: false,
739
+ activeDot: {
740
+ r: 4,
741
+ fill: color,
742
+ stroke: colors.activeDot,
743
+ strokeWidth: 2
744
+ }
745
+ },
746
+ area.key
747
+ );
748
+ })
749
+ ]
750
+ }
751
+ ) }) });
752
+ }
753
+
754
+ // src/components/comparison-row.tsx
755
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
756
+ function ComparisonRow({
757
+ label,
758
+ current,
759
+ previous,
760
+ format: format3 = (v) => v.toLocaleString(),
761
+ className
762
+ }) {
763
+ const delta = previous !== 0 ? (current - previous) / Math.abs(previous) * 100 : 0;
764
+ const isPositive = delta >= 0;
765
+ return /* @__PURE__ */ jsxs8(
766
+ "div",
767
+ {
768
+ className: cn(
769
+ "flex items-center justify-between gap-4 py-2",
770
+ className
771
+ ),
772
+ children: [
773
+ /* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-shrink truncate text-sm text-text-secondary", children: label }),
774
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-4", children: [
775
+ /* @__PURE__ */ jsx8("span", { className: "text-sm font-semibold text-text", children: format3(current) }),
776
+ /* @__PURE__ */ jsx8("span", { className: "text-sm text-text-muted", children: format3(previous) }),
777
+ /* @__PURE__ */ jsxs8(
778
+ "span",
779
+ {
780
+ className: cn(
781
+ "inline-flex items-center rounded-button px-2 py-0.5 text-xs font-medium",
782
+ isPositive ? "bg-revenue-bg text-revenue" : "bg-loss-bg text-loss"
783
+ ),
784
+ "aria-label": `${isPositive ? "Up" : "Down"} ${Math.abs(delta).toFixed(1)}%`,
785
+ children: [
786
+ isPositive ? "\u2191" : "\u2193",
787
+ " ",
788
+ Math.abs(delta).toFixed(1),
789
+ "%"
790
+ ]
791
+ }
792
+ )
793
+ ] })
794
+ ]
795
+ }
796
+ );
797
+ }
798
+
799
+ // src/components/date-range-picker.tsx
800
+ import * as React4 from "react";
801
+ import * as Popover from "@radix-ui/react-popover";
802
+ import {
803
+ startOfMonth,
804
+ endOfMonth,
805
+ subMonths,
806
+ subDays,
807
+ startOfYear,
808
+ format
809
+ } from "date-fns";
810
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
811
+ var DEFAULT_PRESETS = [
812
+ { label: "MTD", value: "mtd" },
813
+ { label: "Last Month", value: "last-month" },
814
+ { label: "Last 30 Days", value: "last-30" },
815
+ { label: "Last 90 Days", value: "last-90" },
816
+ { label: "YTD", value: "ytd" },
817
+ { label: "Custom", value: "custom" }
818
+ ];
819
+ function resolvePreset(preset) {
820
+ const now = /* @__PURE__ */ new Date();
821
+ switch (preset) {
822
+ case "mtd":
823
+ return { start: startOfMonth(now), end: now };
824
+ case "last-month": {
825
+ const prev = subMonths(now, 1);
826
+ return { start: startOfMonth(prev), end: endOfMonth(prev) };
827
+ }
828
+ case "last-30":
829
+ return { start: subDays(now, 30), end: now };
830
+ case "last-90":
831
+ return { start: subDays(now, 90), end: now };
832
+ case "ytd":
833
+ return { start: startOfYear(now), end: now };
834
+ default:
835
+ return null;
836
+ }
837
+ }
838
+ function DateRangePicker({
839
+ value,
840
+ onChange,
841
+ onPresetChange,
842
+ presets = DEFAULT_PRESETS,
843
+ className
844
+ }) {
845
+ const [open, setOpen] = React4.useState(false);
846
+ const [activePreset, setActivePreset] = React4.useState(null);
847
+ const [showCustomForm, setShowCustomForm] = React4.useState(false);
848
+ const [customStart, setCustomStart] = React4.useState(
849
+ format(value.start, "yyyy-MM-dd")
850
+ );
851
+ const [customEnd, setCustomEnd] = React4.useState(
852
+ format(value.end, "yyyy-MM-dd")
853
+ );
854
+ const handlePresetClick = (preset) => {
855
+ setActivePreset(preset);
856
+ onPresetChange?.(preset);
857
+ if (preset === "custom") {
858
+ setShowCustomForm(true);
859
+ setCustomStart(format(value.start, "yyyy-MM-dd"));
860
+ setCustomEnd(format(value.end, "yyyy-MM-dd"));
861
+ return;
862
+ }
863
+ setShowCustomForm(false);
864
+ const range = resolvePreset(preset);
865
+ if (range) {
866
+ onChange(range);
867
+ setOpen(false);
868
+ }
869
+ };
870
+ const handleCustomApply = () => {
871
+ const start = /* @__PURE__ */ new Date(customStart + "T00:00:00");
872
+ const end = /* @__PURE__ */ new Date(customEnd + "T00:00:00");
873
+ if (!isNaN(start.getTime()) && !isNaN(end.getTime()) && start <= end) {
874
+ onChange({ start, end });
875
+ setOpen(false);
876
+ setShowCustomForm(false);
877
+ }
878
+ };
879
+ const displayLabel = `${format(value.start, "MMM d, yyyy")} - ${format(value.end, "MMM d, yyyy")}`;
880
+ return /* @__PURE__ */ jsxs9(Popover.Root, { open, onOpenChange: setOpen, children: [
881
+ /* @__PURE__ */ jsx9(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs9(
882
+ "button",
883
+ {
884
+ type: "button",
885
+ className: cn(
886
+ "inline-flex items-center gap-2 rounded-button border border-surface-border bg-surface px-3 py-1.5",
887
+ "text-sm text-text hover:bg-surface-hover",
888
+ "outline-none focus:border-accent focus:ring-1 focus:ring-accent",
889
+ className
890
+ ),
891
+ children: [
892
+ /* @__PURE__ */ jsx9(
893
+ "svg",
894
+ {
895
+ width: "16",
896
+ height: "16",
897
+ viewBox: "0 0 16 16",
898
+ fill: "none",
899
+ className: "text-text-tertiary",
900
+ children: /* @__PURE__ */ jsx9(
901
+ "path",
902
+ {
903
+ d: "M5 1v2M11 1v2M1 6h14M3 3h10a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",
904
+ stroke: "currentColor",
905
+ strokeWidth: "1.5",
906
+ strokeLinecap: "round",
907
+ strokeLinejoin: "round"
908
+ }
909
+ )
910
+ }
911
+ ),
912
+ /* @__PURE__ */ jsx9("span", { children: displayLabel })
913
+ ]
914
+ }
915
+ ) }),
916
+ /* @__PURE__ */ jsx9(Popover.Portal, { children: /* @__PURE__ */ jsxs9(
917
+ Popover.Content,
918
+ {
919
+ align: "start",
920
+ sideOffset: 4,
921
+ className: cn(
922
+ "z-50 rounded-card border border-surface-border bg-surface p-3 shadow-card",
923
+ "animate-in fade-in-0 zoom-in-95",
924
+ "w-64"
925
+ ),
926
+ children: [
927
+ /* @__PURE__ */ jsx9("div", { className: "flex flex-col gap-1", children: presets.map((preset) => /* @__PURE__ */ jsx9(
928
+ "button",
929
+ {
930
+ type: "button",
931
+ onClick: () => handlePresetClick(preset.value),
932
+ className: cn(
933
+ "rounded-button px-3 py-1.5 text-left text-sm transition-colors",
934
+ activePreset === preset.value ? "bg-accent-light text-accent-dark font-medium" : "text-text hover:bg-surface-hover"
935
+ ),
936
+ children: preset.label
937
+ },
938
+ preset.value
939
+ )) }),
940
+ showCustomForm && /* @__PURE__ */ jsxs9("div", { className: "mt-3 flex flex-col gap-2 border-t border-surface-border pt-3", children: [
941
+ /* @__PURE__ */ jsxs9("label", { className: "flex flex-col gap-1", children: [
942
+ /* @__PURE__ */ jsx9("span", { className: "text-xs font-medium text-text-secondary", children: "Start date" }),
943
+ /* @__PURE__ */ jsx9(
944
+ "input",
945
+ {
946
+ type: "date",
947
+ value: customStart,
948
+ onChange: (e) => setCustomStart(e.target.value),
949
+ className: cn(
950
+ "rounded-button border border-surface-border bg-surface px-2 py-1",
951
+ "text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent"
952
+ )
953
+ }
954
+ )
955
+ ] }),
956
+ /* @__PURE__ */ jsxs9("label", { className: "flex flex-col gap-1", children: [
957
+ /* @__PURE__ */ jsx9("span", { className: "text-xs font-medium text-text-secondary", children: "End date" }),
958
+ /* @__PURE__ */ jsx9(
959
+ "input",
960
+ {
961
+ type: "date",
962
+ value: customEnd,
963
+ onChange: (e) => setCustomEnd(e.target.value),
964
+ className: cn(
965
+ "rounded-button border border-surface-border bg-surface px-2 py-1",
966
+ "text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent"
967
+ )
968
+ }
969
+ )
970
+ ] }),
971
+ /* @__PURE__ */ jsx9(
972
+ "button",
973
+ {
974
+ type: "button",
975
+ onClick: handleCustomApply,
976
+ className: cn(
977
+ "mt-1 rounded-button bg-accent px-3 py-1.5 text-sm font-medium text-text-inverse",
978
+ "hover:bg-accent-dark transition-colors"
979
+ ),
980
+ children: "Apply"
981
+ }
982
+ )
983
+ ] }),
984
+ /* @__PURE__ */ jsx9(Popover.Arrow, { className: "fill-surface-border" })
985
+ ]
986
+ }
987
+ ) })
988
+ ] });
989
+ }
990
+
991
+ // src/components/filter-bar.tsx
992
+ import * as React5 from "react";
993
+ import * as Select from "@radix-ui/react-select";
994
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
995
+ function FilterDropdownSingle({
996
+ filter,
997
+ value,
998
+ onChange
999
+ }) {
1000
+ return /* @__PURE__ */ jsxs10(Select.Root, { value: value || void 0, onValueChange: onChange, children: [
1001
+ /* @__PURE__ */ jsxs10(
1002
+ Select.Trigger,
1003
+ {
1004
+ "aria-label": filter.label,
1005
+ className: cn(
1006
+ "inline-flex items-center gap-1.5 rounded-button border border-surface-border bg-surface px-3 py-1.5",
1007
+ "text-sm outline-none hover:bg-surface-hover",
1008
+ "focus:border-accent focus:ring-1 focus:ring-accent",
1009
+ value ? "text-text" : "text-text-tertiary"
1010
+ ),
1011
+ children: [
1012
+ /* @__PURE__ */ jsx10(Select.Value, { placeholder: filter.label }),
1013
+ /* @__PURE__ */ jsx10(Select.Icon, { children: /* @__PURE__ */ jsx10(
1014
+ "svg",
1015
+ {
1016
+ width: "12",
1017
+ height: "12",
1018
+ viewBox: "0 0 12 12",
1019
+ fill: "none",
1020
+ className: "text-text-muted",
1021
+ children: /* @__PURE__ */ jsx10(
1022
+ "path",
1023
+ {
1024
+ d: "M3 4.5l3 3 3-3",
1025
+ stroke: "currentColor",
1026
+ strokeWidth: "1.5",
1027
+ strokeLinecap: "round",
1028
+ strokeLinejoin: "round"
1029
+ }
1030
+ )
1031
+ }
1032
+ ) })
1033
+ ]
1034
+ }
1035
+ ),
1036
+ /* @__PURE__ */ jsx10(Select.Portal, { children: /* @__PURE__ */ jsx10(
1037
+ Select.Content,
1038
+ {
1039
+ className: cn(
1040
+ "z-50 overflow-hidden rounded-card border border-surface-border bg-surface shadow-card",
1041
+ "animate-in fade-in-0 zoom-in-95"
1042
+ ),
1043
+ position: "popper",
1044
+ sideOffset: 4,
1045
+ children: /* @__PURE__ */ jsx10(Select.Viewport, { className: "p-1", children: filter.options.map((option) => /* @__PURE__ */ jsx10(
1046
+ Select.Item,
1047
+ {
1048
+ value: option.value,
1049
+ className: cn(
1050
+ "cursor-pointer rounded-button px-3 py-1.5 text-sm text-text outline-none",
1051
+ "data-[highlighted]:bg-surface-hover",
1052
+ "data-[state=checked]:font-medium data-[state=checked]:text-accent"
1053
+ ),
1054
+ children: /* @__PURE__ */ jsx10(Select.ItemText, { children: option.label })
1055
+ },
1056
+ option.value
1057
+ )) })
1058
+ }
1059
+ ) })
1060
+ ] });
1061
+ }
1062
+ function FilterDropdownMultiple({
1063
+ filter,
1064
+ value,
1065
+ onChange
1066
+ }) {
1067
+ const [open, setOpen] = React5.useState(false);
1068
+ const handleToggle = (optionValue) => {
1069
+ const next = value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue];
1070
+ onChange(next);
1071
+ };
1072
+ const selectedLabels = filter.options.filter((o) => value.includes(o.value)).map((o) => o.label);
1073
+ return /* @__PURE__ */ jsxs10("div", { className: "relative", children: [
1074
+ /* @__PURE__ */ jsxs10(
1075
+ "button",
1076
+ {
1077
+ type: "button",
1078
+ onClick: () => setOpen(!open),
1079
+ className: cn(
1080
+ "inline-flex items-center gap-1.5 rounded-button border border-surface-border bg-surface px-3 py-1.5",
1081
+ "text-sm outline-none hover:bg-surface-hover",
1082
+ "focus:border-accent focus:ring-1 focus:ring-accent",
1083
+ value.length > 0 ? "text-text" : "text-text-tertiary"
1084
+ ),
1085
+ children: [
1086
+ /* @__PURE__ */ jsx10("span", { children: value.length === 0 ? filter.label : selectedLabels.length <= 2 ? selectedLabels.join(", ") : `${selectedLabels[0]} +${selectedLabels.length - 1}` }),
1087
+ /* @__PURE__ */ jsx10(
1088
+ "svg",
1089
+ {
1090
+ width: "12",
1091
+ height: "12",
1092
+ viewBox: "0 0 12 12",
1093
+ fill: "none",
1094
+ className: "text-text-muted",
1095
+ children: /* @__PURE__ */ jsx10(
1096
+ "path",
1097
+ {
1098
+ d: "M3 4.5l3 3 3-3",
1099
+ stroke: "currentColor",
1100
+ strokeWidth: "1.5",
1101
+ strokeLinecap: "round",
1102
+ strokeLinejoin: "round"
1103
+ }
1104
+ )
1105
+ }
1106
+ )
1107
+ ]
1108
+ }
1109
+ ),
1110
+ open && /* @__PURE__ */ jsxs10(Fragment2, { children: [
1111
+ /* @__PURE__ */ jsx10(
1112
+ "div",
1113
+ {
1114
+ className: "fixed inset-0 z-40",
1115
+ onClick: () => setOpen(false)
1116
+ }
1117
+ ),
1118
+ /* @__PURE__ */ jsx10(
1119
+ "div",
1120
+ {
1121
+ className: cn(
1122
+ "absolute left-0 top-full z-50 mt-1 min-w-[12rem] overflow-hidden rounded-card border border-surface-border bg-surface p-1 shadow-card"
1123
+ ),
1124
+ children: filter.options.map((option) => {
1125
+ const checked = value.includes(option.value);
1126
+ return /* @__PURE__ */ jsxs10(
1127
+ "button",
1128
+ {
1129
+ type: "button",
1130
+ onClick: () => handleToggle(option.value),
1131
+ className: cn(
1132
+ "flex w-full items-center gap-2 rounded-button px-3 py-1.5 text-left text-sm text-text outline-none",
1133
+ "hover:bg-surface-hover"
1134
+ ),
1135
+ children: [
1136
+ /* @__PURE__ */ jsx10(
1137
+ "span",
1138
+ {
1139
+ className: cn(
1140
+ "flex h-4 w-4 items-center justify-center rounded border",
1141
+ checked ? "border-accent bg-accent text-text-inverse" : "border-surface-border bg-surface"
1142
+ ),
1143
+ children: checked && /* @__PURE__ */ jsx10(
1144
+ "svg",
1145
+ {
1146
+ width: "10",
1147
+ height: "10",
1148
+ viewBox: "0 0 10 10",
1149
+ fill: "none",
1150
+ children: /* @__PURE__ */ jsx10(
1151
+ "path",
1152
+ {
1153
+ d: "M2 5l2 2 4-4",
1154
+ stroke: "currentColor",
1155
+ strokeWidth: "1.5",
1156
+ strokeLinecap: "round",
1157
+ strokeLinejoin: "round"
1158
+ }
1159
+ )
1160
+ }
1161
+ )
1162
+ }
1163
+ ),
1164
+ /* @__PURE__ */ jsx10("span", { children: option.label })
1165
+ ]
1166
+ },
1167
+ option.value
1168
+ );
1169
+ })
1170
+ }
1171
+ )
1172
+ ] })
1173
+ ] });
1174
+ }
1175
+ function ActiveFilterBadge({
1176
+ filter,
1177
+ value
1178
+ }) {
1179
+ const count = Array.isArray(value) ? value.length : value ? 1 : 0;
1180
+ if (count === 0) return null;
1181
+ return /* @__PURE__ */ jsxs10(
1182
+ "span",
1183
+ {
1184
+ className: cn(
1185
+ "inline-flex items-center gap-1 rounded-full bg-accent-light px-2 py-0.5 text-xs font-medium text-accent-dark"
1186
+ ),
1187
+ children: [
1188
+ filter.label,
1189
+ /* @__PURE__ */ jsx10("span", { className: "rounded-full bg-accent px-1.5 py-0.5 text-2xs leading-none text-text-inverse", children: count })
1190
+ ]
1191
+ }
1192
+ );
1193
+ }
1194
+ function FilterBar({
1195
+ filters,
1196
+ values,
1197
+ onChange,
1198
+ onClear,
1199
+ className
1200
+ }) {
1201
+ const hasActiveFilters = Object.values(values).some(
1202
+ (v) => Array.isArray(v) ? v.length > 0 : Boolean(v)
1203
+ );
1204
+ return /* @__PURE__ */ jsxs10("div", { className: cn("flex flex-col gap-2", className), children: [
1205
+ /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap items-center gap-2", children: [
1206
+ filters.map((filter) => {
1207
+ const currentValue = values[filter.id];
1208
+ if (filter.multiple) {
1209
+ return /* @__PURE__ */ jsx10(
1210
+ FilterDropdownMultiple,
1211
+ {
1212
+ filter,
1213
+ value: Array.isArray(currentValue) ? currentValue : [],
1214
+ onChange: (val) => onChange(filter.id, val)
1215
+ },
1216
+ filter.id
1217
+ );
1218
+ }
1219
+ return /* @__PURE__ */ jsx10(
1220
+ FilterDropdownSingle,
1221
+ {
1222
+ filter,
1223
+ value: typeof currentValue === "string" ? currentValue : "",
1224
+ onChange: (val) => onChange(filter.id, val)
1225
+ },
1226
+ filter.id
1227
+ );
1228
+ }),
1229
+ hasActiveFilters && onClear && /* @__PURE__ */ jsx10(
1230
+ "button",
1231
+ {
1232
+ type: "button",
1233
+ onClick: onClear,
1234
+ className: cn(
1235
+ "rounded-button px-2 py-1.5 text-sm text-text-tertiary",
1236
+ "hover:text-text hover:bg-surface-hover transition-colors"
1237
+ ),
1238
+ children: "Clear all"
1239
+ }
1240
+ )
1241
+ ] }),
1242
+ hasActiveFilters && /* @__PURE__ */ jsx10("div", { className: "flex flex-wrap items-center gap-1.5", children: filters.map((filter) => {
1243
+ const currentValue = values[filter.id];
1244
+ if (!currentValue) return null;
1245
+ return /* @__PURE__ */ jsx10(
1246
+ ActiveFilterBadge,
1247
+ {
1248
+ filter,
1249
+ value: currentValue
1250
+ },
1251
+ filter.id
1252
+ );
1253
+ }) })
1254
+ ] });
1255
+ }
1256
+
1257
+ // src/components/sidebar-nav.tsx
1258
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1259
+ function SidebarNav({
1260
+ items,
1261
+ collapsed = false,
1262
+ onToggleCollapse,
1263
+ header,
1264
+ footer,
1265
+ className
1266
+ }) {
1267
+ return /* @__PURE__ */ jsxs11(
1268
+ "nav",
1269
+ {
1270
+ className: cn(
1271
+ "flex h-full flex-col border-r border-surface-border bg-surface-secondary",
1272
+ "transition-[width] duration-200 ease-in-out",
1273
+ collapsed ? "w-sidebar-collapsed" : "w-sidebar-w",
1274
+ className
1275
+ ),
1276
+ "aria-label": "Sidebar navigation",
1277
+ children: [
1278
+ header && /* @__PURE__ */ jsx11(
1279
+ "div",
1280
+ {
1281
+ className: cn(
1282
+ "flex items-center border-b border-surface-border px-3 py-3",
1283
+ collapsed && "justify-center"
1284
+ ),
1285
+ children: header
1286
+ }
1287
+ ),
1288
+ /* @__PURE__ */ jsx11("ul", { className: "flex flex-1 flex-col gap-0.5 overflow-y-auto p-2", children: items.map((item) => /* @__PURE__ */ jsx11("li", { children: /* @__PURE__ */ jsxs11(
1289
+ "a",
1290
+ {
1291
+ href: item.href,
1292
+ className: cn(
1293
+ "flex items-center gap-3 rounded-button px-3 py-2 text-sm transition-colors",
1294
+ "outline-none focus-visible:ring-2 focus-visible:ring-accent",
1295
+ item.active ? "bg-surface-hover text-text font-medium border-l-2 border-accent" : "text-text-secondary hover:bg-surface-hover hover:text-text border-l-2 border-transparent",
1296
+ collapsed && "justify-center px-2"
1297
+ ),
1298
+ "aria-current": item.active ? "page" : void 0,
1299
+ title: collapsed ? item.label : void 0,
1300
+ children: [
1301
+ item.icon && /* @__PURE__ */ jsx11(
1302
+ "span",
1303
+ {
1304
+ className: cn(
1305
+ "flex h-5 w-5 shrink-0 items-center justify-center",
1306
+ item.active ? "text-accent" : "text-text-tertiary"
1307
+ ),
1308
+ children: item.icon
1309
+ }
1310
+ ),
1311
+ !collapsed && /* @__PURE__ */ jsx11("span", { className: "truncate", children: item.label })
1312
+ ]
1313
+ }
1314
+ ) }, item.href)) }),
1315
+ footer,
1316
+ onToggleCollapse && /* @__PURE__ */ jsx11("div", { className: "border-t border-surface-border p-2", children: /* @__PURE__ */ jsxs11(
1317
+ "button",
1318
+ {
1319
+ type: "button",
1320
+ onClick: onToggleCollapse,
1321
+ className: cn(
1322
+ "flex w-full items-center gap-3 rounded-button px-3 py-2 text-sm text-text-tertiary",
1323
+ "hover:bg-surface-hover hover:text-text transition-colors",
1324
+ "outline-none focus-visible:ring-2 focus-visible:ring-accent",
1325
+ collapsed && "justify-center px-2"
1326
+ ),
1327
+ "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
1328
+ children: [
1329
+ /* @__PURE__ */ jsx11(
1330
+ "svg",
1331
+ {
1332
+ width: "16",
1333
+ height: "16",
1334
+ viewBox: "0 0 16 16",
1335
+ fill: "none",
1336
+ className: cn(
1337
+ "shrink-0 transition-transform duration-200",
1338
+ collapsed && "rotate-180"
1339
+ ),
1340
+ children: /* @__PURE__ */ jsx11(
1341
+ "path",
1342
+ {
1343
+ d: "M10 3L5 8l5 5",
1344
+ stroke: "currentColor",
1345
+ strokeWidth: "1.5",
1346
+ strokeLinecap: "round",
1347
+ strokeLinejoin: "round"
1348
+ }
1349
+ )
1350
+ }
1351
+ ),
1352
+ !collapsed && /* @__PURE__ */ jsx11("span", { children: "Collapse" })
1353
+ ]
1354
+ }
1355
+ ) })
1356
+ ]
1357
+ }
1358
+ );
1359
+ }
1360
+
1361
+ // src/components/page-header.tsx
1362
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1363
+ function PageHeader({
1364
+ title,
1365
+ description,
1366
+ breadcrumbs,
1367
+ actions,
1368
+ className
1369
+ }) {
1370
+ return /* @__PURE__ */ jsxs12("div", { className: cn("space-y-1", className), children: [
1371
+ breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx12("nav", { "aria-label": "Breadcrumb", className: "mb-2", children: /* @__PURE__ */ jsx12("ol", { className: "flex items-center gap-1 text-xs text-text-tertiary", children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ jsxs12("li", { className: "flex items-center gap-1", children: [
1372
+ index > 0 && /* @__PURE__ */ jsx12("span", { "aria-hidden": "true", className: "text-text-muted", children: "/" }),
1373
+ crumb.href ? /* @__PURE__ */ jsx12(
1374
+ "a",
1375
+ {
1376
+ href: crumb.href,
1377
+ className: "transition-colors hover:text-text-secondary",
1378
+ children: crumb.label
1379
+ }
1380
+ ) : /* @__PURE__ */ jsx12("span", { className: "text-text-secondary", children: crumb.label })
1381
+ ] }, index)) }) }),
1382
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-start justify-between gap-4", children: [
1383
+ /* @__PURE__ */ jsxs12("div", { className: "min-w-0", children: [
1384
+ /* @__PURE__ */ jsx12("h1", { className: "text-2xl font-semibold text-text", children: title }),
1385
+ description && /* @__PURE__ */ jsx12("p", { className: "mt-1 text-sm text-text-secondary", children: description })
1386
+ ] }),
1387
+ actions && /* @__PURE__ */ jsx12("div", { className: "flex flex-shrink-0 items-center gap-2", children: actions })
1388
+ ] })
1389
+ ] });
1390
+ }
1391
+
1392
+ // src/components/button.tsx
1393
+ import { Slot } from "@radix-ui/react-slot";
1394
+ import { cva } from "class-variance-authority";
1395
+ import { jsx as jsx13 } from "react/jsx-runtime";
1396
+ var buttonVariants = cva(
1397
+ "inline-flex items-center justify-center rounded-button font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent disabled:pointer-events-none disabled:opacity-50",
1398
+ {
1399
+ variants: {
1400
+ variant: {
1401
+ primary: "bg-primary text-primary-foreground font-display uppercase tracking-wider hover:opacity-90",
1402
+ secondary: "border-2 border-foreground bg-transparent text-foreground hover:bg-foreground hover:text-background",
1403
+ ghost: "bg-transparent text-foreground hover:bg-muted"
1404
+ },
1405
+ size: {
1406
+ sm: "h-8 px-3 text-xs",
1407
+ md: "h-10 px-5 text-sm",
1408
+ lg: "h-12 px-8 text-base"
1409
+ }
1410
+ },
1411
+ defaultVariants: {
1412
+ variant: "primary",
1413
+ size: "md"
1414
+ }
1415
+ }
1416
+ );
1417
+ function Button({
1418
+ className,
1419
+ variant,
1420
+ size,
1421
+ asChild = false,
1422
+ ...props
1423
+ }) {
1424
+ const Comp = asChild ? Slot : "button";
1425
+ return /* @__PURE__ */ jsx13(
1426
+ Comp,
1427
+ {
1428
+ className: cn(buttonVariants({ variant, size, className })),
1429
+ ...props
1430
+ }
1431
+ );
1432
+ }
1433
+
1434
+ // src/components/badge.tsx
1435
+ import { cva as cva2 } from "class-variance-authority";
1436
+ import { jsx as jsx14 } from "react/jsx-runtime";
1437
+ var badgeVariants = cva2(
1438
+ "inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium transition-colors",
1439
+ {
1440
+ variants: {
1441
+ variant: {
1442
+ default: "bg-foreground text-background",
1443
+ primary: "bg-primary text-primary-foreground",
1444
+ outline: "border-2 border-foreground text-foreground bg-transparent",
1445
+ muted: "bg-muted text-muted-foreground"
1446
+ }
1447
+ },
1448
+ defaultVariants: {
1449
+ variant: "default"
1450
+ }
1451
+ }
1452
+ );
1453
+ function Badge({ className, variant, ...props }) {
1454
+ return /* @__PURE__ */ jsx14("span", { className: cn(badgeVariants({ variant, className })), ...props });
1455
+ }
1456
+
1457
+ // src/components/card.tsx
1458
+ import { jsx as jsx15 } from "react/jsx-runtime";
1459
+ function CardHeader({ className, ...props }) {
1460
+ return /* @__PURE__ */ jsx15("div", { className: cn("flex flex-col gap-1.5 p-6 pb-0", className), ...props });
1461
+ }
1462
+ function CardTitle({ className, ...props }) {
1463
+ return /* @__PURE__ */ jsx15(
1464
+ "h3",
1465
+ {
1466
+ className: cn("font-display text-xl uppercase tracking-wider text-card-foreground", className),
1467
+ ...props
1468
+ }
1469
+ );
1470
+ }
1471
+ function CardDescription({ className, ...props }) {
1472
+ return /* @__PURE__ */ jsx15("p", { className: cn("text-sm text-muted-foreground", className), ...props });
1473
+ }
1474
+ function CardContent({ className, ...props }) {
1475
+ return /* @__PURE__ */ jsx15("div", { className: cn("p-6", className), ...props });
1476
+ }
1477
+ function CardFooter({ className, ...props }) {
1478
+ return /* @__PURE__ */ jsx15("div", { className: cn("flex items-center p-6 pt-0", className), ...props });
1479
+ }
1480
+ function CardRoot({ className, ...props }) {
1481
+ return /* @__PURE__ */ jsx15(
1482
+ "div",
1483
+ {
1484
+ className: cn(
1485
+ "rounded-card border-2 border-foreground/40 bg-card text-card-foreground",
1486
+ className
1487
+ ),
1488
+ ...props
1489
+ }
1490
+ );
1491
+ }
1492
+ var Card = Object.assign(CardRoot, {
1493
+ Header: CardHeader,
1494
+ Title: CardTitle,
1495
+ Description: CardDescription,
1496
+ Content: CardContent,
1497
+ Footer: CardFooter
1498
+ });
1499
+
1500
+ // src/components/section.tsx
1501
+ import { cva as cva3 } from "class-variance-authority";
1502
+ import { jsx as jsx16 } from "react/jsx-runtime";
1503
+ var sectionVariants = cva3("py-16 md:py-24", {
1504
+ variants: {
1505
+ variant: {
1506
+ default: "",
1507
+ muted: "bg-muted/30",
1508
+ bordered: "border-y-2 border-foreground/40"
1509
+ }
1510
+ },
1511
+ defaultVariants: {
1512
+ variant: "default"
1513
+ }
1514
+ });
1515
+ function Section({
1516
+ className,
1517
+ variant,
1518
+ noContainer = false,
1519
+ children,
1520
+ ...props
1521
+ }) {
1522
+ return /* @__PURE__ */ jsx16("section", { className: cn(sectionVariants({ variant }), className), ...props, children: noContainer ? children : /* @__PURE__ */ jsx16("div", { className: "mx-auto max-w-7xl px-6 lg:px-8", children }) });
1523
+ }
1524
+
1525
+ // src/components/stat-card.tsx
1526
+ import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1527
+ function StatCard({ value, label, notched = false, className, ...props }) {
1528
+ return /* @__PURE__ */ jsxs13(
1529
+ "div",
1530
+ {
1531
+ className: cn(
1532
+ "relative overflow-hidden rounded-card bg-foreground p-6 text-background",
1533
+ className
1534
+ ),
1535
+ ...props,
1536
+ children: [
1537
+ /* @__PURE__ */ jsx17("span", { className: "absolute top-2 left-2 h-1 w-1 rounded-full bg-background/40" }),
1538
+ /* @__PURE__ */ jsx17("span", { className: "absolute top-2 right-2 h-1 w-1 rounded-full bg-background/40" }),
1539
+ /* @__PURE__ */ jsx17("span", { className: "absolute bottom-2 left-2 h-1 w-1 rounded-full bg-background/40" }),
1540
+ /* @__PURE__ */ jsx17("span", { className: "absolute bottom-2 right-2 h-1 w-1 rounded-full bg-background/40" }),
1541
+ notched && /* @__PURE__ */ jsxs13(Fragment3, { children: [
1542
+ /* @__PURE__ */ jsx17("span", { className: "absolute left-0 top-1/2 h-5 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full bg-background" }),
1543
+ /* @__PURE__ */ jsx17("span", { className: "absolute right-0 top-1/2 h-5 w-2.5 translate-x-1/2 -translate-y-1/2 rounded-full bg-background" })
1544
+ ] }),
1545
+ /* @__PURE__ */ jsx17("div", { className: "font-display text-4xl uppercase tracking-wider", children: value }),
1546
+ /* @__PURE__ */ jsx17("div", { className: "mt-1 text-sm uppercase tracking-wider text-background/70", children: label })
1547
+ ]
1548
+ }
1549
+ );
1550
+ }
1551
+
1552
+ // src/components/testimonial-card.tsx
1553
+ import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
1554
+ function TestimonialCard({
1555
+ quote,
1556
+ author,
1557
+ role,
1558
+ avatarUrl,
1559
+ rating,
1560
+ className,
1561
+ ...props
1562
+ }) {
1563
+ return /* @__PURE__ */ jsxs14(
1564
+ "div",
1565
+ {
1566
+ className: cn(
1567
+ "rounded-card border-2 border-foreground/40 p-6",
1568
+ className
1569
+ ),
1570
+ ...props,
1571
+ children: [
1572
+ /* @__PURE__ */ jsx18("span", { className: "font-display text-4xl leading-none text-primary", "aria-hidden": "true", children: "\u201C" }),
1573
+ rating && /* @__PURE__ */ jsx18("div", { className: "mb-3 flex gap-0.5", children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx18(
1574
+ "svg",
1575
+ {
1576
+ className: cn("h-4 w-4", i < rating ? "text-primary" : "text-muted"),
1577
+ viewBox: "0 0 20 20",
1578
+ fill: "currentColor",
1579
+ children: /* @__PURE__ */ jsx18("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" })
1580
+ },
1581
+ i
1582
+ )) }),
1583
+ /* @__PURE__ */ jsx18("blockquote", { className: "text-sm leading-relaxed text-foreground", children: quote }),
1584
+ /* @__PURE__ */ jsxs14("div", { className: "mt-4 flex items-center gap-3", children: [
1585
+ avatarUrl && /* @__PURE__ */ jsx18(
1586
+ "img",
1587
+ {
1588
+ src: avatarUrl,
1589
+ alt: author,
1590
+ className: "h-10 w-10 rounded-full border-2 border-foreground/20 object-cover"
1591
+ }
1592
+ ),
1593
+ /* @__PURE__ */ jsxs14("div", { children: [
1594
+ /* @__PURE__ */ jsx18("div", { className: "text-sm font-semibold text-foreground", children: author }),
1595
+ role && /* @__PURE__ */ jsx18("div", { className: "text-xs text-muted-foreground", children: role })
1596
+ ] })
1597
+ ] })
1598
+ ]
1599
+ }
1600
+ );
1601
+ }
1602
+
1603
+ // src/components/pricing-card.tsx
1604
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
1605
+ function PricingCard({
1606
+ name,
1607
+ price,
1608
+ unit = "/mo",
1609
+ description,
1610
+ features,
1611
+ ctaLabel = "Get Started",
1612
+ ctaHref,
1613
+ onCtaClick,
1614
+ featured = false,
1615
+ badge,
1616
+ className,
1617
+ ...props
1618
+ }) {
1619
+ return /* @__PURE__ */ jsxs15(
1620
+ "div",
1621
+ {
1622
+ className: cn(
1623
+ "relative flex flex-col rounded-card border-2 p-6",
1624
+ featured ? "border-primary bg-foreground text-background" : "border-foreground/40",
1625
+ className
1626
+ ),
1627
+ ...props,
1628
+ children: [
1629
+ /* @__PURE__ */ jsxs15("div", { className: "mb-4 flex items-center justify-between", children: [
1630
+ /* @__PURE__ */ jsx19("h3", { className: "font-display text-xl uppercase tracking-wider", children: name }),
1631
+ badge && /* @__PURE__ */ jsx19(Badge, { variant: featured ? "primary" : "default", children: badge })
1632
+ ] }),
1633
+ /* @__PURE__ */ jsxs15("div", { className: "mb-4", children: [
1634
+ /* @__PURE__ */ jsx19("span", { className: "font-display text-4xl", children: price }),
1635
+ unit && /* @__PURE__ */ jsx19("span", { className: cn("text-sm", featured ? "text-background/70" : "text-muted-foreground"), children: unit })
1636
+ ] }),
1637
+ description && /* @__PURE__ */ jsx19("div", { className: cn(
1638
+ "mb-6 border-y-2 py-3 text-sm",
1639
+ featured ? "border-background/20" : "border-foreground/20"
1640
+ ), children: description }),
1641
+ /* @__PURE__ */ jsx19("ul", { className: "mb-6 flex-1 space-y-2", children: features.map((feature) => /* @__PURE__ */ jsxs15("li", { className: "flex items-start gap-2 text-sm", children: [
1642
+ /* @__PURE__ */ jsx19(
1643
+ "svg",
1644
+ {
1645
+ className: cn("mt-0.5 h-4 w-4 shrink-0", featured ? "text-primary" : "text-primary"),
1646
+ viewBox: "0 0 20 20",
1647
+ fill: "currentColor",
1648
+ children: /* @__PURE__ */ jsx19("path", { d: "M10 2l2.39 4.843L17.5 7.72l-3.75 3.657.885 5.163L10 14.058 5.365 16.54l.885-5.163L2.5 7.72l5.11-.877L10 2z" })
1649
+ }
1650
+ ),
1651
+ /* @__PURE__ */ jsx19("span", { children: feature })
1652
+ ] }, feature)) }),
1653
+ /* @__PURE__ */ jsx19(
1654
+ Button,
1655
+ {
1656
+ variant: featured ? "primary" : "secondary",
1657
+ className: "w-full",
1658
+ onClick: onCtaClick,
1659
+ ...ctaHref ? { asChild: true } : {},
1660
+ children: ctaHref ? /* @__PURE__ */ jsx19("a", { href: ctaHref, children: ctaLabel }) : ctaLabel
1661
+ }
1662
+ )
1663
+ ]
1664
+ }
1665
+ );
1666
+ }
1667
+
1668
+ // src/components/logo-grid.tsx
1669
+ import { jsx as jsx20 } from "react/jsx-runtime";
1670
+ var colsMap = {
1671
+ 3: "grid-cols-3",
1672
+ 4: "grid-cols-2 sm:grid-cols-4",
1673
+ 5: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-5",
1674
+ 6: "grid-cols-3 sm:grid-cols-6"
1675
+ };
1676
+ function LogoGrid({
1677
+ logos,
1678
+ columns = 4,
1679
+ className,
1680
+ ...props
1681
+ }) {
1682
+ return /* @__PURE__ */ jsx20(
1683
+ "div",
1684
+ {
1685
+ className: cn("grid items-center gap-8", colsMap[columns], className),
1686
+ ...props,
1687
+ children: logos.map((logo) => {
1688
+ const img = /* @__PURE__ */ jsx20(
1689
+ "img",
1690
+ {
1691
+ src: logo.src,
1692
+ alt: logo.alt,
1693
+ className: "h-10 w-auto object-contain grayscale transition-all duration-300 hover:grayscale-0 hover:scale-110"
1694
+ }
1695
+ );
1696
+ return /* @__PURE__ */ jsx20("div", { className: "flex items-center justify-center", children: logo.href ? /* @__PURE__ */ jsx20("a", { href: logo.href, target: "_blank", rel: "noopener noreferrer", children: img }) : img }, logo.alt);
1697
+ })
1698
+ }
1699
+ );
1700
+ }
1701
+
1702
+ // src/components/footer.tsx
1703
+ import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
1704
+ function Footer({
1705
+ columns,
1706
+ bottomContent,
1707
+ className,
1708
+ ...props
1709
+ }) {
1710
+ return /* @__PURE__ */ jsx21("footer", { className: cn("bg-foreground text-background", className), ...props, children: /* @__PURE__ */ jsxs16("div", { className: "mx-auto max-w-7xl px-6 py-12 lg:px-8", children: [
1711
+ /* @__PURE__ */ jsx21("div", { className: "grid gap-8 sm:grid-cols-2 lg:grid-cols-4", children: columns.map((col) => /* @__PURE__ */ jsxs16("div", { children: [
1712
+ /* @__PURE__ */ jsx21("h4", { className: "font-display text-sm uppercase tracking-wider text-background/70", children: col.heading }),
1713
+ /* @__PURE__ */ jsx21("ul", { className: "mt-3 space-y-2", children: col.links.map((link) => /* @__PURE__ */ jsx21("li", { children: /* @__PURE__ */ jsx21(
1714
+ "a",
1715
+ {
1716
+ href: link.href,
1717
+ className: "text-sm text-background/80 transition-colors hover:text-background",
1718
+ children: link.label
1719
+ }
1720
+ ) }, link.label)) })
1721
+ ] }, col.heading)) }),
1722
+ /* @__PURE__ */ jsx21("div", { className: "mt-10 border-t-2 border-background/20 pt-6", children: bottomContent ?? /* @__PURE__ */ jsxs16("p", { className: "text-xs text-background/50", children: [
1723
+ "\xA9 ",
1724
+ (/* @__PURE__ */ new Date()).getFullYear(),
1725
+ " All rights reserved."
1726
+ ] }) })
1727
+ ] }) });
1728
+ }
1729
+
1730
+ // src/components/social-card.tsx
1731
+ import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
1732
+ function SocialCard({ width = 1200, height = 630 }) {
1733
+ return /* @__PURE__ */ jsxs17(
1734
+ "div",
1735
+ {
1736
+ style: {
1737
+ width,
1738
+ height,
1739
+ background: "#0e0e0e",
1740
+ color: "#e6ddd0",
1741
+ fontFamily: "'Bebas Neue', Impact, sans-serif",
1742
+ display: "flex",
1743
+ flexDirection: "column",
1744
+ justifyContent: "space-between",
1745
+ padding: 64,
1746
+ position: "relative",
1747
+ overflow: "hidden"
1748
+ },
1749
+ children: [
1750
+ [
1751
+ { top: 24, left: 24 },
1752
+ { top: 24, right: 24 },
1753
+ { bottom: 24, left: 24 },
1754
+ { bottom: 24, right: 24 }
1755
+ ].map((pos, i) => /* @__PURE__ */ jsx22(
1756
+ "span",
1757
+ {
1758
+ style: {
1759
+ position: "absolute",
1760
+ ...pos,
1761
+ width: 6,
1762
+ height: 6,
1763
+ borderRadius: "50%",
1764
+ background: "rgba(230,221,208,0.3)"
1765
+ }
1766
+ },
1767
+ i
1768
+ )),
1769
+ /* @__PURE__ */ jsx22(
1770
+ "div",
1771
+ {
1772
+ style: {
1773
+ position: "absolute",
1774
+ inset: 16,
1775
+ border: "2px solid rgba(230,221,208,0.15)",
1776
+ borderRadius: 2,
1777
+ pointerEvents: "none"
1778
+ }
1779
+ }
1780
+ ),
1781
+ /* @__PURE__ */ jsxs17("div", { children: [
1782
+ /* @__PURE__ */ jsxs17("div", { style: { display: "flex", alignItems: "center", gap: 16, marginBottom: 48 }, children: [
1783
+ /* @__PURE__ */ jsx22(
1784
+ "div",
1785
+ {
1786
+ style: {
1787
+ width: 48,
1788
+ height: 48,
1789
+ background: "#fcd34d",
1790
+ borderRadius: 4,
1791
+ display: "flex",
1792
+ alignItems: "center",
1793
+ justifyContent: "center",
1794
+ fontSize: 28,
1795
+ lineHeight: 1
1796
+ },
1797
+ children: "\u{1F969}"
1798
+ }
1799
+ ),
1800
+ /* @__PURE__ */ jsx22(
1801
+ "span",
1802
+ {
1803
+ style: {
1804
+ fontSize: 24,
1805
+ letterSpacing: "0.1em",
1806
+ textTransform: "uppercase",
1807
+ color: "rgba(230,221,208,0.5)",
1808
+ fontFamily: "'Bebas Neue', Impact, sans-serif"
1809
+ },
1810
+ children: "Lambchop"
1811
+ }
1812
+ )
1813
+ ] }),
1814
+ /* @__PURE__ */ jsxs17(
1815
+ "h1",
1816
+ {
1817
+ style: {
1818
+ fontSize: 96,
1819
+ lineHeight: 1,
1820
+ textTransform: "uppercase",
1821
+ letterSpacing: "0.05em",
1822
+ margin: 0,
1823
+ fontWeight: 400
1824
+ },
1825
+ children: [
1826
+ "Design",
1827
+ /* @__PURE__ */ jsx22("br", {}),
1828
+ "System"
1829
+ ]
1830
+ }
1831
+ )
1832
+ ] }),
1833
+ /* @__PURE__ */ jsxs17("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-end" }, children: [
1834
+ /* @__PURE__ */ jsx22("div", { style: { display: "flex", gap: 32 }, children: [
1835
+ { value: "24", label: "Components" },
1836
+ { value: "3", label: "Font Families" },
1837
+ { value: "9", label: "Chart Colors" }
1838
+ ].map((stat) => /* @__PURE__ */ jsxs17("div", { children: [
1839
+ /* @__PURE__ */ jsx22(
1840
+ "div",
1841
+ {
1842
+ style: {
1843
+ fontSize: 40,
1844
+ letterSpacing: "0.05em",
1845
+ color: "#fcd34d",
1846
+ fontFamily: "'Bebas Neue', Impact, sans-serif"
1847
+ },
1848
+ children: stat.value
1849
+ }
1850
+ ),
1851
+ /* @__PURE__ */ jsx22(
1852
+ "div",
1853
+ {
1854
+ style: {
1855
+ fontSize: 11,
1856
+ letterSpacing: "0.15em",
1857
+ textTransform: "uppercase",
1858
+ color: "rgba(230,221,208,0.5)",
1859
+ fontFamily: "'DM Sans', sans-serif"
1860
+ },
1861
+ children: stat.label
1862
+ }
1863
+ )
1864
+ ] }, stat.label)) }),
1865
+ /* @__PURE__ */ jsx22(
1866
+ "div",
1867
+ {
1868
+ style: {
1869
+ width: 80,
1870
+ height: 4,
1871
+ background: "#fcd34d",
1872
+ borderRadius: 2
1873
+ }
1874
+ }
1875
+ )
1876
+ ] })
1877
+ ]
1878
+ }
1879
+ );
1880
+ }
1881
+
1882
+ // src/hooks/use-intersection-observer.ts
1883
+ import { useRef as useRef2, useState as useState5, useEffect as useEffect2, useCallback } from "react";
1884
+ function useIntersectionObserver({
1885
+ threshold = 0.1,
1886
+ rootMargin = "0px",
1887
+ triggerOnce = true
1888
+ } = {}) {
1889
+ const [isIntersecting, setIsIntersecting] = useState5(false);
1890
+ const elementRef = useRef2(null);
1891
+ const observerRef = useRef2(null);
1892
+ const ref = useCallback(
1893
+ (node) => {
1894
+ if (observerRef.current) {
1895
+ observerRef.current.disconnect();
1896
+ observerRef.current = null;
1897
+ }
1898
+ elementRef.current = node;
1899
+ if (!node) return;
1900
+ observerRef.current = new IntersectionObserver(
1901
+ ([entry]) => {
1902
+ if (entry.isIntersecting) {
1903
+ setIsIntersecting(true);
1904
+ if (triggerOnce && observerRef.current) {
1905
+ observerRef.current.disconnect();
1906
+ }
1907
+ } else if (!triggerOnce) {
1908
+ setIsIntersecting(false);
1909
+ }
1910
+ },
1911
+ { threshold, rootMargin }
1912
+ );
1913
+ observerRef.current.observe(node);
1914
+ },
1915
+ [threshold, rootMargin, triggerOnce]
1916
+ );
1917
+ useEffect2(() => {
1918
+ return () => {
1919
+ observerRef.current?.disconnect();
1920
+ };
1921
+ }, []);
1922
+ return { ref, isIntersecting };
1923
+ }
1924
+
1925
+ // src/components/fade-in.tsx
1926
+ import { jsx as jsx23 } from "react/jsx-runtime";
1927
+ var directionMap = {
1928
+ up: "animate-fade-in-up",
1929
+ down: "animate-fade-in-down",
1930
+ left: "animate-fade-in-left",
1931
+ right: "animate-fade-in-right"
1932
+ };
1933
+ function FadeIn({
1934
+ direction = "up",
1935
+ delay = 0,
1936
+ className,
1937
+ children,
1938
+ ...props
1939
+ }) {
1940
+ const { ref, isIntersecting } = useIntersectionObserver({ triggerOnce: true });
1941
+ return /* @__PURE__ */ jsx23(
1942
+ "div",
1943
+ {
1944
+ ref,
1945
+ className: cn(
1946
+ isIntersecting ? directionMap[direction] : "opacity-0",
1947
+ className
1948
+ ),
1949
+ style: delay ? { animationDelay: `${delay}ms` } : void 0,
1950
+ ...props,
1951
+ children
1952
+ }
1953
+ );
1954
+ }
1955
+
1956
+ // src/components/scale-in.tsx
1957
+ import { jsx as jsx24 } from "react/jsx-runtime";
1958
+ function ScaleIn({
1959
+ delay = 0,
1960
+ className,
1961
+ children,
1962
+ ...props
1963
+ }) {
1964
+ const { ref, isIntersecting } = useIntersectionObserver({ triggerOnce: true });
1965
+ return /* @__PURE__ */ jsx24(
1966
+ "div",
1967
+ {
1968
+ ref,
1969
+ className: cn(
1970
+ isIntersecting ? "animate-scale-in" : "opacity-0",
1971
+ className
1972
+ ),
1973
+ style: delay ? { animationDelay: `${delay}ms` } : void 0,
1974
+ ...props,
1975
+ children
1976
+ }
1977
+ );
1978
+ }
1979
+
1980
+ // src/components/stagger-container.tsx
1981
+ import * as React6 from "react";
1982
+ import { jsx as jsx25 } from "react/jsx-runtime";
1983
+ function StaggerContainer({
1984
+ stagger = 100,
1985
+ className,
1986
+ children,
1987
+ ...props
1988
+ }) {
1989
+ const { ref, isIntersecting } = useIntersectionObserver({ triggerOnce: true });
1990
+ return /* @__PURE__ */ jsx25("div", { ref, className: cn(className), ...props, children: React6.Children.map(children, (child, index) => {
1991
+ if (!React6.isValidElement(child)) return child;
1992
+ return React6.cloneElement(child, {
1993
+ style: {
1994
+ ...child.props.style,
1995
+ transitionDelay: `${index * stagger}ms`,
1996
+ opacity: isIntersecting ? 1 : 0,
1997
+ transform: isIntersecting ? "translateY(0)" : "translateY(1rem)",
1998
+ transition: `opacity 0.5s ease-out, transform 0.5s ease-out`
1999
+ }
2000
+ });
2001
+ }) });
2002
+ }
2003
+
2004
+ // src/hooks/use-time-range.ts
2005
+ import { useState as useState6, useMemo, useCallback as useCallback2 } from "react";
2006
+ import {
2007
+ startOfMonth as startOfMonth2,
2008
+ endOfMonth as endOfMonth2,
2009
+ subMonths as subMonths2,
2010
+ subDays as subDays2,
2011
+ startOfYear as startOfYear2,
2012
+ format as format2
2013
+ } from "date-fns";
2014
+ function resolvePreset2(preset) {
2015
+ const now = /* @__PURE__ */ new Date();
2016
+ switch (preset) {
2017
+ case "mtd":
2018
+ return { start: startOfMonth2(now), end: now };
2019
+ case "last-month": {
2020
+ const prev = subMonths2(now, 1);
2021
+ return { start: startOfMonth2(prev), end: endOfMonth2(prev) };
2022
+ }
2023
+ case "last-30":
2024
+ return { start: subDays2(now, 30), end: now };
2025
+ case "last-90":
2026
+ return { start: subDays2(now, 90), end: now };
2027
+ case "ytd":
2028
+ return { start: startOfYear2(now), end: now };
2029
+ case "custom":
2030
+ return { start: subDays2(now, 30), end: now };
2031
+ }
2032
+ }
2033
+ function useTimeRange(initialPreset = "mtd") {
2034
+ const [preset, setPresetState] = useState6(initialPreset);
2035
+ const [customRange, setCustomRange] = useState6(null);
2036
+ const range = useMemo(() => {
2037
+ if (preset === "custom" && customRange) {
2038
+ return { ...customRange, preset };
2039
+ }
2040
+ return { ...resolvePreset2(preset), preset };
2041
+ }, [preset, customRange]);
2042
+ const setPreset = useCallback2((p) => {
2043
+ setPresetState(p);
2044
+ if (p !== "custom") setCustomRange(null);
2045
+ }, []);
2046
+ const setCustom = useCallback2((start, end) => {
2047
+ setPresetState("custom");
2048
+ setCustomRange({ start, end });
2049
+ }, []);
2050
+ const formatted = useMemo(
2051
+ () => ({
2052
+ start: format2(range.start, "yyyy-MM-dd"),
2053
+ end: format2(range.end, "yyyy-MM-dd")
2054
+ }),
2055
+ [range]
2056
+ );
2057
+ return { range, preset, setPreset, setCustom, formatted };
2058
+ }
2059
+
2060
+ // src/hooks/use-table-sort.ts
2061
+ import { useState as useState7, useCallback as useCallback3 } from "react";
2062
+ function useTableSort(initialSort = []) {
2063
+ const [sorting, setSorting] = useState7(initialSort);
2064
+ const toggleSort = useCallback3((columnId) => {
2065
+ setSorting((prev) => {
2066
+ const existing = prev.find((s) => s.id === columnId);
2067
+ if (!existing) return [{ id: columnId, desc: true }];
2068
+ if (existing.desc) return [{ id: columnId, desc: false }];
2069
+ return [];
2070
+ });
2071
+ }, []);
2072
+ return { sorting, setSorting, toggleSort };
2073
+ }
2074
+ export {
2075
+ AreaChart,
2076
+ Badge,
2077
+ BarChart,
2078
+ Button,
2079
+ Card,
2080
+ ComparisonRow,
2081
+ DataTable,
2082
+ DateRangePicker,
2083
+ FadeIn,
2084
+ FilterBar,
2085
+ Footer,
2086
+ KpiCard,
2087
+ LineChart,
2088
+ LogoGrid,
2089
+ MetricTrend,
2090
+ PageHeader,
2091
+ PricingCard,
2092
+ ScaleIn,
2093
+ Section,
2094
+ SidebarNav,
2095
+ SocialCard,
2096
+ Sparkline,
2097
+ StaggerContainer,
2098
+ StatCard,
2099
+ TestimonialCard,
2100
+ cn,
2101
+ useChartColors,
2102
+ useIntersectionObserver,
2103
+ useTableSort,
2104
+ useTimeRange
2105
+ };
2106
+ //# sourceMappingURL=index.js.map