@caqophony/ui 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1439 @@
1
+ 'use client';
2
+ import {
3
+ Button,
4
+ Container,
5
+ NavbarMenu
6
+ } from "./chunk-I5DQCG6D.js";
7
+ import {
8
+ ScrollHintXMark
9
+ } from "./chunk-ID7VBGJA.js";
10
+ import {
11
+ cn
12
+ } from "./chunk-DP5WQAPO.js";
13
+
14
+ // src/marketing/marketing-header.tsx
15
+ import * as React from "react";
16
+ import { createPortal } from "react-dom";
17
+ import { jsx, jsxs } from "react/jsx-runtime";
18
+ var NIGHT_GROUND = "-mb-16 justify-between border-b border-border bg-night-0/80 backdrop-blur-md";
19
+ var ON_DARK_GROUND = "text-background dark:text-foreground";
20
+ var DARK_MENU_BUTTON = cn(
21
+ ON_DARK_GROUND,
22
+ "hover:bg-background/10 hover:text-background dark:hover:bg-foreground/10 dark:hover:text-foreground"
23
+ );
24
+ var NIGHT_MENU_BUTTON = "size-11";
25
+ var FOLDED_AWAY = "md:invisible md:absolute md:w-0 md:overflow-hidden";
26
+ var px = (value) => parseFloat(value) || 0;
27
+ function useFold(refs, actionsHost, hasLinks) {
28
+ const [folded, setFolded] = React.useState(false);
29
+ React.useLayoutEffect(() => {
30
+ const { bar, brand, brandText, nav, links, actionsRow, actionsHome } = refs;
31
+ if (!bar.current || !brand.current || !brandText.current) return;
32
+ let actionsWidth = 0;
33
+ const measure = () => {
34
+ const row = bar.current;
35
+ const mark = brand.current;
36
+ const text = brandText.current;
37
+ if (!row || !mark || !text) return;
38
+ const shown = nav.current ?? actionsRow.current;
39
+ if (!shown || getComputedStyle(shown).display === "none") return;
40
+ const home = actionsHome.current;
41
+ if (home && (!actionsHost || home.contains(actionsHost)))
42
+ actionsWidth = home.getBoundingClientRect().width;
43
+ const barStyle = getComputedStyle(row);
44
+ const room = row.clientWidth - px(barStyle.paddingLeft) - px(barStyle.paddingRight);
45
+ const brandWidth = mark.getBoundingClientRect().width - text.getBoundingClientRect().width + text.scrollWidth;
46
+ const linksWidth = nav.current ? px(getComputedStyle(nav.current).marginLeft) + (links.current?.getBoundingClientRect().width ?? 0) : 0;
47
+ const actionsSpace = actionsRow.current ? nav.current ? px(getComputedStyle(actionsRow.current).marginLeft) : px(getComputedStyle(actionsRow.current).paddingLeft) : 0;
48
+ setFolded(
49
+ Math.ceil(brandWidth + linksWidth + actionsSpace + actionsWidth) > room
50
+ );
51
+ };
52
+ measure();
53
+ const observer = new ResizeObserver(measure);
54
+ for (const el of [
55
+ bar.current,
56
+ brandText.current,
57
+ links.current,
58
+ actionsHome.current
59
+ ])
60
+ if (el) observer.observe(el);
61
+ return () => observer.disconnect();
62
+ }, [refs, actionsHost, hasLinks]);
63
+ return folded;
64
+ }
65
+ function MarketingHeader({
66
+ brandName,
67
+ brandInitials,
68
+ navItems = [],
69
+ actions,
70
+ className,
71
+ variant = "light"
72
+ }) {
73
+ const isDark = variant === "dark";
74
+ const isNight = variant === "night";
75
+ const isGlass = isDark || isNight;
76
+ const hasLinks = navItems.length > 0;
77
+ const bar = React.useRef(null);
78
+ const brand = React.useRef(null);
79
+ const brandText = React.useRef(null);
80
+ const nav = React.useRef(null);
81
+ const links = React.useRef(null);
82
+ const actionsRow = React.useRef(null);
83
+ const actionsHome = React.useRef(null);
84
+ const refs = React.useMemo(
85
+ () => ({ bar, brand, brandText, nav, links, actionsRow, actionsHome }),
86
+ []
87
+ );
88
+ const [actionsHost, setActionsHost] = React.useState(
89
+ null
90
+ );
91
+ const hasActions = Boolean(actions);
92
+ React.useLayoutEffect(() => {
93
+ if (!hasActions) return;
94
+ const host = document.createElement("div");
95
+ host.className = "contents";
96
+ actionsHome.current?.appendChild(host);
97
+ setActionsHost(host);
98
+ return () => {
99
+ host.remove();
100
+ setActionsHost(null);
101
+ };
102
+ }, [hasActions]);
103
+ const drawerActions = React.useCallback(
104
+ (slot) => {
105
+ if (actionsHost) (slot ?? actionsHome.current)?.appendChild(actionsHost);
106
+ },
107
+ [actionsHost]
108
+ );
109
+ const folded = useFold(refs, actionsHost, hasLinks);
110
+ return /* @__PURE__ */ jsxs(
111
+ "header",
112
+ {
113
+ ref: bar,
114
+ "data-testid": "marketing-header",
115
+ "data-folded": folded ? "" : void 0,
116
+ "data-surface": isNight ? "night" : void 0,
117
+ "data-marketing-header": isNight ? "night" : void 0,
118
+ className: cn(
119
+ "sticky top-0 z-50 flex h-16 items-center px-6 lg:px-12",
120
+ isNight ? NIGHT_GROUND : isDark ? "justify-between border-b border-primary-foreground/[0.06] bg-foreground/85 backdrop-blur-md dark:bg-background/85" : "border-b border-border bg-card dark:border-border dark:bg-card",
121
+ className
122
+ ),
123
+ children: [
124
+ /* @__PURE__ */ jsxs(
125
+ "a",
126
+ {
127
+ ref: brand,
128
+ href: "/",
129
+ className: cn(
130
+ "flex min-w-0 items-center gap-2.5 text-base font-bold no-underline",
131
+ isDark ? ON_DARK_GROUND : "text-foreground dark:text-foreground"
132
+ ),
133
+ children: [
134
+ /* @__PURE__ */ jsx("div", { className: "bg-primary-solid flex size-8 shrink-0 items-center justify-center rounded-lg text-xs font-extrabold text-primary-foreground", children: brandInitials }),
135
+ /* @__PURE__ */ jsx("span", { ref: brandText, className: "truncate", children: brandName })
136
+ ]
137
+ }
138
+ ),
139
+ hasLinks && /* @__PURE__ */ jsx(
140
+ "nav",
141
+ {
142
+ ref: nav,
143
+ className: cn(
144
+ "hidden min-w-0 flex-1 overflow-x-clip md:flex",
145
+ isGlass ? "ml-6" : "ml-6 lg:ml-12",
146
+ folded && FOLDED_AWAY
147
+ ),
148
+ children: /* @__PURE__ */ jsx(
149
+ "div",
150
+ {
151
+ ref: links,
152
+ className: cn(
153
+ "flex w-max items-center gap-4 lg:gap-8",
154
+ isGlass && "mx-auto"
155
+ ),
156
+ children: navItems.map((item) => /* @__PURE__ */ jsx(
157
+ "a",
158
+ {
159
+ href: item.href,
160
+ className: cn(
161
+ "whitespace-nowrap text-sm font-medium no-underline transition-colors",
162
+ isNight ? cn(
163
+ "flex min-h-[44px] items-center hover:text-foreground",
164
+ item.active ? "font-semibold text-foreground" : "text-muted-foreground"
165
+ ) : isDark ? "flex min-h-[44px] items-center text-background/70 hover:text-background dark:text-foreground/70 dark:hover:text-foreground" : item.active ? "text-primary-text font-semibold" : "text-muted-foreground hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground"
166
+ ),
167
+ children: item.label
168
+ },
169
+ item.label
170
+ ))
171
+ }
172
+ )
173
+ }
174
+ ),
175
+ actions && /* @__PURE__ */ jsx(
176
+ "div",
177
+ {
178
+ ref: actionsRow,
179
+ className: cn(
180
+ "hidden shrink-0 md:flex",
181
+ hasLinks ? "ml-6" : "ml-auto pl-6",
182
+ folded && FOLDED_AWAY
183
+ ),
184
+ children: /* @__PURE__ */ jsx(
185
+ "div",
186
+ {
187
+ ref: actionsHome,
188
+ className: "flex w-max items-center gap-3 whitespace-nowrap",
189
+ children: actionsHost ? createPortal(actions, actionsHost) : actions
190
+ }
191
+ )
192
+ }
193
+ ),
194
+ (hasLinks || actions) && /* @__PURE__ */ jsx(
195
+ NavbarMenu,
196
+ {
197
+ folded,
198
+ triggerClassName: isDark ? DARK_MENU_BUTTON : isNight ? NIGHT_MENU_BUTTON : void 0,
199
+ surface: isNight ? variant : void 0,
200
+ links: hasLinks ? navItems.map((item) => /* @__PURE__ */ jsx(
201
+ "a",
202
+ {
203
+ href: item.href,
204
+ className: cn(
205
+ "text-sm font-medium no-underline",
206
+ item.active ? "text-primary-text" : "text-foreground"
207
+ ),
208
+ children: item.label
209
+ },
210
+ item.label
211
+ )) : void 0,
212
+ actions: actions ? /* @__PURE__ */ jsx(
213
+ "div",
214
+ {
215
+ ref: drawerActions,
216
+ className: "flex flex-col gap-2 [&>*>*]:w-full"
217
+ }
218
+ ) : void 0
219
+ }
220
+ )
221
+ ]
222
+ }
223
+ );
224
+ }
225
+
226
+ // src/marketing/marketing-hero.tsx
227
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
228
+ function MarketingHero({
229
+ headline,
230
+ subtitle,
231
+ actions,
232
+ visual,
233
+ layout = "centered",
234
+ className
235
+ }) {
236
+ if (layout === "split") {
237
+ return /* @__PURE__ */ jsx2(
238
+ "section",
239
+ {
240
+ "data-testid": "marketing-hero",
241
+ className: cn("bg-primary-solid px-6 py-20 lg:px-12", className),
242
+ children: /* @__PURE__ */ jsxs2("div", { className: "mx-auto grid max-w-[1200px] grid-cols-1 items-center gap-16 md:grid-cols-2", children: [
243
+ /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-5", children: [
244
+ /* @__PURE__ */ jsx2("h1", { className: "text-4xl font-black leading-tight text-primary-foreground md:text-5xl", children: headline }),
245
+ /* @__PURE__ */ jsx2("p", { className: "text-lg font-normal leading-relaxed text-primary-foreground", children: subtitle }),
246
+ actions && /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap gap-4", children: actions })
247
+ ] }),
248
+ visual && /* @__PURE__ */ jsx2("div", { className: "flex items-end justify-end", children: visual })
249
+ ] })
250
+ }
251
+ );
252
+ }
253
+ return /* @__PURE__ */ jsxs2(
254
+ "section",
255
+ {
256
+ "data-testid": "marketing-hero",
257
+ className: cn(
258
+ "bg-primary-solid px-6 pb-20 pt-24 text-center lg:px-12",
259
+ className
260
+ ),
261
+ children: [
262
+ /* @__PURE__ */ jsx2("h1", { className: "mx-auto mb-6 max-w-[800px] text-4xl font-black leading-tight text-primary-foreground md:text-6xl", children: headline }),
263
+ /* @__PURE__ */ jsx2("p", { className: "mx-auto mb-10 max-w-[640px] text-xl font-normal leading-relaxed text-primary-foreground", children: subtitle }),
264
+ actions && /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap justify-center gap-4", children: actions })
265
+ ]
266
+ }
267
+ );
268
+ }
269
+
270
+ // src/marketing/feature-card.tsx
271
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
272
+ function FeatureCard({
273
+ icon,
274
+ title,
275
+ description,
276
+ className
277
+ }) {
278
+ return /* @__PURE__ */ jsxs3(
279
+ "div",
280
+ {
281
+ "data-testid": "feature-card",
282
+ className: cn(
283
+ "rounded-xl border border-border bg-card p-6 shadow-sm dark:border-border dark:bg-card",
284
+ className
285
+ ),
286
+ children: [
287
+ /* @__PURE__ */ jsx3("div", { className: "mb-4 flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10 dark:bg-primary/10", children: /* @__PURE__ */ jsx3("div", { className: "text-primary-text dark:text-primary-text h-6 w-6", children: icon }) }),
288
+ /* @__PURE__ */ jsx3("h3", { className: "mb-2 text-base font-bold text-foreground dark:text-foreground", children: title }),
289
+ /* @__PURE__ */ jsx3("p", { className: "text-sm leading-relaxed text-muted-foreground dark:text-muted-foreground", children: description })
290
+ ]
291
+ }
292
+ );
293
+ }
294
+
295
+ // src/marketing/pricing-tier.tsx
296
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
297
+ function PricingTier({
298
+ name,
299
+ price,
300
+ period,
301
+ features,
302
+ highlighted = false,
303
+ action,
304
+ className
305
+ }) {
306
+ return /* @__PURE__ */ jsxs4(
307
+ "div",
308
+ {
309
+ "data-testid": "pricing-tier",
310
+ className: cn(
311
+ "relative rounded-xl border bg-card p-8 text-center dark:bg-card",
312
+ highlighted ? "border-primary shadow-lg ring-2 ring-primary/10 dark:border-primary dark:ring-primary/10" : "border-border dark:border-border",
313
+ className
314
+ ),
315
+ children: [
316
+ /* @__PURE__ */ jsx4("div", { className: "mb-2 text-lg font-bold text-foreground dark:text-foreground", children: name }),
317
+ /* @__PURE__ */ jsx4("div", { className: "text-primary-text dark:text-primary-text text-4xl font-black", children: price }),
318
+ /* @__PURE__ */ jsx4("div", { className: "mb-6 text-sm text-muted-foreground dark:text-muted-foreground", children: period }),
319
+ /* @__PURE__ */ jsx4("ul", { className: "mb-6 space-y-1.5 text-left", children: features.map((feature) => /* @__PURE__ */ jsxs4(
320
+ "li",
321
+ {
322
+ className: "relative pl-6 text-sm text-foreground dark:text-foreground",
323
+ children: [
324
+ /* @__PURE__ */ jsx4("span", { className: "bg-intent-success dark:bg-intent-success absolute left-0 top-[7px] h-2 w-2 rounded-full" }),
325
+ feature
326
+ ]
327
+ },
328
+ feature
329
+ )) }),
330
+ action && /* @__PURE__ */ jsx4("div", { className: "w-full", children: action })
331
+ ]
332
+ }
333
+ );
334
+ }
335
+
336
+ // src/marketing/faq-item.tsx
337
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
338
+ function MarketingFAQItem({
339
+ question,
340
+ answer,
341
+ dark = false,
342
+ className
343
+ }) {
344
+ return /* @__PURE__ */ jsxs5(
345
+ "div",
346
+ {
347
+ "data-testid": "marketing-faq-item",
348
+ className: cn(
349
+ "border-b py-6",
350
+ dark ? "border-muted-foreground/20 dark:border-muted-foreground/20" : "border-border dark:border-border",
351
+ className
352
+ ),
353
+ children: [
354
+ /* @__PURE__ */ jsx5(
355
+ "h3",
356
+ {
357
+ className: cn(
358
+ "mb-3 text-base font-semibold",
359
+ dark ? "text-primary-foreground dark:text-foreground" : "text-foreground dark:text-foreground"
360
+ ),
361
+ children: question
362
+ }
363
+ ),
364
+ /* @__PURE__ */ jsx5(
365
+ "p",
366
+ {
367
+ className: cn(
368
+ "text-sm leading-[1.7]",
369
+ dark ? "text-primary-foreground/70 dark:text-muted-foreground" : "text-muted-foreground dark:text-muted-foreground"
370
+ ),
371
+ children: answer
372
+ }
373
+ )
374
+ ]
375
+ }
376
+ );
377
+ }
378
+
379
+ // src/marketing/cta-banner.tsx
380
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
381
+ function CTABanner({
382
+ headline,
383
+ description,
384
+ actions,
385
+ className
386
+ }) {
387
+ return /* @__PURE__ */ jsxs6(
388
+ "section",
389
+ {
390
+ "data-testid": "cta-banner",
391
+ className: cn(
392
+ "bg-primary-solid px-6 py-20 text-center lg:px-12",
393
+ className
394
+ ),
395
+ children: [
396
+ /* @__PURE__ */ jsx6("h2", { className: "mb-4 text-4xl font-extrabold text-primary-foreground", children: headline }),
397
+ /* @__PURE__ */ jsx6("p", { className: "mb-8 text-lg text-primary-foreground", children: description }),
398
+ actions && /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap justify-center gap-4", children: actions })
399
+ ]
400
+ }
401
+ );
402
+ }
403
+
404
+ // src/marketing/marketing-cta.tsx
405
+ import { jsx as jsx7 } from "react/jsx-runtime";
406
+ var TREATMENT = {
407
+ light: {
408
+ // the edge is `primary-text`, which reads on the page in either scheme: a
409
+ // dark primary's fill alone sinks into a dark page
410
+ primary: "border-primary-text bg-primary-solid text-primary-foreground hover:opacity-hover",
411
+ secondary: "border-primary-text text-primary-text hover:bg-muted"
412
+ },
413
+ brand: {
414
+ primary: "bg-brand-fill text-brand-fill-foreground hover:opacity-hover",
415
+ secondary: "border-brand-fill text-brand-fill hover:bg-brand-fill hover:text-brand-fill-foreground"
416
+ },
417
+ dark: {
418
+ primary: "bg-night-accent text-night-accent-foreground hover:opacity-hover",
419
+ secondary: "border-night-muted-foreground text-night-foreground hover:bg-night-muted"
420
+ },
421
+ image: {
422
+ primary: "bg-night-accent text-night-accent-foreground shadow-lg hover:opacity-hover",
423
+ secondary: "border-night-muted-foreground bg-night-0 text-night-foreground shadow-lg hover:bg-night-muted"
424
+ }
425
+ };
426
+ var FOCUS = {
427
+ light: "focus-visible:outline-primary-text",
428
+ brand: "focus-visible:outline-brand-fill",
429
+ dark: "focus-visible:outline-night-foreground",
430
+ image: "focus-visible:outline-night-foreground"
431
+ };
432
+ function MarketingCta({
433
+ href,
434
+ ground,
435
+ emphasis,
436
+ className,
437
+ children,
438
+ ...anchor
439
+ }) {
440
+ return /* @__PURE__ */ jsx7(
441
+ "a",
442
+ {
443
+ ...anchor,
444
+ href,
445
+ "data-cta-ground": ground,
446
+ "data-cta-emphasis": emphasis,
447
+ "data-border-current": emphasis === "secondary" ? "" : void 0,
448
+ className: cn(
449
+ "inline-flex min-h-12 items-center justify-center rounded-lg border-2 border-transparent px-6 py-2.5 text-center text-base font-semibold",
450
+ "motion-safe:duration-fast motion-safe:transition-colors",
451
+ "focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2",
452
+ TREATMENT[ground][emphasis],
453
+ FOCUS[ground],
454
+ className
455
+ ),
456
+ children
457
+ }
458
+ );
459
+ }
460
+
461
+ // src/marketing/how-it-works-step.tsx
462
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
463
+ function HowItWorksStep({
464
+ stepNumber,
465
+ title,
466
+ description,
467
+ className
468
+ }) {
469
+ return /* @__PURE__ */ jsxs7(
470
+ "div",
471
+ {
472
+ "data-testid": "how-it-works-step",
473
+ className: cn("text-center", className),
474
+ children: [
475
+ /* @__PURE__ */ jsx8("div", { className: "bg-primary-solid mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full text-xl font-bold text-primary-foreground", children: stepNumber }),
476
+ /* @__PURE__ */ jsx8("h3", { className: "mb-2 text-base font-bold text-foreground dark:text-foreground", children: title }),
477
+ /* @__PURE__ */ jsx8("p", { className: "text-sm leading-relaxed text-muted-foreground dark:text-muted-foreground", children: description })
478
+ ]
479
+ }
480
+ );
481
+ }
482
+
483
+ // src/marketing/use-case-card.tsx
484
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
485
+ function UseCaseCard({
486
+ persona,
487
+ scenario,
488
+ outcome,
489
+ className
490
+ }) {
491
+ return /* @__PURE__ */ jsxs8(
492
+ "div",
493
+ {
494
+ "data-testid": "use-case-card",
495
+ className: cn(
496
+ "rounded-xl border border-border bg-card p-8 dark:border-border dark:bg-card",
497
+ className
498
+ ),
499
+ children: [
500
+ /* @__PURE__ */ jsx9("h3", { className: "mb-3 text-lg font-bold text-foreground dark:text-foreground", children: persona }),
501
+ /* @__PURE__ */ jsx9("p", { className: "mb-4 text-sm leading-relaxed text-muted-foreground dark:text-muted-foreground", children: scenario }),
502
+ /* @__PURE__ */ jsx9("p", { className: "text-intent-success-foreground text-sm font-medium leading-normal", children: outcome })
503
+ ]
504
+ }
505
+ );
506
+ }
507
+
508
+ // src/marketing/blog-grid.tsx
509
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
510
+ function PostCard({
511
+ post,
512
+ featured = false
513
+ }) {
514
+ const Wrapper = post.href ? "a" : "div";
515
+ const wrapperProps = post.href ? { href: post.href } : {};
516
+ return /* @__PURE__ */ jsxs9(
517
+ Wrapper,
518
+ {
519
+ ...wrapperProps,
520
+ className: cn(
521
+ "group flex flex-col overflow-hidden rounded-xl border border-border bg-card shadow-sm transition-shadow hover:shadow-md",
522
+ featured && "sm:flex-row"
523
+ ),
524
+ children: [
525
+ post.thumbnail && /* @__PURE__ */ jsx10(
526
+ "div",
527
+ {
528
+ className: cn(
529
+ "overflow-hidden bg-muted",
530
+ featured ? "aspect-video sm:w-1/2" : "aspect-video w-full"
531
+ ),
532
+ children: /* @__PURE__ */ jsx10(
533
+ "img",
534
+ {
535
+ src: post.thumbnail,
536
+ alt: post.title,
537
+ className: "h-full w-full object-cover transition-transform group-hover:scale-105"
538
+ }
539
+ )
540
+ }
541
+ ),
542
+ /* @__PURE__ */ jsxs9(
543
+ "div",
544
+ {
545
+ className: cn("flex flex-1 flex-col gap-2 p-4", featured && "sm:p-6"),
546
+ children: [
547
+ post.category && /* @__PURE__ */ jsx10("span", { className: "bg-primary-solid w-fit rounded-full px-2.5 py-0.5 text-xs font-medium text-primary-foreground", children: post.category }),
548
+ /* @__PURE__ */ jsx10(
549
+ "h3",
550
+ {
551
+ className: cn(
552
+ "line-clamp-2 font-semibold text-foreground",
553
+ featured ? "text-lg" : "text-sm"
554
+ ),
555
+ children: post.title
556
+ }
557
+ ),
558
+ post.excerpt && /* @__PURE__ */ jsx10("p", { className: "line-clamp-2 text-xs text-muted-foreground", children: post.excerpt }),
559
+ /* @__PURE__ */ jsxs9("div", { className: "mt-auto flex items-center gap-2 pt-2", children: [
560
+ post.authorAvatar && /* @__PURE__ */ jsx10(
561
+ "img",
562
+ {
563
+ src: post.authorAvatar,
564
+ alt: post.author ?? "",
565
+ className: "h-6 w-6 rounded-full object-cover"
566
+ }
567
+ ),
568
+ post.author && /* @__PURE__ */ jsx10("span", { className: "text-xs font-medium text-foreground", children: post.author }),
569
+ /* @__PURE__ */ jsx10("span", { className: "text-xs text-muted-foreground", children: post.date })
570
+ ] })
571
+ ]
572
+ }
573
+ )
574
+ ]
575
+ }
576
+ );
577
+ }
578
+ function PostRow({ post }) {
579
+ const Wrapper = post.href ? "a" : "div";
580
+ const wrapperProps = post.href ? { href: post.href } : {};
581
+ return /* @__PURE__ */ jsxs9(
582
+ Wrapper,
583
+ {
584
+ ...wrapperProps,
585
+ className: "group flex gap-4 border-b border-border py-4 last:border-b-0",
586
+ children: [
587
+ post.thumbnail && /* @__PURE__ */ jsx10("div", { className: "h-20 w-28 flex-shrink-0 overflow-hidden rounded-lg bg-muted", children: /* @__PURE__ */ jsx10(
588
+ "img",
589
+ {
590
+ src: post.thumbnail,
591
+ alt: post.title,
592
+ className: "h-full w-full object-cover"
593
+ }
594
+ ) }),
595
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-1 flex-col gap-1", children: [
596
+ post.category && /* @__PURE__ */ jsx10("span", { className: "bg-primary-solid w-fit rounded-full px-2 py-0.5 text-xs font-medium text-primary-foreground", children: post.category }),
597
+ /* @__PURE__ */ jsx10("h3", { className: "line-clamp-1 text-sm font-semibold text-foreground group-hover:underline", children: post.title }),
598
+ post.excerpt && /* @__PURE__ */ jsx10("p", { className: "line-clamp-1 text-xs text-muted-foreground", children: post.excerpt }),
599
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
600
+ post.author && /* @__PURE__ */ jsx10("span", { className: "text-xs text-muted-foreground", children: post.author }),
601
+ /* @__PURE__ */ jsx10("span", { className: "text-xs text-muted-foreground", children: post.date })
602
+ ] })
603
+ ] })
604
+ ]
605
+ }
606
+ );
607
+ }
608
+ function BlogGrid({
609
+ variant = "threeColumn",
610
+ posts,
611
+ heading,
612
+ description,
613
+ className,
614
+ ...props
615
+ }) {
616
+ return /* @__PURE__ */ jsxs9(
617
+ "section",
618
+ {
619
+ className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
620
+ ...props,
621
+ children: [
622
+ (heading || description) && /* @__PURE__ */ jsxs9("div", { className: "mx-auto mb-10 max-w-2xl text-center", children: [
623
+ heading && /* @__PURE__ */ jsx10("h2", { className: "text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
624
+ description && /* @__PURE__ */ jsx10("p", { className: "mt-3 text-sm text-muted-foreground", children: description })
625
+ ] }),
626
+ variant === "threeColumn" && /* @__PURE__ */ jsx10("div", { className: "mx-auto grid max-w-5xl grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: posts.map((p) => /* @__PURE__ */ jsx10(PostCard, { post: p }, p.id)) }),
627
+ variant === "featured" && posts.length > 0 && /* @__PURE__ */ jsxs9("div", { className: "mx-auto max-w-5xl space-y-6", children: [
628
+ /* @__PURE__ */ jsx10(PostCard, { post: posts[0], featured: true }),
629
+ posts.length > 1 && /* @__PURE__ */ jsx10("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: posts.slice(1).map((p) => /* @__PURE__ */ jsx10(PostCard, { post: p }, p.id)) })
630
+ ] }),
631
+ variant === "list" && /* @__PURE__ */ jsx10("div", { className: "mx-auto max-w-3xl", children: posts.map((p) => /* @__PURE__ */ jsx10(PostRow, { post: p }, p.id)) })
632
+ ]
633
+ }
634
+ );
635
+ }
636
+
637
+ // src/marketing/comparison-table.tsx
638
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
639
+ function ComparisonTable({
640
+ variant = "simple",
641
+ plans,
642
+ features,
643
+ heading,
644
+ className,
645
+ ...props
646
+ }) {
647
+ const featuredPlan = variant === "featured" ? plans.find((p) => p.featured) : null;
648
+ return /* @__PURE__ */ jsxs10("div", { className: cn("w-full", className), ...props, children: [
649
+ heading && /* @__PURE__ */ jsx11("h2", { className: "mb-8 text-center text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
650
+ /* @__PURE__ */ jsxs10("div", { className: "flex w-full overflow-x-auto", children: [
651
+ /* @__PURE__ */ jsxs10("table", { className: "w-full border-collapse", children: [
652
+ /* @__PURE__ */ jsx11("thead", { children: /* @__PURE__ */ jsxs10("tr", { children: [
653
+ /* @__PURE__ */ jsx11("td", { className: "min-w-[180px] border-b border-border p-4" }),
654
+ plans.map((plan) => /* @__PURE__ */ jsxs10(
655
+ "th",
656
+ {
657
+ className: cn(
658
+ "min-w-[140px] border-b border-l border-border p-4 text-center",
659
+ featuredPlan?.id === plan.id && "bg-primary/5"
660
+ ),
661
+ children: [
662
+ featuredPlan?.id === plan.id && plan.badge && /* @__PURE__ */ jsx11("span", { className: "bg-primary-solid mb-2 inline-block rounded-full px-2.5 py-0.5 text-xs font-medium text-primary-foreground", children: plan.badge }),
663
+ /* @__PURE__ */ jsx11("div", { className: "text-sm font-semibold text-foreground", children: plan.name }),
664
+ plan.description && /* @__PURE__ */ jsx11("div", { className: "mt-0.5 text-xs text-muted-foreground", children: plan.description })
665
+ ]
666
+ },
667
+ plan.id
668
+ ))
669
+ ] }) }),
670
+ /* @__PURE__ */ jsx11("tbody", { children: features.map((feature, i) => /* @__PURE__ */ jsxs10(
671
+ "tr",
672
+ {
673
+ className: i % 2 === 1 ? "bg-muted/50" : "",
674
+ children: [
675
+ /* @__PURE__ */ jsx11("td", { className: "border-b border-border p-3 text-sm text-foreground", children: feature.label }),
676
+ plans.map((plan) => {
677
+ const val = feature.values[plan.id];
678
+ return /* @__PURE__ */ jsx11(
679
+ "td",
680
+ {
681
+ className: cn(
682
+ "border-b border-l border-border p-3 text-center text-sm",
683
+ featuredPlan?.id === plan.id && "bg-primary/5"
684
+ ),
685
+ children: val === true ? /* @__PURE__ */ jsx11("span", { className: "text-intent-success-foreground", children: "\u2713" }) : val === false ? /* @__PURE__ */ jsx11("span", { className: "text-muted-foreground", children: "\u2014" }) : /* @__PURE__ */ jsx11("span", { className: "text-foreground", children: val })
686
+ },
687
+ plan.id
688
+ );
689
+ })
690
+ ]
691
+ },
692
+ feature.key
693
+ )) })
694
+ ] }),
695
+ /* @__PURE__ */ jsx11(ScrollHintXMark, {})
696
+ ] })
697
+ ] });
698
+ }
699
+
700
+ // src/marketing/logo-cloud.tsx
701
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
702
+ function LogoCloud({
703
+ variant = "simple",
704
+ logos,
705
+ heading,
706
+ className,
707
+ ...props
708
+ }) {
709
+ const logoElement = (logo, idx) => /* @__PURE__ */ jsx12(
710
+ "div",
711
+ {
712
+ className: "flex items-center justify-center px-4 py-2 text-muted-foreground",
713
+ children: logo.icon ? logo.icon : logo.src ? /* @__PURE__ */ jsx12(
714
+ "img",
715
+ {
716
+ src: logo.src,
717
+ alt: logo.name,
718
+ className: "h-8 max-w-[120px] object-contain opacity-60 grayscale transition-opacity hover:opacity-100"
719
+ }
720
+ ) : /* @__PURE__ */ jsx12("span", { className: "text-sm font-semibold", children: logo.name })
721
+ },
722
+ idx
723
+ );
724
+ if (variant === "scrolling") {
725
+ return /* @__PURE__ */ jsxs11(
726
+ "section",
727
+ {
728
+ className: cn("w-full overflow-hidden px-4 py-10 sm:px-6", className),
729
+ ...props,
730
+ children: [
731
+ heading && /* @__PURE__ */ jsx12("p", { className: "mb-6 text-center text-sm text-muted-foreground", children: heading }),
732
+ /* @__PURE__ */ jsxs11("div", { className: "relative flex gap-12 overflow-hidden", children: [
733
+ /* @__PURE__ */ jsx12("div", { className: "animate-scroll flex shrink-0 gap-12", children: logos.map((l, i) => logoElement(l, i)) }),
734
+ /* @__PURE__ */ jsx12("div", { className: "animate-scroll flex shrink-0 gap-12", "aria-hidden": true, children: logos.map((l, i) => logoElement(l, i + logos.length)) })
735
+ ] }),
736
+ /* @__PURE__ */ jsx12("style", { children: `
737
+ @keyframes scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
738
+ .animate-scroll { animation: scroll 20s linear infinite; }
739
+ ` })
740
+ ]
741
+ }
742
+ );
743
+ }
744
+ if (variant === "branded") {
745
+ return /* @__PURE__ */ jsxs11(
746
+ "section",
747
+ {
748
+ className: cn(
749
+ "w-full border-y border-border px-4 py-10 sm:px-6",
750
+ className
751
+ ),
752
+ ...props,
753
+ children: [
754
+ heading && /* @__PURE__ */ jsx12("p", { className: "mb-6 text-center text-sm font-medium text-foreground", children: heading }),
755
+ /* @__PURE__ */ jsx12("div", { className: "mx-auto flex max-w-4xl flex-wrap items-center justify-center gap-x-10 gap-y-6", children: logos.map((l, i) => logoElement(l, i)) })
756
+ ]
757
+ }
758
+ );
759
+ }
760
+ return /* @__PURE__ */ jsxs11("section", { className: cn("w-full px-4 py-10 sm:px-6", className), ...props, children: [
761
+ heading && /* @__PURE__ */ jsx12("p", { className: "mb-6 text-center text-sm text-muted-foreground", children: heading }),
762
+ /* @__PURE__ */ jsx12("div", { className: "mx-auto flex max-w-4xl flex-wrap items-center justify-center gap-x-10 gap-y-6", children: logos.map((l, i) => logoElement(l, i)) })
763
+ ] });
764
+ }
765
+
766
+ // src/marketing/team-section.tsx
767
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
768
+ function MemberAvatar({
769
+ member,
770
+ size
771
+ }) {
772
+ const sizeClass = size === "sm" ? "h-12 w-12" : size === "md" ? "h-16 w-16" : "h-24 w-24";
773
+ return member.avatar ? /* @__PURE__ */ jsx13(
774
+ "img",
775
+ {
776
+ src: member.avatar,
777
+ alt: member.name,
778
+ className: cn("rounded-full object-cover", sizeClass)
779
+ }
780
+ ) : /* @__PURE__ */ jsx13(
781
+ "div",
782
+ {
783
+ className: cn(
784
+ "flex items-center justify-center rounded-full bg-muted text-lg font-semibold text-muted-foreground",
785
+ sizeClass
786
+ ),
787
+ children: member.name.split(" ").map((n) => n[0]).join("").slice(0, 2)
788
+ }
789
+ );
790
+ }
791
+ function TeamSection({
792
+ variant = "grid",
793
+ members,
794
+ heading,
795
+ description,
796
+ columns = 3,
797
+ className,
798
+ ...props
799
+ }) {
800
+ const colsClass = columns === 2 ? "sm:grid-cols-2" : columns === 4 ? "sm:grid-cols-2 lg:grid-cols-4" : "sm:grid-cols-2 lg:grid-cols-3";
801
+ return /* @__PURE__ */ jsxs12(
802
+ "section",
803
+ {
804
+ className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
805
+ ...props,
806
+ children: [
807
+ (heading || description) && /* @__PURE__ */ jsxs12("div", { className: "mx-auto mb-12 max-w-2xl text-center", children: [
808
+ heading && /* @__PURE__ */ jsx13("h2", { className: "text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
809
+ description && /* @__PURE__ */ jsx13("p", { className: "mt-3 text-sm text-muted-foreground sm:text-base", children: description })
810
+ ] }),
811
+ variant === "grid" && /* @__PURE__ */ jsx13(
812
+ "div",
813
+ {
814
+ className: cn("mx-auto grid max-w-5xl grid-cols-1 gap-10", colsClass),
815
+ children: members.map((m) => /* @__PURE__ */ jsxs12("div", { className: "flex flex-col items-center text-center", children: [
816
+ /* @__PURE__ */ jsx13(MemberAvatar, { member: m, size: "lg" }),
817
+ /* @__PURE__ */ jsx13("h3", { className: "mt-4 text-sm font-semibold text-foreground", children: m.name }),
818
+ /* @__PURE__ */ jsx13("p", { className: "text-xs text-muted-foreground", children: m.role }),
819
+ m.bio && /* @__PURE__ */ jsx13("p", { className: "mt-2 line-clamp-3 text-xs text-muted-foreground", children: m.bio })
820
+ ] }, m.id))
821
+ }
822
+ ),
823
+ variant === "list" && /* @__PURE__ */ jsx13("div", { className: "mx-auto max-w-3xl divide-y divide-border", children: members.map((m) => /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-4 py-4", children: [
824
+ /* @__PURE__ */ jsx13(MemberAvatar, { member: m, size: "md" }),
825
+ /* @__PURE__ */ jsxs12("div", { className: "flex-1", children: [
826
+ /* @__PURE__ */ jsx13("h3", { className: "text-sm font-semibold text-foreground", children: m.name }),
827
+ /* @__PURE__ */ jsx13("p", { className: "text-xs text-muted-foreground", children: m.role }),
828
+ m.bio && /* @__PURE__ */ jsx13("p", { className: "mt-1 line-clamp-2 text-xs text-muted-foreground", children: m.bio })
829
+ ] }),
830
+ m.socialLinks && m.socialLinks.length > 0 && /* @__PURE__ */ jsx13("div", { className: "flex gap-2", children: m.socialLinks.map((s) => /* @__PURE__ */ jsx13(
831
+ "a",
832
+ {
833
+ href: s.href,
834
+ "aria-label": s.label,
835
+ className: "text-muted-foreground hover:text-foreground",
836
+ children: s.icon ?? s.label
837
+ },
838
+ s.label
839
+ )) })
840
+ ] }, m.id)) }),
841
+ variant === "cards" && /* @__PURE__ */ jsx13(
842
+ "div",
843
+ {
844
+ className: cn("mx-auto grid max-w-5xl grid-cols-1 gap-6", colsClass),
845
+ children: members.map((m) => /* @__PURE__ */ jsxs12(
846
+ "div",
847
+ {
848
+ className: "flex flex-col items-center rounded-xl border border-border bg-card p-6 text-center shadow-sm",
849
+ children: [
850
+ /* @__PURE__ */ jsx13(MemberAvatar, { member: m, size: "lg" }),
851
+ /* @__PURE__ */ jsx13("h3", { className: "mt-4 text-sm font-semibold text-foreground", children: m.name }),
852
+ /* @__PURE__ */ jsx13("p", { className: "text-xs text-muted-foreground", children: m.role }),
853
+ m.bio && /* @__PURE__ */ jsx13("p", { className: "mt-2 line-clamp-3 text-xs text-muted-foreground", children: m.bio }),
854
+ m.socialLinks && m.socialLinks.length > 0 && /* @__PURE__ */ jsx13("div", { className: "mt-3 flex gap-3", children: m.socialLinks.map((s) => /* @__PURE__ */ jsx13(
855
+ "a",
856
+ {
857
+ href: s.href,
858
+ "aria-label": s.label,
859
+ className: "text-muted-foreground hover:text-foreground",
860
+ children: s.icon ?? s.label
861
+ },
862
+ s.label
863
+ )) })
864
+ ]
865
+ },
866
+ m.id
867
+ ))
868
+ }
869
+ )
870
+ ]
871
+ }
872
+ );
873
+ }
874
+
875
+ // src/marketing/newsletter-section.tsx
876
+ import * as React2 from "react";
877
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
878
+ function NewsletterSection({
879
+ variant = "centered",
880
+ heading,
881
+ description,
882
+ ctaLabel,
883
+ placeholder,
884
+ onSubscribe,
885
+ className,
886
+ ...props
887
+ }) {
888
+ const [email, setEmail] = React2.useState("");
889
+ if (onSubscribe && !ctaLabel)
890
+ throw new Error(
891
+ "NewsletterSection: `onSubscribe` needs `ctaLabel`; with no label the form is not drawn"
892
+ );
893
+ const handleSubmit = (e) => {
894
+ e.preventDefault();
895
+ if (email.trim()) onSubscribe?.(email.trim());
896
+ };
897
+ const inputField = /* @__PURE__ */ jsx14(
898
+ "input",
899
+ {
900
+ type: "email",
901
+ value: email,
902
+ onChange: (e) => setEmail(e.target.value),
903
+ placeholder,
904
+ "aria-label": placeholder ?? ctaLabel,
905
+ className: "h-10 min-w-40 flex-1 rounded-md border border-border bg-card px-3 text-sm text-foreground outline-none placeholder:text-muted-foreground focus:ring-2 focus:ring-ring"
906
+ }
907
+ );
908
+ const submitBtn = /* @__PURE__ */ jsx14(Button, { type: "submit", children: ctaLabel });
909
+ if (variant === "inline") {
910
+ return /* @__PURE__ */ jsx14("section", { className: cn("w-full px-4 py-8 sm:px-6", className), ...props, children: /* @__PURE__ */ jsxs13("div", { className: "mx-auto flex max-w-xl flex-wrap items-center gap-3", children: [
911
+ heading && /* @__PURE__ */ jsx14("span", { className: "text-sm font-medium text-foreground", children: heading }),
912
+ ctaLabel && /* @__PURE__ */ jsxs13(
913
+ "form",
914
+ {
915
+ onSubmit: handleSubmit,
916
+ className: "flex min-w-0 flex-1 flex-wrap gap-3",
917
+ children: [
918
+ inputField,
919
+ submitBtn
920
+ ]
921
+ }
922
+ )
923
+ ] }) });
924
+ }
925
+ if (variant === "split") {
926
+ return /* @__PURE__ */ jsx14(
927
+ "section",
928
+ {
929
+ className: cn("w-full px-4 py-12 sm:px-6 lg:px-8", className),
930
+ ...props,
931
+ children: /* @__PURE__ */ jsxs13("div", { className: "mx-auto flex max-w-4xl flex-col items-start gap-6 sm:flex-row sm:items-center sm:justify-between", children: [
932
+ /* @__PURE__ */ jsxs13("div", { className: "max-w-md", children: [
933
+ heading && /* @__PURE__ */ jsx14("h2", { className: "text-xl font-bold text-foreground sm:text-2xl", children: heading }),
934
+ description && /* @__PURE__ */ jsx14("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
935
+ ] }),
936
+ ctaLabel && /* @__PURE__ */ jsxs13(
937
+ "form",
938
+ {
939
+ onSubmit: handleSubmit,
940
+ className: "flex w-full flex-wrap gap-3 sm:w-auto",
941
+ children: [
942
+ inputField,
943
+ submitBtn
944
+ ]
945
+ }
946
+ )
947
+ ] })
948
+ }
949
+ );
950
+ }
951
+ return /* @__PURE__ */ jsx14(
952
+ "section",
953
+ {
954
+ className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
955
+ ...props,
956
+ children: /* @__PURE__ */ jsxs13("div", { className: "mx-auto max-w-md text-center", children: [
957
+ heading && /* @__PURE__ */ jsx14("h2", { className: "text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
958
+ description && /* @__PURE__ */ jsx14("p", { className: "mt-3 text-sm text-muted-foreground", children: description }),
959
+ ctaLabel && /* @__PURE__ */ jsxs13("form", { onSubmit: handleSubmit, className: "mt-6 flex flex-wrap gap-3", children: [
960
+ inputField,
961
+ submitBtn
962
+ ] })
963
+ ] })
964
+ }
965
+ );
966
+ }
967
+
968
+ // src/marketing/contact-section.tsx
969
+ import * as React3 from "react";
970
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
971
+ function ContactForm({
972
+ submitLabel,
973
+ onSubmitForm
974
+ }) {
975
+ const id = React3.useId();
976
+ const [form, setForm] = React3.useState({
977
+ name: "",
978
+ email: "",
979
+ message: ""
980
+ });
981
+ const handleSubmit = (e) => {
982
+ e.preventDefault();
983
+ onSubmitForm?.(form);
984
+ };
985
+ const inputClass = "h-10 w-full rounded-md border border-border bg-card px-3 text-sm text-foreground outline-none placeholder:text-muted-foreground focus:ring-2 focus:ring-ring";
986
+ return /* @__PURE__ */ jsxs14("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [
987
+ /* @__PURE__ */ jsxs14("div", { children: [
988
+ /* @__PURE__ */ jsx15(
989
+ "label",
990
+ {
991
+ htmlFor: `${id}-name`,
992
+ className: "mb-1.5 block text-sm font-medium text-foreground",
993
+ children: "Name"
994
+ }
995
+ ),
996
+ /* @__PURE__ */ jsx15(
997
+ "input",
998
+ {
999
+ id: `${id}-name`,
1000
+ type: "text",
1001
+ value: form.name,
1002
+ onChange: (e) => setForm((f) => ({ ...f, name: e.target.value })),
1003
+ className: inputClass
1004
+ }
1005
+ )
1006
+ ] }),
1007
+ /* @__PURE__ */ jsxs14("div", { children: [
1008
+ /* @__PURE__ */ jsx15(
1009
+ "label",
1010
+ {
1011
+ htmlFor: `${id}-email`,
1012
+ className: "mb-1.5 block text-sm font-medium text-foreground",
1013
+ children: "Email"
1014
+ }
1015
+ ),
1016
+ /* @__PURE__ */ jsx15(
1017
+ "input",
1018
+ {
1019
+ id: `${id}-email`,
1020
+ type: "email",
1021
+ value: form.email,
1022
+ onChange: (e) => setForm((f) => ({ ...f, email: e.target.value })),
1023
+ className: inputClass
1024
+ }
1025
+ )
1026
+ ] }),
1027
+ /* @__PURE__ */ jsxs14("div", { children: [
1028
+ /* @__PURE__ */ jsx15(
1029
+ "label",
1030
+ {
1031
+ htmlFor: `${id}-message`,
1032
+ className: "mb-1.5 block text-sm font-medium text-foreground",
1033
+ children: "Message"
1034
+ }
1035
+ ),
1036
+ /* @__PURE__ */ jsx15(
1037
+ "textarea",
1038
+ {
1039
+ id: `${id}-message`,
1040
+ value: form.message,
1041
+ onChange: (e) => setForm((f) => ({ ...f, message: e.target.value })),
1042
+ rows: 4,
1043
+ className: "w-full rounded-md border border-border bg-card px-3 py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground focus:ring-2 focus:ring-ring"
1044
+ }
1045
+ )
1046
+ ] }),
1047
+ /* @__PURE__ */ jsx15(Button, { type: "submit", children: submitLabel })
1048
+ ] });
1049
+ }
1050
+ function ContactSection({
1051
+ variant = "centered",
1052
+ heading,
1053
+ description,
1054
+ submitLabel,
1055
+ onSubmitForm,
1056
+ mapSlot,
1057
+ className,
1058
+ ...props
1059
+ }) {
1060
+ if (onSubmitForm && !submitLabel)
1061
+ throw new Error(
1062
+ "ContactSection: `onSubmitForm` needs `submitLabel`; with no label the form is not drawn"
1063
+ );
1064
+ const headerBlock = (heading || description) && /* @__PURE__ */ jsxs14("div", { children: [
1065
+ heading && /* @__PURE__ */ jsx15("h2", { className: "text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
1066
+ description && /* @__PURE__ */ jsx15("p", { className: "mt-3 text-sm text-muted-foreground", children: description })
1067
+ ] });
1068
+ const formCard = submitLabel && /* @__PURE__ */ jsx15("div", { className: "rounded-xl border border-border bg-card p-6 shadow-sm", children: /* @__PURE__ */ jsx15(ContactForm, { submitLabel, onSubmitForm }) });
1069
+ if (variant === "splitForm") {
1070
+ return /* @__PURE__ */ jsx15(
1071
+ "section",
1072
+ {
1073
+ className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
1074
+ ...props,
1075
+ children: /* @__PURE__ */ jsxs14("div", { className: "mx-auto grid max-w-5xl gap-12 lg:grid-cols-2", children: [
1076
+ /* @__PURE__ */ jsx15("div", { className: "flex flex-col justify-center", children: headerBlock }),
1077
+ formCard
1078
+ ] })
1079
+ }
1080
+ );
1081
+ }
1082
+ if (variant === "withMap") {
1083
+ return /* @__PURE__ */ jsx15(
1084
+ "section",
1085
+ {
1086
+ className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
1087
+ ...props,
1088
+ children: /* @__PURE__ */ jsxs14("div", { className: "mx-auto max-w-5xl", children: [
1089
+ headerBlock,
1090
+ /* @__PURE__ */ jsxs14("div", { className: "mt-8 grid gap-8 lg:grid-cols-2", children: [
1091
+ formCard,
1092
+ mapSlot && /* @__PURE__ */ jsx15("div", { className: "overflow-hidden rounded-xl border border-border bg-muted", children: mapSlot })
1093
+ ] })
1094
+ ] })
1095
+ }
1096
+ );
1097
+ }
1098
+ return /* @__PURE__ */ jsx15(
1099
+ "section",
1100
+ {
1101
+ className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
1102
+ ...props,
1103
+ children: /* @__PURE__ */ jsxs14("div", { className: "mx-auto max-w-lg text-center", children: [
1104
+ headerBlock,
1105
+ /* @__PURE__ */ jsx15("div", { className: "mt-8 text-left", children: formCard })
1106
+ ] })
1107
+ }
1108
+ );
1109
+ }
1110
+
1111
+ // src/marketing/footer.tsx
1112
+ import * as React4 from "react";
1113
+ import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
1114
+ function MarketingFooter({
1115
+ variant = "simple",
1116
+ brandName,
1117
+ logo,
1118
+ linkGroups = [],
1119
+ links = [],
1120
+ socialLinks = [],
1121
+ legalText,
1122
+ newsletterHeading,
1123
+ newsletterDescription,
1124
+ onSubscribe,
1125
+ className,
1126
+ ...props
1127
+ }) {
1128
+ const [email, setEmail] = React4.useState("");
1129
+ const newsletterTitle = React4.useId();
1130
+ if (onSubscribe && !newsletterHeading)
1131
+ throw new Error(
1132
+ "MarketingFooter: `onSubscribe` needs `newsletterHeading`; with no heading the newsletter is not drawn"
1133
+ );
1134
+ const logoBox = logo && /* @__PURE__ */ jsx16("span", { className: "text-primary-text block size-6 shrink-0 [&>*]:size-full", children: logo });
1135
+ const socialRow = socialLinks.length > 0 && /* @__PURE__ */ jsx16("div", { className: "flex gap-4", children: socialLinks.map((s) => /* @__PURE__ */ jsx16(
1136
+ "a",
1137
+ {
1138
+ href: s.href,
1139
+ "aria-label": s.label,
1140
+ className: "text-muted-foreground transition-colors hover:text-foreground",
1141
+ children: s.icon
1142
+ },
1143
+ s.label
1144
+ )) });
1145
+ if (variant === "simple") {
1146
+ return /* @__PURE__ */ jsx16(
1147
+ "footer",
1148
+ {
1149
+ className: cn("w-full border-t border-border bg-card py-8", className),
1150
+ ...props,
1151
+ children: /* @__PURE__ */ jsxs15(Container, { className: "flex flex-col items-center gap-4 sm:flex-row sm:justify-between", children: [
1152
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
1153
+ logoBox,
1154
+ /* @__PURE__ */ jsx16("span", { className: "text-sm font-semibold text-foreground", children: brandName })
1155
+ ] }),
1156
+ links.length > 0 && /* @__PURE__ */ jsx16("nav", { className: "flex flex-wrap gap-4", children: links.map((l) => /* @__PURE__ */ jsx16(
1157
+ "a",
1158
+ {
1159
+ href: l.href,
1160
+ className: "text-sm text-muted-foreground hover:text-foreground",
1161
+ children: l.label
1162
+ },
1163
+ l.label
1164
+ )) }),
1165
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-4", children: [
1166
+ socialRow,
1167
+ legalText && /* @__PURE__ */ jsx16("span", { className: "text-xs text-muted-foreground", children: legalText })
1168
+ ] })
1169
+ ] })
1170
+ }
1171
+ );
1172
+ }
1173
+ if (variant === "withNewsletter") {
1174
+ return /* @__PURE__ */ jsx16(
1175
+ "footer",
1176
+ {
1177
+ className: cn("w-full border-t border-border bg-card py-12", className),
1178
+ ...props,
1179
+ children: /* @__PURE__ */ jsxs15(Container, { children: [
1180
+ /* @__PURE__ */ jsxs15("div", { className: "grid gap-8 lg:grid-cols-[1fr_320px]", children: [
1181
+ /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-2 gap-8 sm:grid-cols-3", children: linkGroups.map((group) => /* @__PURE__ */ jsxs15("div", { children: [
1182
+ /* @__PURE__ */ jsx16("h3", { className: "mb-3 text-sm font-semibold text-foreground", children: group.title }),
1183
+ /* @__PURE__ */ jsx16("ul", { className: "space-y-2", children: group.links.map((l) => /* @__PURE__ */ jsx16("li", { children: /* @__PURE__ */ jsx16(
1184
+ "a",
1185
+ {
1186
+ href: l.href,
1187
+ className: "text-sm text-muted-foreground hover:text-foreground",
1188
+ children: l.label
1189
+ }
1190
+ ) }, l.label)) })
1191
+ ] }, group.title)) }),
1192
+ newsletterHeading && /* @__PURE__ */ jsxs15("div", { children: [
1193
+ /* @__PURE__ */ jsx16(
1194
+ "h3",
1195
+ {
1196
+ id: newsletterTitle,
1197
+ className: "mb-2 text-sm font-semibold text-foreground",
1198
+ children: newsletterHeading
1199
+ }
1200
+ ),
1201
+ newsletterDescription && /* @__PURE__ */ jsx16("p", { className: "mb-3 text-xs text-muted-foreground", children: newsletterDescription }),
1202
+ /* @__PURE__ */ jsxs15(
1203
+ "form",
1204
+ {
1205
+ onSubmit: (e) => {
1206
+ e.preventDefault();
1207
+ if (email.trim()) onSubscribe?.(email.trim());
1208
+ },
1209
+ className: "flex gap-2",
1210
+ children: [
1211
+ /* @__PURE__ */ jsx16(
1212
+ "input",
1213
+ {
1214
+ type: "email",
1215
+ value: email,
1216
+ onChange: (e) => setEmail(e.target.value),
1217
+ "aria-labelledby": newsletterTitle,
1218
+ className: "h-9 min-w-0 flex-1 rounded-md border border-border bg-card px-3 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring"
1219
+ }
1220
+ ),
1221
+ /* @__PURE__ */ jsx16(
1222
+ "button",
1223
+ {
1224
+ type: "submit",
1225
+ className: "bg-primary-solid h-9 rounded-md px-4 text-sm font-medium text-primary-foreground hover:opacity-90",
1226
+ children: "Subscribe"
1227
+ }
1228
+ )
1229
+ ]
1230
+ }
1231
+ )
1232
+ ] })
1233
+ ] }),
1234
+ /* @__PURE__ */ jsxs15("div", { className: "mt-8 flex flex-col items-center justify-between gap-4 border-t border-border pt-6 sm:flex-row", children: [
1235
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
1236
+ logoBox,
1237
+ legalText && /* @__PURE__ */ jsx16("span", { className: "text-sm text-muted-foreground", children: legalText })
1238
+ ] }),
1239
+ socialRow
1240
+ ] })
1241
+ ] })
1242
+ }
1243
+ );
1244
+ }
1245
+ return /* @__PURE__ */ jsx16(
1246
+ "footer",
1247
+ {
1248
+ className: cn("w-full border-t border-border bg-card py-12", className),
1249
+ ...props,
1250
+ children: /* @__PURE__ */ jsxs15(Container, { children: [
1251
+ /* @__PURE__ */ jsxs15("div", { className: "grid gap-8 sm:grid-cols-2 lg:grid-cols-4", children: [
1252
+ /* @__PURE__ */ jsxs15("div", { children: [
1253
+ /* @__PURE__ */ jsxs15("div", { className: "mb-4 flex items-center gap-2", children: [
1254
+ logoBox,
1255
+ /* @__PURE__ */ jsx16("span", { className: "text-sm font-semibold text-foreground", children: brandName })
1256
+ ] }),
1257
+ socialRow
1258
+ ] }),
1259
+ linkGroups.map((group) => /* @__PURE__ */ jsxs15("div", { children: [
1260
+ /* @__PURE__ */ jsx16("h3", { className: "mb-3 text-sm font-semibold text-foreground", children: group.title }),
1261
+ /* @__PURE__ */ jsx16("ul", { className: "space-y-2", children: group.links.map((l) => /* @__PURE__ */ jsx16("li", { children: /* @__PURE__ */ jsx16(
1262
+ "a",
1263
+ {
1264
+ href: l.href,
1265
+ className: "text-sm text-muted-foreground hover:text-foreground",
1266
+ children: l.label
1267
+ }
1268
+ ) }, l.label)) })
1269
+ ] }, group.title))
1270
+ ] }),
1271
+ legalText && /* @__PURE__ */ jsx16("div", { className: "mt-8 border-t border-border pt-6 text-center text-xs text-muted-foreground", children: legalText })
1272
+ ] })
1273
+ }
1274
+ );
1275
+ }
1276
+
1277
+ // src/marketing/testimonial-section.tsx
1278
+ import * as React5 from "react";
1279
+ import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
1280
+ function TestimonialCard({
1281
+ testimonial,
1282
+ className
1283
+ }) {
1284
+ return /* @__PURE__ */ jsxs16(
1285
+ "div",
1286
+ {
1287
+ className: cn(
1288
+ "flex flex-col gap-4 rounded-xl border border-border bg-card p-6 shadow-sm",
1289
+ className
1290
+ ),
1291
+ children: [
1292
+ /* @__PURE__ */ jsxs16("p", { className: "flex-1 text-sm italic text-foreground", children: [
1293
+ "\u201C",
1294
+ testimonial.quote,
1295
+ "\u201D"
1296
+ ] }),
1297
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-3", children: [
1298
+ testimonial.avatar ? /* @__PURE__ */ jsx17(
1299
+ "img",
1300
+ {
1301
+ src: testimonial.avatar,
1302
+ alt: testimonial.name,
1303
+ className: "h-10 w-10 rounded-full object-cover"
1304
+ }
1305
+ ) : /* @__PURE__ */ jsx17("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-muted text-sm font-medium text-muted-foreground", children: testimonial.name.charAt(0) }),
1306
+ /* @__PURE__ */ jsxs16("div", { children: [
1307
+ /* @__PURE__ */ jsx17("p", { className: "text-sm font-semibold text-foreground", children: testimonial.name }),
1308
+ (testimonial.role || testimonial.company) && /* @__PURE__ */ jsx17("p", { className: "text-xs text-muted-foreground", children: [testimonial.role, testimonial.company].filter(Boolean).join(" \xB7 ") })
1309
+ ] })
1310
+ ] })
1311
+ ]
1312
+ }
1313
+ );
1314
+ }
1315
+ function GridLayout({
1316
+ testimonials,
1317
+ columns = 3
1318
+ }) {
1319
+ const gridCols = columns === 2 ? "sm:grid-cols-2" : "sm:grid-cols-2 lg:grid-cols-3";
1320
+ return /* @__PURE__ */ jsx17("div", { className: cn("grid grid-cols-1 gap-6", gridCols), children: testimonials.map((t) => /* @__PURE__ */ jsx17(TestimonialCard, { testimonial: t }, t.id)) });
1321
+ }
1322
+ function CarouselLayout({
1323
+ testimonials,
1324
+ autoPlayInterval = 5e3
1325
+ }) {
1326
+ const [activeIndex, setActiveIndex] = React5.useState(0);
1327
+ React5.useEffect(() => {
1328
+ if (autoPlayInterval <= 0 || testimonials.length <= 1) return;
1329
+ const timer = setInterval(() => {
1330
+ setActiveIndex((i) => (i + 1) % testimonials.length);
1331
+ }, autoPlayInterval);
1332
+ return () => clearInterval(timer);
1333
+ }, [autoPlayInterval, testimonials.length]);
1334
+ const current = testimonials[activeIndex];
1335
+ if (!current) return null;
1336
+ return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center gap-6", children: [
1337
+ /* @__PURE__ */ jsx17("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsx17(TestimonialCard, { testimonial: current, className: "text-center" }) }),
1338
+ testimonials.length > 1 && /* @__PURE__ */ jsx17("div", { className: "flex gap-2", children: testimonials.map((t, i) => /* @__PURE__ */ jsx17(
1339
+ "button",
1340
+ {
1341
+ type: "button",
1342
+ onClick: () => setActiveIndex(i),
1343
+ "aria-label": t.name,
1344
+ className: cn(
1345
+ "h-2 rounded-full transition-all",
1346
+ i === activeIndex ? "w-6 bg-primary" : "w-2 bg-muted-foreground/30"
1347
+ )
1348
+ },
1349
+ i
1350
+ )) })
1351
+ ] });
1352
+ }
1353
+ function SingleQuoteLayout({ testimonial }) {
1354
+ return /* @__PURE__ */ jsxs16("div", { className: "mx-auto flex max-w-3xl flex-col items-center gap-6 text-center", children: [
1355
+ testimonial.logo && /* @__PURE__ */ jsx17(
1356
+ "img",
1357
+ {
1358
+ src: testimonial.logo,
1359
+ alt: testimonial.company ?? "",
1360
+ className: "h-8 opacity-60"
1361
+ }
1362
+ ),
1363
+ /* @__PURE__ */ jsxs16("blockquote", { className: "text-xl font-medium italic text-foreground sm:text-2xl", children: [
1364
+ "\u201C",
1365
+ testimonial.quote,
1366
+ "\u201D"
1367
+ ] }),
1368
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-3", children: [
1369
+ testimonial.avatar ? /* @__PURE__ */ jsx17(
1370
+ "img",
1371
+ {
1372
+ src: testimonial.avatar,
1373
+ alt: testimonial.name,
1374
+ className: "h-12 w-12 rounded-full object-cover"
1375
+ }
1376
+ ) : /* @__PURE__ */ jsx17("div", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-muted text-sm font-medium text-muted-foreground", children: testimonial.name.charAt(0) }),
1377
+ /* @__PURE__ */ jsxs16("div", { className: "text-left", children: [
1378
+ /* @__PURE__ */ jsx17("p", { className: "text-sm font-semibold text-foreground", children: testimonial.name }),
1379
+ (testimonial.role || testimonial.company) && /* @__PURE__ */ jsx17("p", { className: "text-xs text-muted-foreground", children: [testimonial.role, testimonial.company].filter(Boolean).join(" \xB7 ") })
1380
+ ] })
1381
+ ] })
1382
+ ] });
1383
+ }
1384
+ function WallOfLoveLayout({ testimonials }) {
1385
+ return /* @__PURE__ */ jsx17("div", { className: "columns-1 gap-6 sm:columns-2 lg:columns-3", children: testimonials.map((t) => /* @__PURE__ */ jsx17("div", { className: "mb-6 break-inside-avoid", children: /* @__PURE__ */ jsx17(TestimonialCard, { testimonial: t }) }, t.id)) });
1386
+ }
1387
+ function TestimonialSection({
1388
+ variant = "grid",
1389
+ testimonials,
1390
+ heading,
1391
+ subheading,
1392
+ columns = 3,
1393
+ autoPlayInterval = 5e3,
1394
+ className,
1395
+ ...props
1396
+ }) {
1397
+ return /* @__PURE__ */ jsxs16(
1398
+ "section",
1399
+ {
1400
+ className: cn("w-full px-4 py-12 sm:px-6 lg:px-8", className),
1401
+ ...props,
1402
+ children: [
1403
+ (heading || subheading) && /* @__PURE__ */ jsxs16("div", { className: "mx-auto mb-10 max-w-2xl text-center", children: [
1404
+ heading && /* @__PURE__ */ jsx17("h2", { className: "text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
1405
+ subheading && /* @__PURE__ */ jsx17("p", { className: "mt-3 text-sm text-muted-foreground sm:text-base", children: subheading })
1406
+ ] }),
1407
+ variant === "grid" && /* @__PURE__ */ jsx17(GridLayout, { testimonials, columns }),
1408
+ variant === "carousel" && /* @__PURE__ */ jsx17(
1409
+ CarouselLayout,
1410
+ {
1411
+ testimonials,
1412
+ autoPlayInterval
1413
+ }
1414
+ ),
1415
+ variant === "singleQuote" && testimonials[0] && /* @__PURE__ */ jsx17(SingleQuoteLayout, { testimonial: testimonials[0] }),
1416
+ variant === "wallOfLove" && /* @__PURE__ */ jsx17(WallOfLoveLayout, { testimonials })
1417
+ ]
1418
+ }
1419
+ );
1420
+ }
1421
+ export {
1422
+ BlogGrid,
1423
+ CTABanner,
1424
+ ComparisonTable,
1425
+ ContactSection,
1426
+ FeatureCard,
1427
+ LogoCloud,
1428
+ MarketingCta,
1429
+ MarketingFAQItem,
1430
+ MarketingFooter,
1431
+ MarketingHeader,
1432
+ MarketingHero,
1433
+ HowItWorksStep as MarketingHowItWorksStep,
1434
+ PricingTier as MarketingPricingTier,
1435
+ NewsletterSection,
1436
+ TeamSection,
1437
+ TestimonialSection,
1438
+ UseCaseCard
1439
+ };