@olwiba/ui 0.1.4 → 0.1.7

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 CHANGED
@@ -1,13 +1,13 @@
1
1
  import { cn } from './chunk-AMWLSHD6.js';
2
2
  export { MdxContent, cn } from './chunk-AMWLSHD6.js';
3
- import * as React26 from 'react';
4
- import { useState, useEffect } from 'react';
5
- import { Button as Button$1, Card as Card$1, Input as Input$1, Textarea as Textarea$1, Checkbox as Checkbox$1, Switch as Switch$1, useIsMobile, UIVariantProvider, Badge as Badge$1, cn as cn$1, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Avatar, AvatarImage, AvatarFallback, useUIVariant, Separator, Accordion, AccordionItem, AccordionTrigger, AccordionContent, Label, Sheet, SheetTrigger, SheetContent, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandSeparator, CommandGroup, CommandItem, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, ContextMenu as ContextMenu$1, ContextMenuTrigger, ContextMenuContent, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Spinner, SidebarProvider, SidebarInset, CardHeader, CardTitle, CardDescription, CardContent, ContextMenuSeparator, ContextMenuLabel, ContextMenuSub, ContextMenuSubTrigger, ContextMenuSubContent, ContextMenuItem, ContextMenuShortcut, Sidebar, SidebarHeader, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarFooter, SidebarTrigger, useSidebar, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuGroup, DropdownMenuItem } from '@olwiba/cn';
3
+ import * as React29 from 'react';
4
+ import { useRef, useEffect, useState } from 'react';
5
+ import { Button as Button$1, Card as Card$1, Input as Input$1, Textarea as Textarea$1, Checkbox as Checkbox$1, Switch as Switch$1, useIsMobile, UIVariantProvider, Badge as Badge$1, cn as cn$1, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Avatar, AvatarImage, AvatarFallback, useUIVariant, Separator, Accordion, AccordionItem, AccordionTrigger, AccordionContent, Label, Sheet, SheetTrigger, SheetContent, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandSeparator, CommandGroup, CommandItem, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, ContextMenu as ContextMenu$1, ContextMenuTrigger, ContextMenuContent, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Spinner, Popover, PopoverTrigger, PopoverContent, SidebarProvider, SidebarInset, CardHeader, CardTitle, CardDescription, CardContent, ContextMenuSeparator, ContextMenuLabel, ContextMenuSub, ContextMenuSubTrigger, ContextMenuSubContent, ContextMenuItem, ContextMenuShortcut, Sidebar, SidebarHeader, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarFooter, SidebarTrigger, useSidebar, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuGroup, DropdownMenuItem } from '@olwiba/cn';
6
6
  export { CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@olwiba/cn';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
- import { Compass, ArrowLeft, X, ArrowRight, ChevronLeft, ChevronRight, Sparkles, Check, Minus, Quote, Star, Twitter, Github, Linkedin, Mail, Phone, MapPin, MessageSquare, Send, Menu, Search, TrendingUp, TrendingDown, Sun, Moon, AlertTriangle, Loader2, Layers, LayoutGrid, ShieldCheck, Building2, MoreVerticalIcon, CreditCardIcon, BellIcon, LogOutIcon } from 'lucide-react';
8
+ import { Compass, ArrowLeft, X, ArrowRight, ChevronLeft, ChevronRight, Sparkles, Rocket, Check, Minus, Quote, Star, Twitter, Github, Linkedin, Mail, MapPin, MessageSquare, Send, Menu, Search, TrendingUp, TrendingDown, Sun, Moon, Palette, AlertTriangle, Loader2, Layers, LayoutGrid, ShieldCheck, Building2, MoreVerticalIcon, CreditCardIcon, BellIcon, LogOutIcon } from 'lucide-react';
9
9
 
10
- var OlwibaUIContext = React26.createContext({
10
+ var OlwibaUIContext = React29.createContext({
11
11
  isMobile: false,
12
12
  mode: "default",
13
13
  setMode: () => {
@@ -16,17 +16,17 @@ var OlwibaUIContext = React26.createContext({
16
16
  function OlwibaUIProvider({ children, isMobile: isMobileProp, mode: initialMode = "default" }) {
17
17
  const detectedMobile = useIsMobile();
18
18
  const isMobile = isMobileProp ?? detectedMobile;
19
- const [mode, setMode] = React26.useState(initialMode);
19
+ const [mode, setMode] = React29.useState(initialMode);
20
20
  const variant = mode !== "default" ? mode : void 0;
21
21
  return /* @__PURE__ */ jsx(OlwibaUIContext.Provider, { value: { isMobile, mode, setMode }, children: /* @__PURE__ */ jsx(UIVariantProvider, { mode: variant, children }) });
22
22
  }
23
23
  function useOlwibaUI() {
24
- return React26.useContext(OlwibaUIContext);
24
+ return React29.useContext(OlwibaUIContext);
25
25
  }
26
26
  function useUIMode() {
27
- return React26.useContext(OlwibaUIContext).mode;
27
+ return React29.useContext(OlwibaUIContext).mode;
28
28
  }
29
- var Button = React26.forwardRef(
29
+ var Button = React29.forwardRef(
30
30
  ({ mode, ...props }, ref) => {
31
31
  const ctxMode = useUIMode();
32
32
  const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
@@ -34,7 +34,7 @@ var Button = React26.forwardRef(
34
34
  }
35
35
  );
36
36
  Button.displayName = "Button";
37
- var Card = React26.forwardRef(
37
+ var Card = React29.forwardRef(
38
38
  ({ mode, ...props }, ref) => {
39
39
  const ctxMode = useUIMode();
40
40
  const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
@@ -45,7 +45,7 @@ Card.displayName = "Card";
45
45
  function Badge(props) {
46
46
  return /* @__PURE__ */ jsx(Badge$1, { ...props });
47
47
  }
48
- var Input = React26.forwardRef(
48
+ var Input = React29.forwardRef(
49
49
  ({ mode, ...props }, ref) => {
50
50
  const ctxMode = useUIMode();
51
51
  const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
@@ -53,7 +53,7 @@ var Input = React26.forwardRef(
53
53
  }
54
54
  );
55
55
  Input.displayName = "Input";
56
- var Textarea = React26.forwardRef(
56
+ var Textarea = React29.forwardRef(
57
57
  ({ mode, ...props }, ref) => {
58
58
  const ctxMode = useUIMode();
59
59
  const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
@@ -61,13 +61,13 @@ var Textarea = React26.forwardRef(
61
61
  }
62
62
  );
63
63
  Textarea.displayName = "Textarea";
64
- var Checkbox = React26.forwardRef(({ mode, ...props }, ref) => {
64
+ var Checkbox = React29.forwardRef(({ mode, ...props }, ref) => {
65
65
  const ctxMode = useUIMode();
66
66
  const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
67
67
  return /* @__PURE__ */ jsx(Checkbox$1, { mode: resolvedMode, ...props, ref });
68
68
  });
69
69
  Checkbox.displayName = "Checkbox";
70
- var Switch = React26.forwardRef(({ mode: _mode, ...props }, ref) => {
70
+ var Switch = React29.forwardRef(({ mode: _mode, ...props }, ref) => {
71
71
  return /* @__PURE__ */ jsx(Switch$1, { ...props, ref });
72
72
  });
73
73
  Switch.displayName = "Switch";
@@ -490,10 +490,15 @@ function DefaultForm({
490
490
  error,
491
491
  loading,
492
492
  renderLink = defaultRenderLink2,
493
- footer
493
+ footer,
494
+ defaultEmail,
495
+ defaultPassword
494
496
  }) {
495
497
  const isSignUp = mode === "signup";
498
+ const hasPrefill = !!(defaultEmail || defaultPassword);
499
+ const prefillStyle = (active) => active ? { animation: "auth-prefill 1.6s ease-out 0.35s 1 both" } : void 0;
496
500
  return /* @__PURE__ */ jsxs(Card, { className: "w-full", children: [
501
+ hasPrefill && /* @__PURE__ */ jsx("style", { children: `@keyframes auth-prefill{0%{box-shadow:0 0 0 0 hsl(var(--primary)/0)}40%{box-shadow:0 0 0 3px hsl(var(--primary)/0.4)}100%{box-shadow:0 0 0 0 hsl(var(--primary)/0)}}` }),
497
502
  /* @__PURE__ */ jsxs(CardHeader, { children: [
498
503
  brand && /* @__PURE__ */ jsx("div", { className: "mb-2", children: brand }),
499
504
  /* @__PURE__ */ jsx(CardTitle, { children: isSignUp ? "Create an account" : "Sign in" }),
@@ -507,7 +512,18 @@ function DefaultForm({
507
512
  ] }),
508
513
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
509
514
  /* @__PURE__ */ jsx(Label, { htmlFor: "auth-email", children: "Email address" }),
510
- /* @__PURE__ */ jsx(Input, { id: "auth-email", name: "email", type: "email", placeholder: "name@company.com", autoComplete: "email" })
515
+ /* @__PURE__ */ jsx(
516
+ Input,
517
+ {
518
+ id: "auth-email",
519
+ name: "email",
520
+ type: "email",
521
+ placeholder: "name@company.com",
522
+ autoComplete: "email",
523
+ defaultValue: defaultEmail,
524
+ style: prefillStyle(!!defaultEmail)
525
+ }
526
+ )
511
527
  ] }),
512
528
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
513
529
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
@@ -525,7 +541,9 @@ function DefaultForm({
525
541
  name: "password",
526
542
  type: "password",
527
543
  placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
528
- autoComplete: isSignUp ? "new-password" : "current-password"
544
+ autoComplete: isSignUp ? "new-password" : "current-password",
545
+ defaultValue: defaultPassword,
546
+ style: prefillStyle(!!defaultPassword)
529
547
  }
530
548
  )
531
549
  ] }),
@@ -757,9 +775,9 @@ function FadeIn({
757
775
  style,
758
776
  ...props
759
777
  }) {
760
- const ref = React26.useRef(null);
761
- const [visible, setVisible] = React26.useState(false);
762
- React26.useEffect(() => {
778
+ const ref = React29.useRef(null);
779
+ const [visible, setVisible] = React29.useState(false);
780
+ React29.useEffect(() => {
763
781
  const el = ref.current;
764
782
  if (!el) return;
765
783
  const observer = new IntersectionObserver(
@@ -956,9 +974,9 @@ function StaggerChildren({
956
974
  className,
957
975
  ...props
958
976
  }) {
959
- const ref = React26.useRef(null);
960
- const [visible, setVisible] = React26.useState(false);
961
- React26.useEffect(() => {
977
+ const ref = React29.useRef(null);
978
+ const [visible, setVisible] = React29.useState(false);
979
+ React29.useEffect(() => {
962
980
  const el = ref.current;
963
981
  if (!el) return;
964
982
  const observer = new IntersectionObserver(
@@ -976,7 +994,7 @@ function StaggerChildren({
976
994
  return () => observer.disconnect();
977
995
  }, [once]);
978
996
  const [tx, ty] = translateMap2[direction];
979
- return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React26.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
997
+ return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React29.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
980
998
  "div",
981
999
  {
982
1000
  className: "h-full",
@@ -1017,6 +1035,133 @@ function FeaturesSection({
1017
1035
  )) })
1018
1036
  ] }) }) });
1019
1037
  }
1038
+ function GroupedFeaturesSection({
1039
+ badge = "Features",
1040
+ title = "Everything you need to ship",
1041
+ description,
1042
+ groups
1043
+ }) {
1044
+ const mode = useUIVariant();
1045
+ const sectionClasses = cn$1(
1046
+ "overflow-hidden bg-card",
1047
+ mode === "smooth" && "rounded-3xl border",
1048
+ mode === "playful" && "rounded-2xl border-primary/25 border",
1049
+ !mode && "rounded-2xl border"
1050
+ );
1051
+ return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
1052
+ /* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
1053
+ /* @__PURE__ */ jsx("div", { className: "mt-14 space-y-14", children: groups.map((group, i) => /* @__PURE__ */ jsxs("div", { children: [
1054
+ /* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: i * 60, children: /* @__PURE__ */ jsxs("div", { className: "mb-6 flex items-center gap-3", children: [
1055
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold tracking-wide text-muted-foreground uppercase", children: group.label }),
1056
+ /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-border" })
1057
+ ] }) }),
1058
+ /* @__PURE__ */ jsx(StaggerChildren, { className: "grid gap-6 sm:grid-cols-2 lg:grid-cols-3", children: group.features.map((feature) => /* @__PURE__ */ jsx(
1059
+ FeatureCard,
1060
+ {
1061
+ icon: feature.icon,
1062
+ title: feature.title,
1063
+ description: feature.description,
1064
+ href: feature.href
1065
+ },
1066
+ feature.title
1067
+ )) })
1068
+ ] }, group.label)) })
1069
+ ] }) }) });
1070
+ }
1071
+ function StepsSection({
1072
+ badge = "How it works",
1073
+ title = "From zero to shipped",
1074
+ description,
1075
+ steps
1076
+ }) {
1077
+ const mode = useUIVariant();
1078
+ const sectionClasses = cn$1(
1079
+ "overflow-hidden bg-card",
1080
+ mode === "smooth" && "rounded-3xl border",
1081
+ mode === "playful" && "rounded-2xl border-primary/25 border",
1082
+ !mode && "rounded-2xl border"
1083
+ );
1084
+ return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
1085
+ /* @__PURE__ */ jsx(SectionTitle, { badge, title, description }),
1086
+ /* @__PURE__ */ jsxs("div", { className: "mt-12", children: [
1087
+ /* @__PURE__ */ jsx("div", { className: "hidden sm:grid", style: { gridTemplateColumns: `repeat(${steps.length}, 1fr)` }, children: steps.map((step, i) => /* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: i * 80, children: /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col items-center text-center px-4", children: [
1088
+ i < steps.length - 1 && /* @__PURE__ */ jsx(
1089
+ "div",
1090
+ {
1091
+ "aria-hidden": "true",
1092
+ className: "absolute top-6 left-1/2 w-full border-t border-dashed border-border"
1093
+ }
1094
+ ),
1095
+ /* @__PURE__ */ jsx("div", { className: "relative z-10 mb-3 flex h-12 w-12 items-center justify-center rounded-full bg-muted text-2xl", children: step.emoji ?? /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-primary", children: i + 1 }) }),
1096
+ /* @__PURE__ */ jsx("h3", { className: "font-semibold text-foreground", children: step.title }),
1097
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-relaxed text-muted-foreground", children: step.description })
1098
+ ] }) }, step.title)) }),
1099
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0 sm:hidden", children: steps.map((step, i) => /* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: i * 80, children: /* @__PURE__ */ jsxs("div", { className: "relative flex gap-4 pb-8 last:pb-0", children: [
1100
+ i < steps.length - 1 && /* @__PURE__ */ jsx(
1101
+ "div",
1102
+ {
1103
+ "aria-hidden": "true",
1104
+ className: "absolute left-[23px] top-14 bottom-0 w-px border-l border-dashed border-border"
1105
+ }
1106
+ ),
1107
+ /* @__PURE__ */ jsx("div", { className: "relative z-10 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-muted text-2xl", children: step.emoji ?? /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-primary", children: i + 1 }) }),
1108
+ /* @__PURE__ */ jsxs("div", { className: "pt-3", children: [
1109
+ /* @__PURE__ */ jsx("h3", { className: "font-semibold text-foreground", children: step.title }),
1110
+ /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: step.description })
1111
+ ] })
1112
+ ] }) }, step.title)) })
1113
+ ] })
1114
+ ] }) }) });
1115
+ }
1116
+ function TechStackSection({
1117
+ badge = "Built on",
1118
+ title = "The stack",
1119
+ description,
1120
+ items
1121
+ }) {
1122
+ const mode = useUIVariant();
1123
+ const sectionClasses = cn$1(
1124
+ "overflow-hidden bg-card",
1125
+ mode === "smooth" && "rounded-3xl border",
1126
+ mode === "playful" && "rounded-2xl border-primary/25 border",
1127
+ !mode && "rounded-2xl border"
1128
+ );
1129
+ return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
1130
+ /* @__PURE__ */ jsx(SectionTitle, { badge, title, description }),
1131
+ /* @__PURE__ */ jsx(StaggerChildren, { className: "mt-12 grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: items.map((item) => {
1132
+ const Icon = item.icon;
1133
+ const card = /* @__PURE__ */ jsxs(
1134
+ "div",
1135
+ {
1136
+ className: cn$1(
1137
+ "group flex flex-col gap-3 border bg-background p-5 transition-all duration-200",
1138
+ mode === "smooth" ? "rounded-2xl hover:-translate-y-0.5 hover:shadow-md" : "rounded-xl hover:-translate-y-0.5 hover:shadow-md"
1139
+ ),
1140
+ children: [
1141
+ /* @__PURE__ */ jsx(
1142
+ "div",
1143
+ {
1144
+ className: cn$1(
1145
+ "flex h-9 w-9 items-center justify-center bg-muted text-muted-foreground transition-colors group-hover:bg-primary/10 group-hover:text-primary",
1146
+ mode === "smooth" ? "rounded-xl" : "rounded-lg"
1147
+ ),
1148
+ children: /* @__PURE__ */ jsx(Icon, { className: "size-4" })
1149
+ }
1150
+ ),
1151
+ /* @__PURE__ */ jsxs("div", { children: [
1152
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold leading-tight", children: item.name }),
1153
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: item.description })
1154
+ ] })
1155
+ ]
1156
+ }
1157
+ );
1158
+ if (item.href) {
1159
+ return /* @__PURE__ */ jsx("a", { href: item.href, className: "block", children: card }, item.name);
1160
+ }
1161
+ return /* @__PURE__ */ jsx("div", { children: card }, item.name);
1162
+ }) })
1163
+ ] }) }) });
1164
+ }
1020
1165
  function CarouselSection({
1021
1166
  title = "Explore the platform",
1022
1167
  description,
@@ -1024,16 +1169,16 @@ function CarouselSection({
1024
1169
  features
1025
1170
  }) {
1026
1171
  const mode = useUIVariant();
1027
- const trackRef = React26.useRef(null);
1028
- const [canPrev, setCanPrev] = React26.useState(false);
1029
- const [canNext, setCanNext] = React26.useState(true);
1030
- const updateScrollState = React26.useCallback(() => {
1172
+ const trackRef = React29.useRef(null);
1173
+ const [canPrev, setCanPrev] = React29.useState(false);
1174
+ const [canNext, setCanNext] = React29.useState(true);
1175
+ const updateScrollState = React29.useCallback(() => {
1031
1176
  const track = trackRef.current;
1032
1177
  if (!track) return;
1033
1178
  setCanPrev(track.scrollLeft > 8);
1034
1179
  setCanNext(track.scrollLeft < track.scrollWidth - track.clientWidth - 8);
1035
1180
  }, []);
1036
- React26.useEffect(() => {
1181
+ React29.useEffect(() => {
1037
1182
  const track = trackRef.current;
1038
1183
  if (!track) return;
1039
1184
  updateScrollState();
@@ -1117,6 +1262,83 @@ function CarouselSection({
1117
1262
  ] })
1118
1263
  ] }) }) });
1119
1264
  }
1265
+ var speedDuration = {
1266
+ slow: "280s",
1267
+ normal: "180s",
1268
+ fast: "100s"
1269
+ };
1270
+ function FeatureMarqueeSection({
1271
+ badge,
1272
+ title,
1273
+ description,
1274
+ rows,
1275
+ speed = "normal",
1276
+ pauseOnHover = true
1277
+ }) {
1278
+ const mode = useUIVariant();
1279
+ const duration = speedDuration[speed];
1280
+ const sectionClasses = cn$1(
1281
+ "overflow-hidden bg-card",
1282
+ mode === "smooth" && "rounded-3xl border",
1283
+ mode === "playful" && "rounded-2xl border-primary/25 border",
1284
+ !mode && "rounded-2xl border"
1285
+ );
1286
+ return /* @__PURE__ */ jsxs("section", { className: sectionClasses, children: [
1287
+ /* @__PURE__ */ jsxs("div", { className: "py-14 sm:py-20", children: [
1288
+ (title || badge || description) && /* @__PURE__ */ jsx(FadeIn, { direction: "up", children: /* @__PURE__ */ jsx("div", { className: "mx-auto mb-10 max-w-4xl px-6 sm:px-10", children: /* @__PURE__ */ jsx(SectionTitle, { title: title ?? "", description, badge }) }) }),
1289
+ /* @__PURE__ */ jsx("div", { className: "space-y-3", children: rows.map((row, i) => {
1290
+ const direction = row.direction ?? (i % 2 === 0 ? "left" : "right");
1291
+ const reversed = direction === "right";
1292
+ const source = reversed ? [...row.items].reverse() : row.items;
1293
+ const set = Array.from({ length: 4 }, () => source).flat();
1294
+ const items = [...set, ...set];
1295
+ return /* @__PURE__ */ jsx(
1296
+ "div",
1297
+ {
1298
+ className: "group relative overflow-hidden",
1299
+ style: {
1300
+ maskImage: "linear-gradient(to right, transparent, black 8%, black 92%, transparent)",
1301
+ WebkitMaskImage: "linear-gradient(to right, transparent, black 8%, black 92%, transparent)"
1302
+ },
1303
+ children: /* @__PURE__ */ jsx(
1304
+ "div",
1305
+ {
1306
+ className: cn$1(
1307
+ "flex w-max gap-3 py-0.5",
1308
+ pauseOnHover && "group-hover:[animation-play-state:paused]"
1309
+ ),
1310
+ style: {
1311
+ animation: `feature-marquee-left ${duration} linear infinite`
1312
+ },
1313
+ children: items.map((item, j) => {
1314
+ const Icon = item.icon;
1315
+ return /* @__PURE__ */ jsxs(
1316
+ "div",
1317
+ {
1318
+ className: "flex shrink-0 items-center gap-2 rounded-full border bg-background px-4 py-2 text-sm shadow-sm",
1319
+ children: [
1320
+ /* @__PURE__ */ jsx(Icon, { className: "size-3.5 shrink-0 text-primary" }),
1321
+ /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap text-foreground", children: item.title })
1322
+ ]
1323
+ },
1324
+ `${item.title}-${j}`
1325
+ );
1326
+ })
1327
+ }
1328
+ )
1329
+ },
1330
+ i
1331
+ );
1332
+ }) })
1333
+ ] }),
1334
+ /* @__PURE__ */ jsx("style", { children: `
1335
+ @keyframes feature-marquee-left {
1336
+ from { transform: translateX(0); }
1337
+ to { transform: translateX(-50%); }
1338
+ }
1339
+ ` })
1340
+ ] });
1341
+ }
1120
1342
  var defaultRenderLink5 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
1121
1343
  function CtaSection({
1122
1344
  heading,
@@ -1156,6 +1378,71 @@ function CtaSection({
1156
1378
  ] }) })
1157
1379
  ] }) });
1158
1380
  }
1381
+ var defaultRenderLink6 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
1382
+ function CtaCardSection({
1383
+ heading,
1384
+ description,
1385
+ primaryCta,
1386
+ footnote,
1387
+ icon,
1388
+ renderLink = defaultRenderLink6
1389
+ }) {
1390
+ const ref = React29.useRef(null);
1391
+ const [visible, setVisible] = React29.useState(false);
1392
+ React29.useEffect(() => {
1393
+ const el = ref.current;
1394
+ if (!el) return;
1395
+ const observer = new IntersectionObserver(
1396
+ ([entry]) => {
1397
+ if (entry.isIntersecting) {
1398
+ setVisible(true);
1399
+ observer.disconnect();
1400
+ }
1401
+ },
1402
+ { threshold: 0.15 }
1403
+ );
1404
+ observer.observe(el);
1405
+ return () => observer.disconnect();
1406
+ }, []);
1407
+ return /* @__PURE__ */ jsxs(
1408
+ "section",
1409
+ {
1410
+ ref,
1411
+ className: cn$1(
1412
+ "relative overflow-hidden rounded-3xl border border-gray-200 shadow-sm dark:border-border",
1413
+ "bg-[#E0DFDB] dark:bg-card",
1414
+ "transition-[opacity,transform] duration-700 ease-out",
1415
+ visible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-6"
1416
+ ),
1417
+ children: [
1418
+ /* @__PURE__ */ jsx(
1419
+ "div",
1420
+ {
1421
+ className: "pointer-events-none absolute inset-0 flex items-center justify-center",
1422
+ style: {
1423
+ opacity: visible ? 0.12 : 0,
1424
+ transform: visible ? "scale(1) rotate(0deg)" : "scale(0.9) rotate(-5deg)",
1425
+ transition: "opacity 700ms ease 200ms, transform 700ms ease 200ms"
1426
+ },
1427
+ children: icon ?? /* @__PURE__ */ jsx(Rocket, { className: "size-72 text-foreground dark:text-foreground", strokeWidth: 0.75 })
1428
+ }
1429
+ ),
1430
+ /* @__PURE__ */ jsxs("div", { className: "relative z-10 px-6 py-20 text-center sm:px-10 sm:py-28", children: [
1431
+ /* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: heading }),
1432
+ description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-lg text-pretty text-muted-foreground", children: description }),
1433
+ /* @__PURE__ */ jsx("div", { className: "mt-8", children: renderLink({
1434
+ href: primaryCta.href,
1435
+ children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2 rounded-full bg-foreground px-6 py-3 text-sm font-medium text-background transition-opacity hover:opacity-80", children: [
1436
+ primaryCta.label,
1437
+ /* @__PURE__ */ jsx(ArrowRight, { className: "size-4" })
1438
+ ] })
1439
+ }) }),
1440
+ footnote && /* @__PURE__ */ jsx("p", { className: "mt-5 text-sm text-muted-foreground", children: footnote })
1441
+ ] })
1442
+ ]
1443
+ }
1444
+ );
1445
+ }
1159
1446
  function PricingCard({
1160
1447
  name,
1161
1448
  price,
@@ -1164,6 +1451,7 @@ function PricingCard({
1164
1451
  features,
1165
1452
  cta,
1166
1453
  highlighted = false,
1454
+ disabled = false,
1167
1455
  badge,
1168
1456
  onSelect,
1169
1457
  className,
@@ -1174,14 +1462,15 @@ function PricingCard({
1174
1462
  "div",
1175
1463
  {
1176
1464
  className: cn$1(
1177
- "relative flex flex-col border p-6",
1465
+ "relative flex flex-col border p-6 transition-opacity",
1178
1466
  mode === "playful" ? "rounded-2xl rotate-[0.3deg]" : mode === "smooth" ? "rounded-3xl" : "rounded-2xl",
1179
1467
  highlighted ? "border-primary bg-primary/5 shadow-sm" : "bg-card",
1468
+ disabled && "pointer-events-none opacity-40 select-none",
1180
1469
  mode !== "playful" && className
1181
1470
  ),
1182
1471
  ...mode !== "playful" ? props : {},
1183
1472
  children: [
1184
- badge && /* @__PURE__ */ jsx("div", { className: "absolute -top-3 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ jsx(Badge$1, { children: badge }) }),
1473
+ badge && /* @__PURE__ */ jsx("div", { className: "absolute -top-3 left-1/2 -translate-x-1/2", children: typeof badge === "string" ? /* @__PURE__ */ jsx(Badge$1, { children: badge }) : badge }),
1185
1474
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1186
1475
  /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-muted-foreground", children: name }),
1187
1476
  /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-1", children: [
@@ -1196,6 +1485,7 @@ function PricingCard({
1196
1485
  variant: highlighted ? "default" : "outline",
1197
1486
  className: "mt-6 w-full",
1198
1487
  onClick: onSelect,
1488
+ disabled,
1199
1489
  children: cta
1200
1490
  }
1201
1491
  ),
@@ -1227,7 +1517,59 @@ function PricingCard({
1227
1517
  }
1228
1518
  return cardInner;
1229
1519
  }
1230
- var defaultRenderLink6 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
1520
+ function getTimeLeft(deadline) {
1521
+ const diff = new Date(deadline).getTime() - Date.now();
1522
+ if (diff <= 0) return null;
1523
+ return {
1524
+ days: Math.floor(diff / (1e3 * 60 * 60 * 24)),
1525
+ hours: Math.floor(diff / (1e3 * 60 * 60) % 24),
1526
+ minutes: Math.floor(diff / 1e3 / 60 % 60),
1527
+ seconds: Math.floor(diff / 1e3 % 60)
1528
+ };
1529
+ }
1530
+ function CountdownTimer({
1531
+ deadline,
1532
+ label = "Founding price closes in",
1533
+ className,
1534
+ compact = false
1535
+ }) {
1536
+ const [timeLeft, setTimeLeft] = React29.useState(() => getTimeLeft(deadline));
1537
+ React29.useEffect(() => {
1538
+ setTimeLeft(getTimeLeft(deadline));
1539
+ const id = setInterval(() => setTimeLeft(getTimeLeft(deadline)), 1e3);
1540
+ return () => clearInterval(id);
1541
+ }, [deadline]);
1542
+ if (!timeLeft) return null;
1543
+ if (compact) {
1544
+ return /* @__PURE__ */ jsxs("span", { className: cn$1("font-mono tabular-nums", className), children: [
1545
+ timeLeft.days,
1546
+ "d \xB7 ",
1547
+ String(timeLeft.hours).padStart(2, "0"),
1548
+ "h \xB7 ",
1549
+ String(timeLeft.minutes).padStart(2, "0"),
1550
+ "m \xB7 ",
1551
+ String(timeLeft.seconds).padStart(2, "0"),
1552
+ "s"
1553
+ ] });
1554
+ }
1555
+ const units = [
1556
+ { value: timeLeft.days, unit: "d" },
1557
+ { value: timeLeft.hours, unit: "h" },
1558
+ { value: timeLeft.minutes, unit: "m" },
1559
+ { value: timeLeft.seconds, unit: "s" }
1560
+ ];
1561
+ return /* @__PURE__ */ jsxs("div", { className: cn$1("flex items-center justify-center gap-2 text-sm", className), children: [
1562
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
1563
+ /* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 font-mono font-semibold tabular-nums", children: units.map(({ value, unit }, i) => /* @__PURE__ */ jsxs(React29.Fragment, { children: [
1564
+ /* @__PURE__ */ jsxs("span", { children: [
1565
+ String(value).padStart(2, "0"),
1566
+ /* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: unit })
1567
+ ] }),
1568
+ i < units.length - 1 && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/50", children: "\xB7" })
1569
+ ] }, unit)) })
1570
+ ] });
1571
+ }
1572
+ var defaultRenderLink7 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
1231
1573
  function PricingSection({
1232
1574
  title = "Simple, transparent pricing",
1233
1575
  description = "Start for free. Scale as you grow. No hidden fees.",
@@ -1235,23 +1577,26 @@ function PricingSection({
1235
1577
  plans,
1236
1578
  saveBadge = "Save 34%",
1237
1579
  isAuthenticated,
1238
- renderLink = defaultRenderLink6,
1239
- footnote
1580
+ renderLink = defaultRenderLink7,
1581
+ footnote,
1582
+ mode = "subscription",
1583
+ foundingDeadline
1240
1584
  }) {
1241
- const [annual, setAnnual] = React26.useState(false);
1242
- const mode = useUIVariant();
1585
+ const [annual, setAnnual] = React29.useState(false);
1586
+ const isOneTime = mode === "one-time";
1587
+ const uiMode = useUIVariant();
1243
1588
  const sectionClasses = cn$1(
1244
1589
  "overflow-hidden bg-card",
1245
- mode === "smooth" && "rounded-3xl border",
1246
- mode === "playful" && "rounded-2xl border-primary/25 border",
1247
- !mode && "rounded-2xl border"
1590
+ uiMode === "smooth" && "rounded-3xl border",
1591
+ uiMode === "playful" && "rounded-2xl border-primary/25 border",
1592
+ !uiMode && "rounded-2xl border"
1248
1593
  );
1249
1594
  return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-5xl", children: [
1250
1595
  /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
1251
- badge && /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: badge }),
1596
+ badge && (typeof badge === "string" ? /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: badge }) : /* @__PURE__ */ jsx("div", { className: "mb-4", children: badge })),
1252
1597
  /* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
1253
1598
  description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-xl text-pretty text-muted-foreground", children: description }),
1254
- /* @__PURE__ */ jsxs("div", { className: "mt-6 inline-flex items-center gap-3 rounded-full border bg-muted p-1", children: [
1599
+ !isOneTime && /* @__PURE__ */ jsxs("div", { className: "mt-6 inline-flex items-center gap-3 rounded-full border bg-muted p-1", children: [
1255
1600
  /* @__PURE__ */ jsx(
1256
1601
  Button$1,
1257
1602
  {
@@ -1284,18 +1629,22 @@ function PricingSection({
1284
1629
  ] })
1285
1630
  ] }),
1286
1631
  /* @__PURE__ */ jsx(StaggerChildren, { className: "mt-10 grid gap-4 lg:grid-cols-3", children: plans.map((plan) => {
1287
- const price = annual ? plan.annual : plan.monthly;
1632
+ const rawPrice = isOneTime ? plan.monthly : annual ? plan.annual : plan.monthly;
1633
+ const price = plan.priceDisplay ?? `$${rawPrice}`;
1634
+ const period = plan.periodDisplay ?? (isOneTime ? "one-time" : rawPrice > 0 ? "/mo" : "");
1635
+ const badge2 = plan.highlighted && foundingDeadline ? /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded-full border bg-secondary px-2.5 py-0.5 text-xs font-semibold text-secondary-foreground", children: /* @__PURE__ */ jsx(CountdownTimer, { deadline: foundingDeadline, compact: true }) }) : plan.highlighted ? "Founding member" : void 0;
1288
1636
  return /* @__PURE__ */ jsx(
1289
1637
  PricingCard,
1290
1638
  {
1291
1639
  name: plan.name,
1292
- price: `$${price}`,
1293
- period: price > 0 ? "/mo" : "",
1640
+ price,
1641
+ period,
1294
1642
  description: plan.description,
1295
1643
  features: plan.features,
1296
1644
  cta: plan.cta,
1297
1645
  highlighted: plan.highlighted,
1298
- badge: plan.highlighted ? "Most popular" : void 0
1646
+ disabled: plan.disabled,
1647
+ badge: badge2
1299
1648
  },
1300
1649
  plan.name
1301
1650
  );
@@ -1403,7 +1752,7 @@ function TestimonialsSection({
1403
1752
  )) })
1404
1753
  ] }) }) });
1405
1754
  }
1406
- var team = [
1755
+ var defaultTeam = [
1407
1756
  {
1408
1757
  name: "Olivia Reed",
1409
1758
  role: "Co-Founder & CEO",
@@ -1427,40 +1776,21 @@ var team = [
1427
1776
  avatar: "https://ui.shadcn.com/avatars/03.png",
1428
1777
  initials: "PN",
1429
1778
  social: { twitter: "#", github: null, linkedin: "#" }
1430
- },
1431
- {
1432
- name: "Daniel Frost",
1433
- role: "Senior Engineer",
1434
- bio: "Accessibility and performance specialist. If it doesn't work with a keyboard, it's broken.",
1435
- avatar: "https://ui.shadcn.com/avatars/04.png",
1436
- initials: "DF",
1437
- social: { twitter: null, github: "#", linkedin: "#" }
1438
- },
1439
- {
1440
- name: "Aisha Okafor",
1441
- role: "Developer Relations",
1442
- bio: "Writes docs, builds examples, and makes sure every engineer can ship their first block in under an hour.",
1443
- avatar: "https://ui.shadcn.com/avatars/05.png",
1444
- initials: "AO",
1445
- social: { twitter: "#", github: "#", linkedin: "#" }
1446
- },
1447
- {
1448
- name: "Tom Halvorsen",
1449
- role: "Growth",
1450
- bio: "Turns happy users into loud advocates. Runs the community and keeps the changelog sharp.",
1451
- avatar: "https://ui.shadcn.com/avatars/06.png",
1452
- initials: "TH",
1453
- social: { twitter: "#", github: null, linkedin: "#" }
1454
1779
  }
1455
1780
  ];
1456
- function TeamSection() {
1781
+ function TeamSection({
1782
+ members = defaultTeam,
1783
+ badge = "Team",
1784
+ title = "The people behind Olwiba",
1785
+ description = "A small team with deep experience in design systems, open source, and developer tooling."
1786
+ }) {
1457
1787
  return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-5xl", children: [
1458
1788
  /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
1459
- /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: "Team" }),
1460
- /* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: "The people behind Olwiba" }),
1461
- /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-xl text-pretty text-muted-foreground", children: "A small team with deep experience in design systems, open source, and developer tooling." })
1789
+ /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: badge }),
1790
+ /* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
1791
+ /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-xl text-pretty text-muted-foreground", children: description })
1462
1792
  ] }),
1463
- /* @__PURE__ */ jsx("div", { className: "mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3", children: team.map((member) => /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border bg-muted/40 p-5", children: [
1793
+ /* @__PURE__ */ jsx("div", { className: "mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3", children: members.map((member) => /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border bg-muted/40 p-5", children: [
1464
1794
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-4", children: [
1465
1795
  /* @__PURE__ */ jsxs(Avatar, { className: "size-12 rounded-xl", children: [
1466
1796
  /* @__PURE__ */ jsx(AvatarImage, { src: member.avatar, alt: member.name }),
@@ -1472,7 +1802,7 @@ function TeamSection() {
1472
1802
  ] })
1473
1803
  ] }),
1474
1804
  /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm leading-relaxed text-muted-foreground", children: member.bio }),
1475
- /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-2", children: [
1805
+ member.social && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-2", children: [
1476
1806
  member.social.twitter && /* @__PURE__ */ jsx("a", { href: member.social.twitter, "aria-label": "Twitter", className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground", children: /* @__PURE__ */ jsx(Twitter, { className: "size-3.5" }) }),
1477
1807
  member.social.github && /* @__PURE__ */ jsx("a", { href: member.social.github, "aria-label": "GitHub", className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground", children: /* @__PURE__ */ jsx(Github, { className: "size-3.5" }) }),
1478
1808
  member.social.linkedin && /* @__PURE__ */ jsx("a", { href: member.social.linkedin, "aria-label": "LinkedIn", className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground", children: /* @__PURE__ */ jsx(Linkedin, { className: "size-3.5" }) })
@@ -1512,10 +1842,10 @@ function CountUp({
1512
1842
  className,
1513
1843
  ...props
1514
1844
  }) {
1515
- const ref = React26.useRef(null);
1516
- const [value, setValue] = React26.useState(from);
1517
- const hasStarted = React26.useRef(false);
1518
- React26.useEffect(() => {
1845
+ const ref = React29.useRef(null);
1846
+ const [value, setValue] = React29.useState(from);
1847
+ const hasStarted = React29.useRef(false);
1848
+ React29.useEffect(() => {
1519
1849
  const el = ref.current;
1520
1850
  if (!el) return;
1521
1851
  const observer = new IntersectionObserver(
@@ -1608,8 +1938,8 @@ function NewsletterSection({
1608
1938
  successDescription = defaults.successDescription,
1609
1939
  onSubscribe
1610
1940
  } = {}) {
1611
- const [email, setEmail] = React26.useState("");
1612
- const [submitted, setSubmitted] = React26.useState(false);
1941
+ const [email, setEmail] = React29.useState("");
1942
+ const [submitted, setSubmitted] = React29.useState(false);
1613
1943
  async function handleSubmit(e) {
1614
1944
  e.preventDefault();
1615
1945
  if (!email) return;
@@ -1619,8 +1949,10 @@ function NewsletterSection({
1619
1949
  return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsxs("div", { className: "relative px-6 py-14 sm:px-10 sm:py-20", children: [
1620
1950
  /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,hsl(var(--primary)/0.1),transparent_60%)]" }),
1621
1951
  /* @__PURE__ */ jsxs("div", { className: "relative mx-auto max-w-xl text-center", children: [
1622
- /* @__PURE__ */ jsx("div", { className: "mb-4 inline-flex h-10 w-10 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Mail, { className: "size-5" }) }),
1623
- /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-3", children: badge }),
1952
+ /* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-center justify-center gap-2", children: [
1953
+ /* @__PURE__ */ jsx("div", { className: "inline-flex h-8 w-8 items-center justify-center rounded-xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Mail, { className: "size-4" }) }),
1954
+ /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", children: badge })
1955
+ ] }),
1624
1956
  /* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
1625
1957
  /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-sm text-pretty text-muted-foreground", children: description }),
1626
1958
  submitted ? /* @__PURE__ */ jsxs("div", { className: "mt-8 rounded-2xl border bg-muted/50 px-6 py-5 text-sm", children: [
@@ -1666,15 +1998,14 @@ function NewsletterSection({
1666
1998
  }
1667
1999
  var defaultContactInfoResolved = [
1668
2000
  { icon: Mail, label: "Email", value: "hello@olwiba.com" },
1669
- { icon: Phone, label: "Phone", value: "+1 (555) 000-0000" },
1670
- { icon: MapPin, label: "Office", value: "San Francisco, CA" }
2001
+ { icon: MapPin, label: "Base", value: "Aotearoa New Zealand" }
1671
2002
  ];
1672
2003
  var defaults2 = {
1673
- badge: "Contact us",
2004
+ badge: "Contact",
1674
2005
  title: "Let's talk",
1675
- description: "Have a question or want to work together? Fill in the form and we'll get back to you within one business day.",
2006
+ description: "Have a question or want to work together? Fill in the form and you'll hear back from the person who built it.",
1676
2007
  successTitle: "Message sent",
1677
- successDescription: "Thanks for reaching out. We'll get back to you within one business day.",
2008
+ successDescription: "Thanks for reaching out. You'll get a reply within one business day.",
1678
2009
  sendAnotherLabel: "Send another"
1679
2010
  };
1680
2011
  function ContactSection({
@@ -1682,12 +2013,13 @@ function ContactSection({
1682
2013
  title = defaults2.title,
1683
2014
  description = defaults2.description,
1684
2015
  contactInfo = defaultContactInfoResolved,
2016
+ privacyHref,
1685
2017
  successTitle = defaults2.successTitle,
1686
2018
  successDescription = defaults2.successDescription,
1687
2019
  sendAnotherLabel = defaults2.sendAnotherLabel,
1688
2020
  onSubmit
1689
2021
  } = {}) {
1690
- const [submitted, setSubmitted] = React26.useState(false);
2022
+ const [submitted, setSubmitted] = React29.useState(false);
1691
2023
  async function handleSubmit(e) {
1692
2024
  e.preventDefault();
1693
2025
  await onSubmit?.(e);
@@ -1695,49 +2027,41 @@ function ContactSection({
1695
2027
  }
1696
2028
  return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsxs("div", { className: "grid lg:grid-cols-[1fr_1.4fr]", children: [
1697
2029
  /* @__PURE__ */ jsxs("div", { className: "relative overflow-hidden bg-primary px-8 py-12 text-primary-foreground", children: [
1698
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(circle_at_top_right,hsl(var(--primary-foreground)/0.1),transparent_60%)]" }),
1699
- /* @__PURE__ */ jsxs("div", { className: "relative space-y-6", children: [
2030
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(circle_at_top_right,hsl(var(--primary-foreground)/0.12),transparent_55%)]" }),
2031
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(circle_at_bottom_left,hsl(var(--primary-foreground)/0.06),transparent_60%)]" }),
2032
+ /* @__PURE__ */ jsxs("div", { className: "relative flex h-full flex-col gap-8", children: [
1700
2033
  /* @__PURE__ */ jsxs("div", { children: [
1701
2034
  /* @__PURE__ */ jsx(
1702
2035
  Badge$1,
1703
2036
  {
1704
2037
  variant: "secondary",
1705
- className: "mb-3 bg-primary-foreground/15 text-primary-foreground hover:bg-primary-foreground/20",
2038
+ className: "mb-4 bg-primary-foreground/15 text-primary-foreground hover:bg-primary-foreground/20",
1706
2039
  children: badge
1707
2040
  }
1708
2041
  ),
1709
- /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold", children: title }),
1710
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-primary-foreground/70", children: description })
2042
+ /* @__PURE__ */ jsx("h2", { className: "text-3xl font-semibold leading-tight", children: title }),
2043
+ /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm leading-relaxed text-primary-foreground/70", children: description })
1711
2044
  ] }),
1712
2045
  /* @__PURE__ */ jsx(Separator, { className: "bg-primary-foreground/20" }),
1713
- /* @__PURE__ */ jsx("div", { className: "space-y-4", children: contactInfo.map(({ icon: Icon = Mail, label, value }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1714
- /* @__PURE__ */ jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary-foreground/10", children: /* @__PURE__ */ jsx(Icon, { className: "size-4" }) }),
2046
+ /* @__PURE__ */ jsx("div", { className: "space-y-5", children: contactInfo.map(({ icon: Icon = Mail, label, value }) => /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
2047
+ /* @__PURE__ */ jsx("div", { className: "mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary-foreground/10", children: /* @__PURE__ */ jsx(Icon, { className: "size-4" }) }),
1715
2048
  /* @__PURE__ */ jsxs("div", { children: [
1716
- /* @__PURE__ */ jsx("div", { className: "text-xs text-primary-foreground/60", children: label }),
1717
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: value })
2049
+ /* @__PURE__ */ jsx("div", { className: "text-xs font-medium uppercase tracking-wider text-primary-foreground/50", children: label }),
2050
+ /* @__PURE__ */ jsx("div", { className: "mt-0.5 text-sm font-medium", children: value })
1718
2051
  ] })
1719
- ] }, label)) })
2052
+ ] }, label)) }),
2053
+ /* @__PURE__ */ jsx("div", { className: "mt-auto", children: /* @__PURE__ */ jsx("p", { className: "text-xs text-primary-foreground/40", children: "Response within one business day." }) })
1720
2054
  ] })
1721
2055
  ] }),
1722
- /* @__PURE__ */ jsx("div", { className: "p-8", children: submitted ? /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-[320px] flex-col items-center justify-center gap-4 text-center", children: [
1723
- /* @__PURE__ */ jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(MessageSquare, { className: "size-6" }) }),
2056
+ /* @__PURE__ */ jsx("div", { className: "p-8 sm:p-10", children: submitted ? /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-[360px] flex-col items-center justify-center gap-5 text-center", children: [
2057
+ /* @__PURE__ */ jsx("div", { className: "flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(MessageSquare, { className: "size-6" }) }),
1724
2058
  /* @__PURE__ */ jsxs("div", { children: [
1725
- /* @__PURE__ */ jsx("h3", { className: "font-semibold", children: successTitle }),
1726
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: successDescription })
2059
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: successTitle }),
2060
+ /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm text-muted-foreground", children: successDescription })
1727
2061
  ] }),
1728
- /* @__PURE__ */ jsx(Button$1, { variant: "outline", onClick: () => setSubmitted(false), children: sendAnotherLabel })
2062
+ /* @__PURE__ */ jsx(Button$1, { variant: "outline", size: "sm", onClick: () => setSubmitted(false), children: sendAnotherLabel })
1729
2063
  ] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-5", children: [
1730
- /* @__PURE__ */ jsx(
1731
- "input",
1732
- {
1733
- type: "text",
1734
- name: "company",
1735
- tabIndex: -1,
1736
- autoComplete: "off",
1737
- "aria-hidden": "true",
1738
- className: "hidden"
1739
- }
1740
- ),
2064
+ /* @__PURE__ */ jsx("input", { type: "text", name: "_hp", tabIndex: -1, autoComplete: "off", "aria-hidden": "true", className: "hidden" }),
1741
2065
  /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
1742
2066
  /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1743
2067
  /* @__PURE__ */ jsx(Label, { htmlFor: "contact-first", children: "First name" }),
@@ -1748,8 +2072,24 @@ function ContactSection({
1748
2072
  /* @__PURE__ */ jsx(Input$1, { id: "contact-last", name: "lastName", placeholder: "Reed", required: true })
1749
2073
  ] })
1750
2074
  ] }),
2075
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
2076
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
2077
+ /* @__PURE__ */ jsxs(Label, { htmlFor: "contact-company", className: "flex gap-1", children: [
2078
+ "Company",
2079
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "(optional)" })
2080
+ ] }),
2081
+ /* @__PURE__ */ jsx(Input$1, { id: "contact-company", name: "company", placeholder: "Acme Inc." })
2082
+ ] }),
2083
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
2084
+ /* @__PURE__ */ jsxs(Label, { htmlFor: "contact-phone", className: "flex gap-1", children: [
2085
+ "Phone",
2086
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "(optional)" })
2087
+ ] }),
2088
+ /* @__PURE__ */ jsx(Input$1, { id: "contact-phone", name: "phone", type: "tel", placeholder: "+1 (555) 000-0000" })
2089
+ ] })
2090
+ ] }),
1751
2091
  /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1752
- /* @__PURE__ */ jsx(Label, { htmlFor: "contact-email", children: "Email" }),
2092
+ /* @__PURE__ */ jsx(Label, { htmlFor: "contact-email", children: "Work email" }),
1753
2093
  /* @__PURE__ */ jsx(Input$1, { id: "contact-email", name: "email", type: "email", placeholder: "olivia@company.com", required: true })
1754
2094
  ] }),
1755
2095
  /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
@@ -1764,11 +2104,20 @@ function ContactSection({
1764
2104
  id: "contact-message",
1765
2105
  name: "message",
1766
2106
  placeholder: "Tell us what you're working on...",
1767
- className: "min-h-28 resize-none",
2107
+ className: "min-h-32 resize-none",
1768
2108
  required: true
1769
2109
  }
1770
2110
  )
1771
2111
  ] }),
2112
+ privacyHref && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
2113
+ /* @__PURE__ */ jsx(Checkbox$1, { id: "contact-privacy", name: "privacy", required: true, className: "mt-0.5" }),
2114
+ /* @__PURE__ */ jsxs(Label, { htmlFor: "contact-privacy", className: "text-sm font-normal leading-snug text-muted-foreground", children: [
2115
+ "By submitting this form you agree to our",
2116
+ " ",
2117
+ /* @__PURE__ */ jsx("a", { href: privacyHref, className: "font-medium text-foreground underline-offset-2 hover:underline", children: "privacy policy" }),
2118
+ "."
2119
+ ] })
2120
+ ] }),
1772
2121
  /* @__PURE__ */ jsxs(Button$1, { type: "submit", className: "w-full", children: [
1773
2122
  "Send message",
1774
2123
  /* @__PURE__ */ jsx(Send, { className: "ml-2 size-4" })
@@ -1776,22 +2125,143 @@ function ContactSection({
1776
2125
  ] }) })
1777
2126
  ] }) });
1778
2127
  }
1779
- var defaultRenderLink7 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
2128
+ function ComparisonSection({
2129
+ badge = "The math",
2130
+ title = "The math is simple",
2131
+ description,
2132
+ columns
2133
+ }) {
2134
+ const mode = useUIVariant();
2135
+ const sectionClasses = cn$1(
2136
+ "overflow-hidden bg-card",
2137
+ mode === "smooth" && "rounded-3xl border",
2138
+ mode === "playful" && "rounded-2xl border-primary/25 border",
2139
+ !mode && "rounded-2xl border"
2140
+ );
2141
+ return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
2142
+ /* @__PURE__ */ jsx(SectionTitle, { badge, title, description }),
2143
+ /* @__PURE__ */ jsx(StaggerChildren, { className: "mt-12 grid gap-4 sm:grid-cols-3", children: columns.map((col) => /* @__PURE__ */ jsxs(
2144
+ "div",
2145
+ {
2146
+ className: cn$1(
2147
+ "flex flex-col rounded-2xl border p-6",
2148
+ col.highlighted ? "border-foreground bg-foreground text-background" : "border-border bg-muted/40"
2149
+ ),
2150
+ children: [
2151
+ /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
2152
+ /* @__PURE__ */ jsx(
2153
+ "p",
2154
+ {
2155
+ className: cn$1(
2156
+ "text-xs font-semibold uppercase tracking-widest",
2157
+ col.highlighted ? "text-background/60" : "text-muted-foreground"
2158
+ ),
2159
+ children: col.label
2160
+ }
2161
+ ),
2162
+ /* @__PURE__ */ jsx(
2163
+ "p",
2164
+ {
2165
+ className: cn$1(
2166
+ "mt-2 text-2xl font-bold tracking-tight",
2167
+ col.highlighted ? "text-background" : "text-foreground"
2168
+ ),
2169
+ children: col.cost
2170
+ }
2171
+ ),
2172
+ col.costDetail && /* @__PURE__ */ jsx(
2173
+ "p",
2174
+ {
2175
+ className: cn$1(
2176
+ "mt-1 text-sm",
2177
+ col.highlighted ? "text-background/60" : "text-muted-foreground"
2178
+ ),
2179
+ children: col.costDetail
2180
+ }
2181
+ )
2182
+ ] }),
2183
+ /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-3", children: col.items.map((item) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2.5", children: [
2184
+ col.highlighted ? /* @__PURE__ */ jsx(Check, { className: "mt-0.5 size-4 shrink-0 text-background/70" }) : /* @__PURE__ */ jsx(Minus, { className: "mt-0.5 size-4 shrink-0 text-muted-foreground/50" }),
2185
+ /* @__PURE__ */ jsx(
2186
+ "span",
2187
+ {
2188
+ className: cn$1(
2189
+ "text-sm leading-snug",
2190
+ col.highlighted ? "text-background/90" : "text-muted-foreground"
2191
+ ),
2192
+ children: item
2193
+ }
2194
+ )
2195
+ ] }, item)) })
2196
+ ]
2197
+ },
2198
+ col.label
2199
+ )) })
2200
+ ] }) }) });
2201
+ }
2202
+ function QualificationSection({
2203
+ badge = "Who it is for",
2204
+ title = "Is this for you?",
2205
+ description,
2206
+ columns
2207
+ }) {
2208
+ const mode = useUIVariant();
2209
+ const sectionClasses = cn$1(
2210
+ "overflow-hidden bg-card",
2211
+ mode === "smooth" && "rounded-3xl border",
2212
+ mode === "playful" && "rounded-2xl border-primary/25 border",
2213
+ !mode && "rounded-2xl border"
2214
+ );
2215
+ return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
2216
+ /* @__PURE__ */ jsx(SectionTitle, { badge, title, description }),
2217
+ /* @__PURE__ */ jsx(FadeIn, { direction: "up", className: "mt-12 grid gap-6 sm:grid-cols-2", children: columns.map((col) => {
2218
+ const isPositive = col.variant === "positive";
2219
+ const Icon = isPositive ? Check : X;
2220
+ return /* @__PURE__ */ jsxs(
2221
+ "div",
2222
+ {
2223
+ className: cn$1(
2224
+ "flex flex-col gap-4 rounded-2xl border p-6",
2225
+ isPositive ? "border-border bg-muted/30" : "border-border bg-muted/10"
2226
+ ),
2227
+ children: [
2228
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold uppercase tracking-widest text-muted-foreground", children: col.heading }),
2229
+ /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-3", children: col.items.map((item) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-3", children: [
2230
+ /* @__PURE__ */ jsx(
2231
+ "span",
2232
+ {
2233
+ className: cn$1(
2234
+ "mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-full",
2235
+ isPositive ? "bg-emerald-500/15 text-emerald-600 dark:text-emerald-400" : "bg-rose-500/15 text-rose-600 dark:text-rose-400"
2236
+ ),
2237
+ children: /* @__PURE__ */ jsx(Icon, { className: "size-3" })
2238
+ }
2239
+ ),
2240
+ /* @__PURE__ */ jsx("span", { className: "text-sm leading-relaxed text-foreground/80", children: item })
2241
+ ] }, item)) })
2242
+ ]
2243
+ },
2244
+ col.heading
2245
+ );
2246
+ }) })
2247
+ ] }) }) });
2248
+ }
2249
+ var defaultRenderLink8 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
1780
2250
  function Navbar({
1781
2251
  brand,
1782
2252
  navLinks,
1783
2253
  cta,
1784
2254
  controls,
1785
- renderLink = defaultRenderLink7
2255
+ renderLink = defaultRenderLink8
1786
2256
  }) {
1787
- const [open, setOpen] = React26.useState(false);
2257
+ const [open, setOpen] = React29.useState(false);
1788
2258
  const brandHref = brand.href ?? "/";
1789
2259
  const hasRightContent = controls?.length || cta?.primary || cta?.secondary;
1790
2260
  return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsxs("nav", { className: "grid h-16 grid-cols-[1fr_auto_1fr] items-center px-6", children: [
1791
2261
  renderLink({
1792
2262
  href: brandHref,
1793
2263
  children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 font-semibold", children: [
1794
- brand.logo && /* @__PURE__ */ jsx("span", { className: "flex h-9 w-9 items-center justify-center rounded-xl bg-primary text-primary-foreground", children: brand.logo }),
2264
+ brand.logo,
1795
2265
  /* @__PURE__ */ jsx("span", { children: brand.name })
1796
2266
  ] })
1797
2267
  }),
@@ -1801,7 +2271,7 @@ function Navbar({
1801
2271
  children: link.label
1802
2272
  }) }, link.label)) }),
1803
2273
  hasRightContent && /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-end gap-2 md:flex", children: [
1804
- controls?.map((control, i) => /* @__PURE__ */ jsx(React26.Fragment, { children: control }, i)),
2274
+ controls?.map((control, i) => /* @__PURE__ */ jsx(React29.Fragment, { children: control }, i)),
1805
2275
  (cta?.secondary || cta?.primary) && controls?.length ? /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }) : null,
1806
2276
  cta?.secondary && renderLink({
1807
2277
  href: cta.secondary.href,
@@ -1822,12 +2292,12 @@ function Navbar({
1822
2292
  /* @__PURE__ */ jsx("span", { onClick: () => setOpen(false), className: "cursor-pointer", children: renderLink({
1823
2293
  href: brandHref,
1824
2294
  children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 font-semibold", children: [
1825
- brand.logo && /* @__PURE__ */ jsx("span", { className: "flex h-7 w-7 items-center justify-center rounded-lg bg-primary text-primary-foreground", children: brand.logo }),
2295
+ brand.logo,
1826
2296
  /* @__PURE__ */ jsx("span", { children: brand.name })
1827
2297
  ] })
1828
2298
  }) }),
1829
2299
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1830
- controls?.map((control, i) => /* @__PURE__ */ jsx(React26.Fragment, { children: control }, i)),
2300
+ controls?.map((control, i) => /* @__PURE__ */ jsx(React29.Fragment, { children: control }, i)),
1831
2301
  /* @__PURE__ */ jsxs(Button$1, { variant: "ghost", size: "icon", onClick: () => setOpen(false), children: [
1832
2302
  /* @__PURE__ */ jsx(X, { className: "size-4" }),
1833
2303
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close menu" })
@@ -1854,22 +2324,22 @@ function Navbar({
1854
2324
  ] })
1855
2325
  ] }) });
1856
2326
  }
1857
- var defaultRenderLink8 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
2327
+ var defaultRenderLink9 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
1858
2328
  function Footer({
1859
2329
  brand,
1860
2330
  navLinks,
1861
2331
  socialLinks,
1862
2332
  legal,
1863
- renderLink = defaultRenderLink8
2333
+ renderLink = defaultRenderLink9
1864
2334
  }) {
1865
2335
  const brandHref = brand.href ?? "/";
1866
2336
  const copyrightText = legal ?? `\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${brand.name}. All rights reserved.`;
1867
- return /* @__PURE__ */ jsx("footer", { className: "overflow-hidden rounded-2xl border bg-muted text-foreground", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-7xl px-6 py-20 sm:py-24 lg:px-8", children: [
2337
+ return /* @__PURE__ */ jsx("footer", { className: "overflow-hidden rounded-2xl border bg-card text-foreground", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-7xl px-6 py-20 sm:py-24 lg:px-8", children: [
1868
2338
  /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: renderLink({
1869
2339
  href: brandHref,
1870
2340
  className: "flex items-center gap-2",
1871
2341
  children: /* @__PURE__ */ jsxs(Fragment, { children: [
1872
- brand.logo && /* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-foreground/10 text-foreground", children: brand.logo }),
2342
+ brand.logo,
1873
2343
  /* @__PURE__ */ jsx("span", { className: "text-lg font-semibold text-foreground", children: brand.name })
1874
2344
  ] })
1875
2345
  }) }),
@@ -1891,7 +2361,7 @@ function Footer({
1891
2361
  /* @__PURE__ */ jsx("p", { className: "mt-10 text-center text-sm/6 text-muted-foreground/70", children: copyrightText })
1892
2362
  ] }) });
1893
2363
  }
1894
- var speedDuration = {
2364
+ var speedDuration2 = {
1895
2365
  slow: "60s",
1896
2366
  normal: "40s",
1897
2367
  fast: "25s"
@@ -1901,7 +2371,7 @@ function LogoStrip({
1901
2371
  label,
1902
2372
  speed = "normal"
1903
2373
  }) {
1904
- const duration = speedDuration[speed];
2374
+ const duration = speedDuration2[speed];
1905
2375
  return /* @__PURE__ */ jsxs(FadeIn, { direction: "up", children: [
1906
2376
  /* @__PURE__ */ jsxs("section", { className: "overflow-hidden py-8", children: [
1907
2377
  label && /* @__PURE__ */ jsx("p", { className: "mb-6 text-center text-sm text-muted-foreground", children: label }),
@@ -1972,7 +2442,7 @@ function LogoStrip({
1972
2442
  ] });
1973
2443
  }
1974
2444
  function GridUnderlay({ variant, size = 24, className, ...props }) {
1975
- const id = React26.useId();
2445
+ const id = React29.useId();
1976
2446
  const pattern = variant === "dots" ? /* @__PURE__ */ jsx("circle", { cx: size / 2, cy: size / 2, r: 1, fill: "currentColor" }) : variant === "lines" ? /* @__PURE__ */ jsx("path", { d: `M ${size} 0 L 0 0 0 ${size}`, fill: "none", stroke: "currentColor", strokeWidth: 0.5 }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1977
2447
  /* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
1978
2448
  /* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
@@ -2000,9 +2470,9 @@ function GlowUnderlay({
2000
2470
  style,
2001
2471
  ...props
2002
2472
  }) {
2003
- const [pos, setPos] = React26.useState({ x: "50%", y: "50%" });
2004
- const containerRef = React26.useRef(null);
2005
- React26.useEffect(() => {
2473
+ const [pos, setPos] = React29.useState({ x: "50%", y: "50%" });
2474
+ const containerRef = React29.useRef(null);
2475
+ React29.useEffect(() => {
2006
2476
  if (!followCursor) return;
2007
2477
  const handleMouseMove = (e) => {
2008
2478
  const el = containerRef.current;
@@ -2086,6 +2556,53 @@ function Overlay(props) {
2086
2556
  if (props.variant === "scrim") return /* @__PURE__ */ jsx(ScrimOverlay, { ...props });
2087
2557
  return /* @__PURE__ */ jsx(LoadingOverlay, { ...props });
2088
2558
  }
2559
+ function AnimatedPill({ labels, interval = 3800, className }) {
2560
+ const pillRef = useRef(null);
2561
+ const textRef = useRef(null);
2562
+ useEffect(() => {
2563
+ const pill = pillRef.current;
2564
+ const text = textRef.current;
2565
+ if (!pill || !text || labels.length < 2) return;
2566
+ pill.style.width = pill.offsetWidth + "px";
2567
+ pill.dataset.w = String(pill.offsetWidth);
2568
+ let idx = 0;
2569
+ const cycle = () => {
2570
+ idx = (idx + 1) % labels.length;
2571
+ text.style.transition = "opacity 140ms ease";
2572
+ text.style.opacity = "0";
2573
+ setTimeout(() => {
2574
+ text.textContent = labels[idx] ?? "";
2575
+ const oldW = parseFloat(pill.dataset.w ?? "0");
2576
+ pill.style.transition = "none";
2577
+ pill.style.width = "auto";
2578
+ const newW = pill.offsetWidth;
2579
+ pill.style.width = oldW + "px";
2580
+ void pill.offsetWidth;
2581
+ pill.style.transition = "width 280ms cubic-bezier(0.4, 0, 0.2, 1)";
2582
+ pill.style.width = newW + "px";
2583
+ pill.dataset.w = String(newW);
2584
+ setTimeout(() => {
2585
+ text.style.transition = "opacity 140ms ease";
2586
+ text.style.opacity = "1";
2587
+ }, 260);
2588
+ }, 150);
2589
+ };
2590
+ const id = setInterval(cycle, interval);
2591
+ return () => clearInterval(id);
2592
+ }, [labels, interval]);
2593
+ if (!labels.length) return null;
2594
+ return /* @__PURE__ */ jsx(
2595
+ "span",
2596
+ {
2597
+ ref: pillRef,
2598
+ className: cn$1(
2599
+ "inline-flex items-center overflow-hidden whitespace-nowrap rounded-full border bg-secondary px-2.5 py-0.5 text-xs font-semibold text-secondary-foreground",
2600
+ className
2601
+ ),
2602
+ children: /* @__PURE__ */ jsx("span", { ref: textRef, children: labels[0] })
2603
+ }
2604
+ );
2605
+ }
2089
2606
  function PageTransition({
2090
2607
  variant = "fade",
2091
2608
  duration = 300,
@@ -2094,8 +2611,8 @@ function PageTransition({
2094
2611
  style,
2095
2612
  ...props
2096
2613
  }) {
2097
- const [mounted, setMounted] = React26.useState(false);
2098
- React26.useEffect(() => {
2614
+ const [mounted, setMounted] = React29.useState(false);
2615
+ React29.useEffect(() => {
2099
2616
  const id = requestAnimationFrame(() => setMounted(true));
2100
2617
  return () => cancelAnimationFrame(id);
2101
2618
  }, []);
@@ -2122,8 +2639,8 @@ function Spotlight({
2122
2639
  triggerClassName,
2123
2640
  shortcut = "\u2318K"
2124
2641
  }) {
2125
- const [open, setOpen] = React26.useState(false);
2126
- React26.useEffect(() => {
2642
+ const [open, setOpen] = React29.useState(false);
2643
+ React29.useEffect(() => {
2127
2644
  const down = (e) => {
2128
2645
  if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
2129
2646
  e.preventDefault();
@@ -2153,7 +2670,7 @@ function Spotlight({
2153
2670
  /* @__PURE__ */ jsx(CommandInput, { placeholder }),
2154
2671
  /* @__PURE__ */ jsxs(CommandList, { children: [
2155
2672
  /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
2156
- groups.map((group, i) => /* @__PURE__ */ jsxs(React26.Fragment, { children: [
2673
+ groups.map((group, i) => /* @__PURE__ */ jsxs(React29.Fragment, { children: [
2157
2674
  i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
2158
2675
  /* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
2159
2676
  CommandItem,
@@ -2178,8 +2695,8 @@ function Spotlight({
2178
2695
  var BASE = 40;
2179
2696
  var MAGNIFY_RADIUS = 80;
2180
2697
  function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
2181
- const [mouseX, setMouseX] = React26.useState(null);
2182
- const containerRef = React26.useRef(null);
2698
+ const [mouseX, setMouseX] = React29.useState(null);
2699
+ const containerRef = React29.useRef(null);
2183
2700
  function getScale(index) {
2184
2701
  if (mouseX === null || !containerRef.current) return 1;
2185
2702
  const container = containerRef.current;
@@ -2385,26 +2902,254 @@ function ImageCard({
2385
2902
  }
2386
2903
  );
2387
2904
  }
2905
+ var DASH_ON = "5px";
2906
+ var DASH_OFF = "4px";
2907
+ function FlowConnector({
2908
+ direction = "vertical",
2909
+ color,
2910
+ arrow = false,
2911
+ animate = false,
2912
+ animateDur = "1.4s",
2913
+ animateDelay = "0s",
2914
+ className,
2915
+ style
2916
+ }) {
2917
+ const stroke = color ?? "currentColor";
2918
+ const opacity = color ? 0.75 : 0.4;
2919
+ if (direction === "vertical") {
2920
+ return /* @__PURE__ */ jsxs(
2921
+ "div",
2922
+ {
2923
+ className: cn$1("relative flex flex-col items-center", className),
2924
+ style,
2925
+ "aria-hidden": true,
2926
+ children: [
2927
+ animate && /* @__PURE__ */ jsx("style", { children: `@keyframes fc-dot-v{0%{top:-4px;opacity:0}8%{opacity:1}88%{opacity:1}100%{top:calc(100% + 4px);opacity:0}}` }),
2928
+ /* @__PURE__ */ jsx(
2929
+ "div",
2930
+ {
2931
+ className: "flex-1",
2932
+ style: {
2933
+ width: 2,
2934
+ opacity,
2935
+ background: `repeating-linear-gradient(to bottom, ${stroke} 0, ${stroke} ${DASH_ON}, transparent ${DASH_ON}, transparent calc(${DASH_ON} + ${DASH_OFF}))`
2936
+ }
2937
+ }
2938
+ ),
2939
+ animate && /* @__PURE__ */ jsx(
2940
+ "div",
2941
+ {
2942
+ style: {
2943
+ position: "absolute",
2944
+ left: "50%",
2945
+ transform: "translateX(-50%)",
2946
+ width: 5,
2947
+ height: 5,
2948
+ borderRadius: "50%",
2949
+ backgroundColor: stroke,
2950
+ animation: `fc-dot-v ${animateDur} ease-in-out ${animateDelay} infinite both`
2951
+ }
2952
+ }
2953
+ ),
2954
+ arrow && /* @__PURE__ */ jsx(
2955
+ "svg",
2956
+ {
2957
+ width: "12",
2958
+ height: "7",
2959
+ viewBox: "0 0 12 7",
2960
+ style: { display: "block", opacity },
2961
+ "aria-hidden": true,
2962
+ children: /* @__PURE__ */ jsx(
2963
+ "polyline",
2964
+ {
2965
+ points: "1,1 6,6 11,1",
2966
+ fill: "none",
2967
+ stroke,
2968
+ strokeWidth: "1.5",
2969
+ strokeLinecap: "round",
2970
+ strokeLinejoin: "round"
2971
+ }
2972
+ )
2973
+ }
2974
+ )
2975
+ ]
2976
+ }
2977
+ );
2978
+ }
2979
+ return /* @__PURE__ */ jsxs(
2980
+ "div",
2981
+ {
2982
+ className: cn$1("flex items-center", className),
2983
+ style,
2984
+ "aria-hidden": true,
2985
+ children: [
2986
+ /* @__PURE__ */ jsx(
2987
+ "div",
2988
+ {
2989
+ className: "flex-1",
2990
+ style: {
2991
+ height: 2,
2992
+ opacity,
2993
+ background: `repeating-linear-gradient(to right, ${stroke} 0, ${stroke} ${DASH_ON}, transparent ${DASH_ON}, transparent calc(${DASH_ON} + ${DASH_OFF}))`
2994
+ }
2995
+ }
2996
+ ),
2997
+ arrow && /* @__PURE__ */ jsx(
2998
+ "svg",
2999
+ {
3000
+ width: "7",
3001
+ height: "12",
3002
+ viewBox: "0 0 7 12",
3003
+ style: { display: "block", opacity },
3004
+ "aria-hidden": true,
3005
+ children: /* @__PURE__ */ jsx(
3006
+ "polyline",
3007
+ {
3008
+ points: "1,1 6,6 1,11",
3009
+ fill: "none",
3010
+ stroke,
3011
+ strokeWidth: "1.5",
3012
+ strokeLinecap: "round",
3013
+ strokeLinejoin: "round"
3014
+ }
3015
+ )
3016
+ }
3017
+ )
3018
+ ]
3019
+ }
3020
+ );
3021
+ }
3022
+ var MARKER_L = "fb-ml";
3023
+ var MARKER_R = "fb-mr";
3024
+ function FlowBracket({
3025
+ anchorTop = 8,
3026
+ anchorBottom = 92,
3027
+ extent = 22,
3028
+ arrow = true,
3029
+ color = "rgba(148,163,184,0.4)",
3030
+ colorLeft,
3031
+ colorRight,
3032
+ left = true,
3033
+ right = true,
3034
+ animate = false,
3035
+ animateDur = "4s",
3036
+ reverseRight = false,
3037
+ style,
3038
+ className,
3039
+ children
3040
+ }) {
3041
+ const L = -extent;
3042
+ const R = 1e3 + extent;
3043
+ const cl = colorLeft ?? color;
3044
+ const cr = colorRight ?? color;
3045
+ const leftD = `M 0,${anchorBottom} L ${L},${anchorBottom} L ${L},${anchorTop} L 0,${anchorTop}`;
3046
+ const rightD = reverseRight ? `M 1000,${anchorTop} L ${R},${anchorTop} L ${R},${anchorBottom} L 1000,${anchorBottom}` : `M 1000,${anchorBottom} L ${R},${anchorBottom} L ${R},${anchorTop} L 1000,${anchorTop}`;
3047
+ const ep = `${(extent / 10).toFixed(1)}%`;
3048
+ const dotKeyframes = animate ? `
3049
+ @keyframes fb-dl{
3050
+ 0%{top:${anchorBottom}%;left:0;opacity:0}
3051
+ 6%{opacity:1}
3052
+ 20%{top:${anchorBottom}%;left:-${ep}}
3053
+ 80%{top:${anchorTop}%;left:-${ep};opacity:1}
3054
+ 94%{top:${anchorTop}%;left:0;opacity:0}
3055
+ 100%{top:${anchorTop}%;left:0;opacity:0}
3056
+ }
3057
+ @keyframes fb-dr{
3058
+ 0%{top:${anchorBottom}%;left:100%;opacity:0}
3059
+ 6%{opacity:1}
3060
+ 20%{top:${anchorBottom}%;left:calc(100% + ${ep})}
3061
+ 80%{top:${anchorTop}%;left:calc(100% + ${ep});opacity:1}
3062
+ 94%{top:${anchorTop}%;left:100%;opacity:0}
3063
+ 100%{top:${anchorTop}%;left:100%;opacity:0}
3064
+ }` : "";
3065
+ const dotBase = {
3066
+ position: "absolute",
3067
+ width: 5,
3068
+ height: 5,
3069
+ borderRadius: "50%",
3070
+ transform: "translate(-50%, -50%)",
3071
+ pointerEvents: "none",
3072
+ opacity: 0
3073
+ };
3074
+ return /* @__PURE__ */ jsxs("div", { className, style: { position: "relative", ...style }, children: [
3075
+ animate && /* @__PURE__ */ jsx("style", { children: dotKeyframes }),
3076
+ /* @__PURE__ */ jsxs(
3077
+ "svg",
3078
+ {
3079
+ viewBox: "0 0 1000 100",
3080
+ preserveAspectRatio: "none",
3081
+ "aria-hidden": true,
3082
+ className: "pointer-events-none absolute inset-0",
3083
+ style: { width: "100%", height: "100%", overflow: "visible" },
3084
+ children: [
3085
+ /* @__PURE__ */ jsxs("defs", { children: [
3086
+ /* @__PURE__ */ jsx("marker", { id: MARKER_L, markerWidth: "10", markerHeight: "8", refX: "8", refY: "4", orient: "auto", children: /* @__PURE__ */ jsx("polyline", { points: "1,1 8,4 1,7", fill: "none", stroke: cl, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }),
3087
+ /* @__PURE__ */ jsx("marker", { id: MARKER_R, markerWidth: "10", markerHeight: "8", refX: "8", refY: "4", orient: "auto", children: /* @__PURE__ */ jsx("polyline", { points: "1,1 8,4 1,7", fill: "none", stroke: cr, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
3088
+ ] }),
3089
+ left && /* @__PURE__ */ jsx(
3090
+ "path",
3091
+ {
3092
+ d: leftD,
3093
+ fill: "none",
3094
+ stroke: cl,
3095
+ strokeWidth: 1.5,
3096
+ strokeDasharray: "5,4",
3097
+ vectorEffect: "non-scaling-stroke",
3098
+ ...arrow ? { markerEnd: `url(#${MARKER_L})` } : {}
3099
+ }
3100
+ ),
3101
+ right && /* @__PURE__ */ jsx(
3102
+ "path",
3103
+ {
3104
+ d: rightD,
3105
+ fill: "none",
3106
+ stroke: cr,
3107
+ strokeWidth: 1.5,
3108
+ strokeDasharray: "5,4",
3109
+ vectorEffect: "non-scaling-stroke",
3110
+ ...arrow ? { markerEnd: `url(#${MARKER_R})` } : {}
3111
+ }
3112
+ )
3113
+ ]
3114
+ }
3115
+ ),
3116
+ children,
3117
+ animate && left && /* @__PURE__ */ jsx(
3118
+ "div",
3119
+ {
3120
+ "aria-hidden": true,
3121
+ style: { ...dotBase, backgroundColor: cl, animation: `fb-dl ${animateDur} ease-in-out 0s infinite` }
3122
+ }
3123
+ ),
3124
+ animate && right && /* @__PURE__ */ jsx(
3125
+ "div",
3126
+ {
3127
+ "aria-hidden": true,
3128
+ style: { ...dotBase, backgroundColor: cr, animation: `fb-dr ${animateDur} ease-in-out 1.8s infinite` }
3129
+ }
3130
+ )
3131
+ ] });
3132
+ }
2388
3133
  function FullPageSpinner({ message }) {
2389
3134
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-4", children: [
2390
3135
  /* @__PURE__ */ jsx(Spinner, { className: "size-8" }),
2391
3136
  message && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: message })
2392
3137
  ] });
2393
3138
  }
2394
- var defaultRenderLink9 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
3139
+ var defaultRenderLink10 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
2395
3140
  function PageHeader({
2396
3141
  title,
2397
3142
  description,
2398
3143
  breadcrumbs,
2399
3144
  backButton,
2400
- renderLink = defaultRenderLink9,
3145
+ renderLink = defaultRenderLink10,
2401
3146
  className,
2402
3147
  children
2403
3148
  }) {
2404
3149
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
2405
3150
  breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "mb-2 flex items-center gap-1 text-sm text-muted-foreground", children: breadcrumbs.map((crumb, i) => {
2406
3151
  const isLast = i === breadcrumbs.length - 1;
2407
- return /* @__PURE__ */ jsxs(React26.Fragment, { children: [
3152
+ return /* @__PURE__ */ jsxs(React29.Fragment, { children: [
2408
3153
  i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
2409
3154
  isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
2410
3155
  href: crumb.href,
@@ -2440,15 +3185,15 @@ function PageHeader({
2440
3185
  ] });
2441
3186
  }
2442
3187
  function Suspensed({ children, fallback }) {
2443
- return /* @__PURE__ */ jsx(React26.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
3188
+ return /* @__PURE__ */ jsx(React29.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
3189
+ }
3190
+ function getInitialTheme() {
3191
+ if (typeof document === "undefined") return "dark";
3192
+ const stored = localStorage.getItem("theme");
3193
+ return stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
2444
3194
  }
2445
3195
  function ThemeSwitchMinimal() {
2446
- const [theme, setThemeState] = React26.useState("dark");
2447
- React26.useEffect(() => {
2448
- const stored = localStorage.getItem("theme");
2449
- const resolved = stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
2450
- setThemeState(resolved);
2451
- }, []);
3196
+ const [theme, setThemeState] = React29.useState(getInitialTheme);
2452
3197
  const toggle = () => {
2453
3198
  const next = theme === "dark" ? "light" : "dark";
2454
3199
  setThemeState(next);
@@ -2490,8 +3235,154 @@ function ModeSwitchMinimal() {
2490
3235
  mode
2491
3236
  ) });
2492
3237
  }
3238
+ var BRAND_COLORS = [
3239
+ {
3240
+ name: "zinc",
3241
+ label: "Zinc",
3242
+ css: `
3243
+ :root { --primary: oklch(0.205 0 0); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.708 0 0); }
3244
+ .dark { --primary: oklch(0.922 0 0); --primary-foreground: oklch(0.205 0 0); --ring: oklch(0.556 0 0); }
3245
+ `
3246
+ },
3247
+ {
3248
+ name: "blue",
3249
+ label: "Blue",
3250
+ css: `
3251
+ :root { --primary: oklch(0.546 0.245 262.881); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.546 0.245 262.881); }
3252
+ .dark { --primary: oklch(0.623 0.214 259.815); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.623 0.214 259.815); }
3253
+ `
3254
+ },
3255
+ {
3256
+ name: "emerald",
3257
+ label: "Emerald",
3258
+ css: `
3259
+ :root { --primary: oklch(0.596 0.145 163.225); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.596 0.145 163.225); }
3260
+ .dark { --primary: oklch(0.765 0.177 163.223); --primary-foreground: oklch(0.145 0 0); --ring: oklch(0.765 0.177 163.223); }
3261
+ `
3262
+ },
3263
+ {
3264
+ name: "purple",
3265
+ label: "Purple",
3266
+ css: `
3267
+ :root { --primary: oklch(0.558 0.288 302.321); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.558 0.288 302.321); }
3268
+ .dark { --primary: oklch(0.714 0.203 305.504); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.714 0.203 305.504); }
3269
+ `
3270
+ },
3271
+ {
3272
+ name: "rose",
3273
+ label: "Rose",
3274
+ css: `
3275
+ :root { --primary: oklch(0.645 0.246 16.439); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.645 0.246 16.439); }
3276
+ .dark { --primary: oklch(0.717 0.194 17.428); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.717 0.194 17.428); }
3277
+ `
3278
+ },
3279
+ {
3280
+ name: "orange",
3281
+ label: "Orange",
3282
+ css: `
3283
+ :root { --primary: oklch(0.705 0.213 47.604); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.705 0.213 47.604); }
3284
+ .dark { --primary: oklch(0.792 0.184 70.08); --primary-foreground: oklch(0.145 0 0); --ring: oklch(0.792 0.184 70.08); }
3285
+ `
3286
+ },
3287
+ {
3288
+ name: "slate",
3289
+ label: "Slate",
3290
+ css: `
3291
+ :root { --primary: oklch(0.446 0.043 257.281); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.446 0.043 257.281); }
3292
+ .dark { --primary: oklch(0.704 0.04 256.788); --primary-foreground: oklch(0.129 0.042 264.695); --ring: oklch(0.704 0.04 256.788); }
3293
+ `
3294
+ }
3295
+ ];
3296
+ var PREVIEW_HEX = {
3297
+ zinc: "#27272a",
3298
+ blue: "#3b82f6",
3299
+ emerald: "#10b981",
3300
+ purple: "#a855f7",
3301
+ rose: "#f43f5e",
3302
+ orange: "#f97316",
3303
+ slate: "#64748b"
3304
+ };
3305
+ var STORAGE_KEY = "brand-color";
3306
+ var STYLE_ID = "brand-color-override";
3307
+ function applyColor(color) {
3308
+ let el = document.getElementById(STYLE_ID);
3309
+ if (!el) {
3310
+ el = document.createElement("style");
3311
+ el.id = STYLE_ID;
3312
+ document.head.appendChild(el);
3313
+ }
3314
+ el.textContent = color.css;
3315
+ localStorage.setItem(STORAGE_KEY, color.name);
3316
+ }
3317
+ function getInitialColorName() {
3318
+ if (typeof localStorage === "undefined") return "emerald";
3319
+ return localStorage.getItem(STORAGE_KEY) ?? "emerald";
3320
+ }
3321
+ function BrandColorSwitchMinimal() {
3322
+ const [active, setActive] = React29.useState(getInitialColorName);
3323
+ const [open, setOpen] = React29.useState(false);
3324
+ React29.useEffect(() => {
3325
+ const saved = localStorage.getItem(STORAGE_KEY) ?? "emerald";
3326
+ const color = BRAND_COLORS.find((c) => c.name === saved);
3327
+ if (color) applyColor(color);
3328
+ }, []);
3329
+ function select(color) {
3330
+ applyColor(color);
3331
+ setActive(color.name);
3332
+ setOpen(false);
3333
+ }
3334
+ const activeHex = PREVIEW_HEX[active] ?? "#27272a";
3335
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
3336
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
3337
+ Button$1,
3338
+ {
3339
+ variant: "ghost",
3340
+ size: "icon",
3341
+ className: "size-8",
3342
+ "aria-label": "Change brand color",
3343
+ children: /* @__PURE__ */ jsxs("span", { className: "relative inline-flex size-4 items-center justify-center", children: [
3344
+ /* @__PURE__ */ jsx(Palette, { className: "size-4" }),
3345
+ /* @__PURE__ */ jsx(
3346
+ "span",
3347
+ {
3348
+ className: "absolute -bottom-0.5 -right-0.5 size-1.5 rounded-full ring-1 ring-background",
3349
+ style: { background: activeHex }
3350
+ }
3351
+ )
3352
+ ] })
3353
+ }
3354
+ ) }),
3355
+ /* @__PURE__ */ jsxs(PopoverContent, { className: "w-auto p-3", align: "end", children: [
3356
+ /* @__PURE__ */ jsx("p", { className: "mb-2.5 text-xs font-medium text-muted-foreground", children: "Brand color" }),
3357
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 gap-1.5", children: BRAND_COLORS.map((color) => /* @__PURE__ */ jsxs(
3358
+ "button",
3359
+ {
3360
+ type: "button",
3361
+ onClick: () => select(color),
3362
+ title: color.label,
3363
+ className: "group flex flex-col items-center gap-1",
3364
+ children: [
3365
+ /* @__PURE__ */ jsx(
3366
+ "span",
3367
+ {
3368
+ className: "flex size-7 items-center justify-center rounded-full ring-offset-background transition-all group-hover:scale-110",
3369
+ style: {
3370
+ background: PREVIEW_HEX[color.name],
3371
+ boxShadow: active === color.name ? `0 0 0 2px var(--background), 0 0 0 4px ${PREVIEW_HEX[color.name]}` : void 0
3372
+ },
3373
+ children: active === color.name && /* @__PURE__ */ jsx("svg", { className: "size-3 text-white", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", children: /* @__PURE__ */ jsx("path", { d: "M20 6L9 17l-5-5", strokeLinecap: "round", strokeLinejoin: "round" }) })
3374
+ }
3375
+ ),
3376
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: color.label })
3377
+ ]
3378
+ },
3379
+ color.name
3380
+ )) })
3381
+ ] })
3382
+ ] });
3383
+ }
2493
3384
  function ThemeColorUpdater({ colorTheme }) {
2494
- React26.useEffect(() => {
3385
+ React29.useEffect(() => {
2495
3386
  if (colorTheme) {
2496
3387
  document.documentElement.setAttribute("data-theme", colorTheme);
2497
3388
  } else {
@@ -2501,7 +3392,7 @@ function ThemeColorUpdater({ colorTheme }) {
2501
3392
  return null;
2502
3393
  }
2503
3394
  function VersionBanner({ version, message, className, onDismiss }) {
2504
- const [dismissed, setDismissed] = React26.useState(false);
3395
+ const [dismissed, setDismissed] = React29.useState(false);
2505
3396
  if (dismissed) return null;
2506
3397
  return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-4 bg-primary/10 px-4 py-2 text-sm", className), children: [
2507
3398
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -2541,7 +3432,7 @@ function DevBanner({ environment = "development", className }) {
2541
3432
  );
2542
3433
  }
2543
3434
  function RegisterHotkeys({ hotkeys }) {
2544
- React26.useEffect(() => {
3435
+ React29.useEffect(() => {
2545
3436
  const handleKeyDown = (event) => {
2546
3437
  for (const hotkey of hotkeys) {
2547
3438
  const matches = event.key.toLowerCase() === hotkey.key.toLowerCase() && !!event.ctrlKey === !!hotkey.ctrl && !!event.metaKey === !!hotkey.meta && !!event.shiftKey === !!hotkey.shift && !!event.altKey === !!hotkey.alt;
@@ -2600,6 +3491,16 @@ function PostList({ posts, renderLink, emptyMessage = "No posts published yet."
2600
3491
  }
2601
3492
  return /* @__PURE__ */ jsx("div", { className: "grid gap-8 sm:grid-cols-2", children: posts.map((post) => /* @__PURE__ */ jsx(PostCard, { ...post, renderLink }, post.slug)) });
2602
3493
  }
3494
+ var releaseTypeLabel = {
3495
+ release: "Major Release",
3496
+ fix: "Fix",
3497
+ enhancement: "Enhancement"
3498
+ };
3499
+ var releaseTypeVariant = {
3500
+ release: "default",
3501
+ fix: "outline",
3502
+ enhancement: "secondary"
3503
+ };
2603
3504
  function formatDate2(dateStr) {
2604
3505
  return new Date(dateStr).toLocaleDateString("en-US", {
2605
3506
  year: "numeric",
@@ -2613,6 +3514,8 @@ function ChangelogCard({
2613
3514
  date,
2614
3515
  slug,
2615
3516
  version,
3517
+ releaseType,
3518
+ highlights,
2616
3519
  hrefPrefix = "/changelog",
2617
3520
  renderLink
2618
3521
  }) {
@@ -2621,18 +3524,44 @@ function ChangelogCard({
2621
3524
  children,
2622
3525
  className
2623
3526
  }) => renderLink ? renderLink({ href, children, className }) : /* @__PURE__ */ jsx("a", { href, className, children });
2624
- return /* @__PURE__ */ jsxs("article", { className: "group flex flex-col gap-3 border-b border-border/60 pb-8 last:border-0 last:pb-0", children: [
2625
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 text-sm text-muted-foreground", children: [
2626
- /* @__PURE__ */ jsx("time", { dateTime: date, children: formatDate2(date) }),
2627
- version && /* @__PURE__ */ jsxs(Fragment, { children: [
2628
- /* @__PURE__ */ jsx("span", { children: "\xB7" }),
2629
- /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "font-mono text-xs", children: version })
2630
- ] })
2631
- ] }),
2632
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold leading-snug tracking-tight", children: /* @__PURE__ */ jsx(LinkWrapper, { className: "transition-colors hover:text-primary", children: title }) }),
2633
- /* @__PURE__ */ jsx("p", { className: cn$1("line-clamp-3 text-sm text-muted-foreground"), children: summary }),
2634
- /* @__PURE__ */ jsx(LinkWrapper, { className: "text-sm font-medium text-primary hover:underline", children: "Read release notes \u2192" })
2635
- ] });
3527
+ const hasHighlights = highlights && highlights.length > 0;
3528
+ return /* @__PURE__ */ jsxs(
3529
+ "article",
3530
+ {
3531
+ className: cn$1(
3532
+ "flex flex-col gap-5 rounded-2xl border border-border bg-card p-6 sm:p-8",
3533
+ !hasHighlights && "border-b border-border/60 rounded-none bg-transparent p-0 pb-8 last:pb-0 last:border-0"
3534
+ ),
3535
+ children: [
3536
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
3537
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
3538
+ /* @__PURE__ */ jsx("time", { className: "text-sm text-muted-foreground", dateTime: date, children: formatDate2(date) }),
3539
+ version && /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "font-mono text-xs", children: version }),
3540
+ releaseType && /* @__PURE__ */ jsx(Badge$1, { variant: releaseTypeVariant[releaseType], className: "text-xs", children: releaseTypeLabel[releaseType] })
3541
+ ] }),
3542
+ /* @__PURE__ */ jsxs(LinkWrapper, { className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline", children: [
3543
+ "Read update",
3544
+ /* @__PURE__ */ jsx(ArrowRight, { className: "size-3.5" })
3545
+ ] })
3546
+ ] }),
3547
+ /* @__PURE__ */ jsxs("div", { children: [
3548
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold leading-snug tracking-tight", children: /* @__PURE__ */ jsx(LinkWrapper, { className: "transition-colors hover:text-primary", children: title }) }),
3549
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-relaxed text-muted-foreground", children: summary })
3550
+ ] }),
3551
+ hasHighlights && /* @__PURE__ */ jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: highlights.map((h) => /* @__PURE__ */ jsxs(
3552
+ "div",
3553
+ {
3554
+ className: "rounded-xl border border-border/70 bg-background p-4",
3555
+ children: [
3556
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold leading-snug", children: h.title }),
3557
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: h.description })
3558
+ ]
3559
+ },
3560
+ h.title
3561
+ )) })
3562
+ ]
3563
+ }
3564
+ );
2636
3565
  }
2637
3566
  function ChangelogList({
2638
3567
  entries,
@@ -2661,36 +3590,36 @@ function useMounted() {
2661
3590
  return mounted;
2662
3591
  }
2663
3592
  function useConfirm() {
2664
- const [isOpen, setIsOpen] = React26.useState(false);
2665
- const [options, setOptions] = React26.useState({});
2666
- const resolveRef = React26.useRef(null);
2667
- const confirm = React26.useCallback((opts = {}) => {
3593
+ const [isOpen, setIsOpen] = React29.useState(false);
3594
+ const [options, setOptions] = React29.useState({});
3595
+ const resolveRef = React29.useRef(null);
3596
+ const confirm = React29.useCallback((opts = {}) => {
2668
3597
  setOptions(opts);
2669
3598
  setIsOpen(true);
2670
3599
  return new Promise((resolve) => {
2671
3600
  resolveRef.current = resolve;
2672
3601
  });
2673
3602
  }, []);
2674
- const handleConfirm = React26.useCallback(() => {
3603
+ const handleConfirm = React29.useCallback(() => {
2675
3604
  resolveRef.current?.(true);
2676
3605
  setIsOpen(false);
2677
3606
  }, []);
2678
- const handleCancel = React26.useCallback(() => {
3607
+ const handleCancel = React29.useCallback(() => {
2679
3608
  resolveRef.current?.(false);
2680
3609
  setIsOpen(false);
2681
3610
  }, []);
2682
3611
  return { confirm, isOpen, options, handleConfirm, handleCancel };
2683
3612
  }
2684
3613
  function useControlledOpen(defaultOpen = false) {
2685
- const [isOpen, setIsOpen] = React26.useState(defaultOpen);
2686
- const open = React26.useCallback(() => setIsOpen(true), []);
2687
- const close = React26.useCallback(() => setIsOpen(false), []);
2688
- const toggle = React26.useCallback(() => setIsOpen((prev) => !prev), []);
3614
+ const [isOpen, setIsOpen] = React29.useState(defaultOpen);
3615
+ const open = React29.useCallback(() => setIsOpen(true), []);
3616
+ const close = React29.useCallback(() => setIsOpen(false), []);
3617
+ const toggle = React29.useCallback(() => setIsOpen((prev) => !prev), []);
2689
3618
  return { isOpen, open, close, toggle, setIsOpen };
2690
3619
  }
2691
3620
  function useScrolledPast(threshold) {
2692
- const [scrolledPast, setScrolledPast] = React26.useState(false);
2693
- React26.useEffect(() => {
3621
+ const [scrolledPast, setScrolledPast] = React29.useState(false);
3622
+ React29.useEffect(() => {
2694
3623
  const handleScroll = () => {
2695
3624
  setScrolledPast(window.scrollY > threshold);
2696
3625
  };
@@ -2701,30 +3630,30 @@ function useScrolledPast(threshold) {
2701
3630
  return scrolledPast;
2702
3631
  }
2703
3632
  function useCopyToClipboard() {
2704
- const [copied, setCopied] = React26.useState(false);
2705
- const timeoutRef = React26.useRef(void 0);
2706
- const copy = React26.useCallback((text) => {
3633
+ const [copied, setCopied] = React29.useState(false);
3634
+ const timeoutRef = React29.useRef(void 0);
3635
+ const copy = React29.useCallback((text) => {
2707
3636
  navigator.clipboard.writeText(text).then(() => {
2708
3637
  setCopied(true);
2709
3638
  clearTimeout(timeoutRef.current);
2710
3639
  timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
2711
3640
  });
2712
3641
  }, []);
2713
- React26.useEffect(() => () => clearTimeout(timeoutRef.current), []);
3642
+ React29.useEffect(() => () => clearTimeout(timeoutRef.current), []);
2714
3643
  return [copied, copy];
2715
3644
  }
2716
3645
  function useDebounce(value, delay) {
2717
- const [debounced, setDebounced] = React26.useState(value);
2718
- React26.useEffect(() => {
3646
+ const [debounced, setDebounced] = React29.useState(value);
3647
+ React29.useEffect(() => {
2719
3648
  const timer = setTimeout(() => setDebounced(value), delay);
2720
3649
  return () => clearTimeout(timer);
2721
3650
  }, [value, delay]);
2722
3651
  return debounced;
2723
3652
  }
2724
3653
  function useIntersectionObserver(options) {
2725
- const ref = React26.useRef(null);
2726
- const [isIntersecting, setIsIntersecting] = React26.useState(false);
2727
- React26.useEffect(() => {
3654
+ const ref = React29.useRef(null);
3655
+ const [isIntersecting, setIsIntersecting] = React29.useState(false);
3656
+ React29.useEffect(() => {
2728
3657
  const el = ref.current;
2729
3658
  if (!el) return;
2730
3659
  const observer = new IntersectionObserver(([entry]) => {
@@ -2736,7 +3665,7 @@ function useIntersectionObserver(options) {
2736
3665
  return [ref, isIntersecting];
2737
3666
  }
2738
3667
  function useLocalStorage(key, initialValue) {
2739
- const [storedValue, setStoredValue] = React26.useState(() => {
3668
+ const [storedValue, setStoredValue] = React29.useState(() => {
2740
3669
  if (typeof window === "undefined") return initialValue;
2741
3670
  try {
2742
3671
  const item = window.localStorage.getItem(key);
@@ -2745,7 +3674,7 @@ function useLocalStorage(key, initialValue) {
2745
3674
  return initialValue;
2746
3675
  }
2747
3676
  });
2748
- const setValue = React26.useCallback(
3677
+ const setValue = React29.useCallback(
2749
3678
  (value) => {
2750
3679
  try {
2751
3680
  setStoredValue(value);
@@ -2760,11 +3689,11 @@ function useLocalStorage(key, initialValue) {
2760
3689
  return [storedValue, setValue];
2761
3690
  }
2762
3691
  function useMediaQuery(query) {
2763
- const [matches, setMatches] = React26.useState(() => {
3692
+ const [matches, setMatches] = React29.useState(() => {
2764
3693
  if (typeof window === "undefined") return false;
2765
3694
  return window.matchMedia(query).matches;
2766
3695
  });
2767
- React26.useEffect(() => {
3696
+ React29.useEffect(() => {
2768
3697
  if (typeof window === "undefined") return;
2769
3698
  const mql = window.matchMedia(query);
2770
3699
  setMatches(mql.matches);
@@ -2775,18 +3704,18 @@ function useMediaQuery(query) {
2775
3704
  return matches;
2776
3705
  }
2777
3706
  function usePagination(total, pageSize) {
2778
- const [page, setPage] = React26.useState(1);
3707
+ const [page, setPage] = React29.useState(1);
2779
3708
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
2780
3709
  const offset = (page - 1) * pageSize;
2781
- const goTo = React26.useCallback(
3710
+ const goTo = React29.useCallback(
2782
3711
  (p) => setPage(Math.min(Math.max(1, p), totalPages)),
2783
3712
  [totalPages]
2784
3713
  );
2785
- const next = React26.useCallback(() => goTo(page + 1), [page, goTo]);
2786
- const prev = React26.useCallback(() => goTo(page - 1), [page, goTo]);
3714
+ const next = React29.useCallback(() => goTo(page + 1), [page, goTo]);
3715
+ const prev = React29.useCallback(() => goTo(page - 1), [page, goTo]);
2787
3716
  return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
2788
3717
  }
2789
3718
 
2790
- export { AppContent, AppGrid, AppGridCell, AppScreen, AppShell, AuthSection, Badge, Button, Card, CarouselSection, ChangelogCard, ChangelogList, Checkbox, ConfirmDialog, ContactSection, ContextMenu, CountUp, CtaSection, DevBanner, Dock, EmptyState, ErrorPage, FadeIn, FaqSection, FeatureCard, FeaturesSection, Footer, FullPageSpinner, GlassCard, Grid, GridItem, HeroSection, ImageCard, Input, LogoStrip, ModeSwitchMinimal, Navbar, NewsletterSection, OlwibaUIProvider, Overlay, PageHeader, PageTransition, PhoneFrame, PostCard, PostList, PricingCard, PricingSection, PublicPageFrame, RegisterHotkeys, RootErrorFallback, Section, SectionTitle, Spotlight, Stack, StaggerChildren, StatCard, StatsSection, Suspensed, Switch, TeamSection, TestimonialCard, TestimonialsSection, Textarea, ThemeColorUpdater, ThemeSwitchMinimal, Underlay, UpgradePrompt, VersionBanner, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode };
3719
+ export { AnimatedPill, AppContent, AppGrid, AppGridCell, AppScreen, AppShell, AuthSection, Badge, BrandColorSwitchMinimal, Button, Card, CarouselSection, ChangelogCard, ChangelogList, Checkbox, ComparisonSection, ConfirmDialog, ContactSection, ContextMenu, CountUp, CountdownTimer, CtaCardSection, CtaSection, DevBanner, Dock, EmptyState, ErrorPage, FadeIn, FaqSection, FeatureCard, FeatureMarqueeSection, FeaturesSection, FlowBracket, FlowConnector, Footer, FullPageSpinner, GlassCard, Grid, GridItem, GroupedFeaturesSection, HeroSection, ImageCard, Input, LogoStrip, ModeSwitchMinimal, Navbar, NewsletterSection, OlwibaUIProvider, Overlay, PageHeader, PageTransition, PhoneFrame, PostCard, PostList, PricingCard, PricingSection, PublicPageFrame, QualificationSection, RegisterHotkeys, RootErrorFallback, Section, SectionTitle, Spotlight, Stack, StaggerChildren, StatCard, StatsSection, StepsSection, Suspensed, Switch, TeamSection, TechStackSection, TestimonialCard, TestimonialsSection, Textarea, ThemeColorUpdater, ThemeSwitchMinimal, Underlay, UpgradePrompt, VersionBanner, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode };
2791
3720
  //# sourceMappingURL=index.js.map
2792
3721
  //# sourceMappingURL=index.js.map