@saasflare/ui 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3,15 +3,15 @@ import { Calendar } from './chunk-XNDTCYSO.mjs';
3
3
  import { buttonVariants, Button } from './chunk-2ONA6OMO.mjs';
4
4
  export { Button, buttonVariants } from './chunk-2ONA6OMO.mjs';
5
5
  export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './chunk-5C65JNGY.mjs';
6
- import { useSaasflareMotion, springGentle, springBouncy, spring } from './chunk-OZAWULTM.mjs';
6
+ import { useSaasflareMotion, springGentle, springBouncy, spring, noMotion } from './chunk-OZAWULTM.mjs';
7
7
  export { fadeIn, noMotion, scaleIn, slideDown, slideUp, spring, springBouncy, springGentle, springStiff, useSaasflareMotion } from './chunk-OZAWULTM.mjs';
8
- import { CaretDownIcon, CheckIcon, CaretUpIcon, CircleIcon, CaretRightIcon, XIcon, CircleNotchIcon, XCircleIcon, WarningIcon, InfoIcon, CheckCircleIcon, DotsThreeIcon, MagnifyingGlassIcon, CaretLeftIcon, SidebarSimpleIcon, ArrowUpIcon, TiktokLogoIcon, DribbbleLogoIcon, GitlabLogoIcon, StripeLogoIcon, PaypalLogoIcon, RedditLogoIcon, SlackLogoIcon, MediumLogoIcon, LinkedinLogoIcon, FacebookLogoIcon, DiscordLogoIcon, XLogoIcon, MicrosoftOutlookLogoIcon, AppleLogoIcon, GithubLogoIcon, GoogleLogoIcon, SunIcon, MoonIcon, MonitorIcon } from './chunk-GI6VN7XU.mjs';
8
+ import { CaretDownIcon, CheckIcon, CaretUpIcon, CircleIcon, CaretRightIcon, XIcon, CircleNotchIcon, XCircleIcon, WarningIcon, InfoIcon, CheckCircleIcon, DotsThreeIcon, MagnifyingGlassIcon, CaretLeftIcon, SidebarSimpleIcon, PauseIcon, PlayIcon, ArrowUpIcon, TiktokLogoIcon, DribbbleLogoIcon, GitlabLogoIcon, StripeLogoIcon, PaypalLogoIcon, RedditLogoIcon, SlackLogoIcon, MediumLogoIcon, LinkedinLogoIcon, FacebookLogoIcon, DiscordLogoIcon, XLogoIcon, MicrosoftOutlookLogoIcon, AppleLogoIcon, GithubLogoIcon, GoogleLogoIcon, SunIcon, MoonIcon, MonitorIcon } from './chunk-GI6VN7XU.mjs';
9
9
  export { ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, CaretDownIcon, CaretLeftIcon, CaretRightIcon, CaretUpIcon, CheckCircleIcon, CheckIcon, CircleIcon, CircleNotchIcon, DotsSixVerticalIcon, DotsThreeIcon, IconBase, InfoIcon, MagnifyingGlassIcon, MinusIcon, MonitorIcon, MoonIcon, PauseIcon, PlayIcon, QuotesIcon, SidebarSimpleIcon, SunIcon, WarningIcon, XCircleIcon, XIcon } from './chunk-GI6VN7XU.mjs';
10
- import { useSaasflareProps, cn } from './chunk-RMQBB72G.mjs';
10
+ import { useSaasflareProps, cn, useReducedMotion } from './chunk-RMQBB72G.mjs';
11
11
  export { SaasflareProvider, SaasflareScript, SaasflareShell, SmoothScrollProvider, cn, useAnimation, useLocalStorage, useReducedMotion, useSaasflareProps, useSaasflareTheme } from './chunk-RMQBB72G.mjs';
12
12
  import * as React5 from 'react';
13
- import React5__default, { useState, useCallback, useMemo, useRef, useEffect, Suspense } from 'react';
14
- import { m, useMotionValue, useSpring, useTransform, AnimatePresence } from 'motion/react';
13
+ import React5__default, { createContext, useState, useCallback, useMemo, useRef, useEffect, Children, Suspense, useContext } from 'react';
14
+ import { m, useMotionValue, useSpring, useTransform, AnimatePresence, useInView, useScroll } from 'motion/react';
15
15
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
16
16
  import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
17
17
  import * as AccordionPrimitive from '@radix-ui/react-accordion';
@@ -294,6 +294,30 @@ function useFocusTrap(active) {
294
294
  }, [active]);
295
295
  return setRef;
296
296
  }
297
+ function useCountdown(target) {
298
+ const targetMs = new Date(target).getTime();
299
+ const calculate = () => {
300
+ const diff = Math.max(0, targetMs - Date.now());
301
+ return {
302
+ days: Math.floor(diff / (1e3 * 60 * 60 * 24)),
303
+ hours: Math.floor(diff / (1e3 * 60 * 60) % 24),
304
+ minutes: Math.floor(diff / (1e3 * 60) % 60),
305
+ seconds: Math.floor(diff / 1e3 % 60),
306
+ totalMs: diff,
307
+ isExpired: diff <= 0
308
+ };
309
+ };
310
+ const [value, setValue] = useState(calculate);
311
+ useEffect(() => {
312
+ const timer = setInterval(() => {
313
+ const next = calculate();
314
+ setValue(next);
315
+ if (next.isExpired) clearInterval(timer);
316
+ }, 1e3);
317
+ return () => clearInterval(timer);
318
+ }, [targetMs]);
319
+ return value;
320
+ }
297
321
  function useFileDialog(options = {}) {
298
322
  const { accept, multiple = false, directory = false, capture, onChange } = options;
299
323
  const [files, setFiles] = useState([]);
@@ -3250,10 +3274,10 @@ var Observer = class {
3250
3274
  });
3251
3275
  }
3252
3276
  };
3253
- this.custom = (jsx84, data) => {
3277
+ this.custom = (jsx120, data) => {
3254
3278
  const id = (data == null ? void 0 : data.id) || toastsCounter++;
3255
3279
  this.create({
3256
- jsx: jsx84(id),
3280
+ jsx: jsx120(id),
3257
3281
  id,
3258
3282
  ...data
3259
3283
  });
@@ -8330,6 +8354,2113 @@ function AuroraBackground({
8330
8354
  }
8331
8355
  );
8332
8356
  }
8357
+ function formatTime(s) {
8358
+ if (!isFinite(s) || s < 0) return "0:00";
8359
+ const m37 = Math.floor(s / 60);
8360
+ const sec = Math.floor(s % 60);
8361
+ return `${m37}:${String(sec).padStart(2, "0")}`;
8362
+ }
8363
+ function AudioPlayer({
8364
+ src,
8365
+ title,
8366
+ className,
8367
+ surface,
8368
+ radius,
8369
+ animated
8370
+ }) {
8371
+ const sf = useSaasflareProps({ surface, radius, animated });
8372
+ const audioRef = useRef(null);
8373
+ const [playing, setPlaying] = useState(false);
8374
+ const [current, setCurrent] = useState(0);
8375
+ const [duration, setDuration] = useState(0);
8376
+ const toggle = useCallback(() => {
8377
+ const audio = audioRef.current;
8378
+ if (!audio) return;
8379
+ if (playing) {
8380
+ audio.pause();
8381
+ } else {
8382
+ audio.play();
8383
+ }
8384
+ setPlaying(!playing);
8385
+ }, [playing]);
8386
+ useEffect(() => {
8387
+ const audio = audioRef.current;
8388
+ if (!audio) return;
8389
+ const onTime = () => setCurrent(audio.currentTime);
8390
+ const onMeta = () => setDuration(audio.duration);
8391
+ const onEnded = () => setPlaying(false);
8392
+ audio.addEventListener("timeupdate", onTime);
8393
+ audio.addEventListener("loadedmetadata", onMeta);
8394
+ audio.addEventListener("ended", onEnded);
8395
+ return () => {
8396
+ audio.removeEventListener("timeupdate", onTime);
8397
+ audio.removeEventListener("loadedmetadata", onMeta);
8398
+ audio.removeEventListener("ended", onEnded);
8399
+ };
8400
+ }, []);
8401
+ const seek = useCallback((e) => {
8402
+ const audio = audioRef.current;
8403
+ if (!audio) return;
8404
+ audio.currentTime = Number(e.target.value);
8405
+ }, []);
8406
+ const progress = duration > 0 ? current / duration * 100 : 0;
8407
+ return /* @__PURE__ */ jsxs(
8408
+ "div",
8409
+ {
8410
+ "data-slot": "audio-player",
8411
+ "data-surface": sf.surface,
8412
+ "data-radius": sf.radius,
8413
+ className: cn(
8414
+ "flex items-center gap-3 rounded-xl border surface-card px-4 py-3",
8415
+ "transition-all duration-200 hover:shadow-md",
8416
+ className
8417
+ ),
8418
+ children: [
8419
+ /* @__PURE__ */ jsx("audio", { ref: audioRef, src, preload: "metadata" }),
8420
+ /* @__PURE__ */ jsx(
8421
+ "button",
8422
+ {
8423
+ type: "button",
8424
+ onClick: toggle,
8425
+ className: "flex size-9 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground transition-colors hover:bg-primary/90",
8426
+ "aria-label": playing ? "Pause" : "Play",
8427
+ children: playing ? /* @__PURE__ */ jsx(PauseIcon, { weight: sf.iconWeight, className: "size-4" }) : /* @__PURE__ */ jsx(PlayIcon, { weight: sf.iconWeight, className: "ml-0.5 size-4" })
8428
+ }
8429
+ ),
8430
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-1", children: [
8431
+ title && /* @__PURE__ */ jsx("span", { className: "text-xs font-medium truncate", children: title }),
8432
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
8433
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] tabular-nums text-muted-foreground", children: formatTime(current) }),
8434
+ /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
8435
+ /* @__PURE__ */ jsx("div", { className: "h-1 rounded-full bg-muted", children: /* @__PURE__ */ jsx(
8436
+ "div",
8437
+ {
8438
+ className: "h-1 rounded-full bg-primary transition-[width]",
8439
+ style: { width: `${progress}%` }
8440
+ }
8441
+ ) }),
8442
+ /* @__PURE__ */ jsx(
8443
+ "input",
8444
+ {
8445
+ type: "range",
8446
+ min: 0,
8447
+ max: duration || 0,
8448
+ value: current,
8449
+ onChange: seek,
8450
+ className: "absolute inset-0 h-1 w-full cursor-pointer opacity-0",
8451
+ "aria-label": "Seek"
8452
+ }
8453
+ )
8454
+ ] }),
8455
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] tabular-nums text-muted-foreground", children: formatTime(duration) })
8456
+ ] })
8457
+ ] })
8458
+ ]
8459
+ }
8460
+ );
8461
+ }
8462
+ var COL_MAP = {
8463
+ 2: "md:grid-cols-2",
8464
+ 3: "md:grid-cols-3",
8465
+ 4: "md:grid-cols-4"
8466
+ };
8467
+ function BentoGrid({
8468
+ children,
8469
+ columns = 3,
8470
+ gap = 4,
8471
+ className
8472
+ }) {
8473
+ return /* @__PURE__ */ jsx(
8474
+ "div",
8475
+ {
8476
+ className: cn(
8477
+ "grid grid-cols-1",
8478
+ COL_MAP[columns],
8479
+ className
8480
+ ),
8481
+ style: { gap: `${gap * 0.25}rem` },
8482
+ "data-slot": "bento-grid",
8483
+ children
8484
+ }
8485
+ );
8486
+ }
8487
+ var COL_SPAN_MAP = {
8488
+ 1: "",
8489
+ 2: "md:col-span-2",
8490
+ 3: "md:col-span-3",
8491
+ 4: "md:col-span-4"
8492
+ };
8493
+ var ROW_SPAN_MAP = {
8494
+ 1: "",
8495
+ 2: "md:row-span-2",
8496
+ 3: "md:row-span-3"
8497
+ };
8498
+ function BentoGridItem({
8499
+ children,
8500
+ colSpan = 1,
8501
+ rowSpan = 1,
8502
+ index = 0,
8503
+ className,
8504
+ surface,
8505
+ radius,
8506
+ animated
8507
+ }) {
8508
+ const sf = useSaasflareProps({ surface, radius, animated });
8509
+ const reduced = useReducedMotion();
8510
+ return /* @__PURE__ */ jsx(
8511
+ m.div,
8512
+ {
8513
+ initial: reduced ? false : { opacity: 0, y: 16 },
8514
+ whileInView: reduced ? void 0 : { opacity: 1, y: 0 },
8515
+ viewport: { once: true, margin: "-60px" },
8516
+ transition: reduced ? noMotion : { ...springGentle, delay: index * 0.08 },
8517
+ "data-slot": "bento-grid-item",
8518
+ "data-surface": sf.surface,
8519
+ "data-radius": sf.radius,
8520
+ className: cn(
8521
+ "rounded-xl border surface-card p-6 text-card-foreground",
8522
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
8523
+ "motion-reduce:hover:transform-none",
8524
+ COL_SPAN_MAP[colSpan],
8525
+ ROW_SPAN_MAP[rowSpan],
8526
+ className
8527
+ ),
8528
+ children
8529
+ }
8530
+ );
8531
+ }
8532
+ function BlurFade({
8533
+ children,
8534
+ delay = 0,
8535
+ blur = 8,
8536
+ yOffset = 12,
8537
+ duration = 0.5,
8538
+ once = true,
8539
+ className
8540
+ }) {
8541
+ const reduced = useReducedMotion();
8542
+ const ref = useRef(null);
8543
+ const isInView = useInView(ref, { once, margin: "-50px" });
8544
+ if (reduced) {
8545
+ return /* @__PURE__ */ jsx("div", { className, children });
8546
+ }
8547
+ return /* @__PURE__ */ jsx(
8548
+ m.div,
8549
+ {
8550
+ ref,
8551
+ initial: { opacity: 0, y: yOffset, filter: `blur(${blur}px)` },
8552
+ animate: isInView ? { opacity: 1, y: 0, filter: "blur(0px)" } : { opacity: 0, y: yOffset, filter: `blur(${blur}px)` },
8553
+ transition: { duration, delay, ease: "easeOut" },
8554
+ className: cn("will-change-[opacity,transform,filter]", className),
8555
+ "data-slot": "blur-fade",
8556
+ children
8557
+ }
8558
+ );
8559
+ }
8560
+ function BorderBeam({
8561
+ color = "hsl(var(--primary))",
8562
+ colorFrom = "transparent",
8563
+ duration = 6,
8564
+ size = 150,
8565
+ borderRadius = "inherit",
8566
+ className
8567
+ }) {
8568
+ const reduced = useReducedMotion();
8569
+ if (reduced) return null;
8570
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
8571
+ /* @__PURE__ */ jsx("style", { children: `
8572
+ @keyframes sf-border-beam {
8573
+ 0% { offset-distance: 0%; }
8574
+ 100% { offset-distance: 100%; }
8575
+ }
8576
+ ` }),
8577
+ /* @__PURE__ */ jsx(
8578
+ "div",
8579
+ {
8580
+ className: cn("pointer-events-none absolute inset-0", className),
8581
+ style: { borderRadius },
8582
+ "aria-hidden": "true",
8583
+ "data-slot": "border-beam",
8584
+ children: /* @__PURE__ */ jsx(
8585
+ "div",
8586
+ {
8587
+ style: {
8588
+ position: "absolute",
8589
+ inset: 0,
8590
+ borderRadius,
8591
+ /* The beam travels along the rect path */
8592
+ offsetPath: `rect(0 auto auto 0 round ${borderRadius})`,
8593
+ animation: `sf-border-beam ${duration}s linear infinite`,
8594
+ background: `linear-gradient(to left, ${color}, ${colorFrom})`,
8595
+ width: size,
8596
+ height: size,
8597
+ opacity: 0.7,
8598
+ filter: "blur(4px)"
8599
+ }
8600
+ }
8601
+ )
8602
+ }
8603
+ )
8604
+ ] });
8605
+ }
8606
+ function Compare({
8607
+ before,
8608
+ after,
8609
+ beforeLabel,
8610
+ afterLabel,
8611
+ initialPosition = 50,
8612
+ aspectRatio = "16/9",
8613
+ className
8614
+ }) {
8615
+ const [position, setPosition] = useState(initialPosition);
8616
+ const containerRef = useRef(null);
8617
+ const dragging = useRef(false);
8618
+ const updatePosition = useCallback((clientX) => {
8619
+ if (!containerRef.current) return;
8620
+ const rect = containerRef.current.getBoundingClientRect();
8621
+ const x = Math.max(0, Math.min(clientX - rect.left, rect.width));
8622
+ setPosition(x / rect.width * 100);
8623
+ }, []);
8624
+ const onPointerDown = useCallback(
8625
+ (e) => {
8626
+ dragging.current = true;
8627
+ e.target.setPointerCapture(e.pointerId);
8628
+ updatePosition(e.clientX);
8629
+ },
8630
+ [updatePosition]
8631
+ );
8632
+ const onPointerMove = useCallback(
8633
+ (e) => {
8634
+ if (!dragging.current) return;
8635
+ updatePosition(e.clientX);
8636
+ },
8637
+ [updatePosition]
8638
+ );
8639
+ const onPointerUp = useCallback(() => {
8640
+ dragging.current = false;
8641
+ }, []);
8642
+ const onKeyDown = useCallback((e) => {
8643
+ if (e.key === "ArrowLeft") setPosition((p) => Math.max(0, p - 2));
8644
+ else if (e.key === "ArrowRight") setPosition((p) => Math.min(100, p + 2));
8645
+ }, []);
8646
+ return /* @__PURE__ */ jsxs(
8647
+ "div",
8648
+ {
8649
+ ref: containerRef,
8650
+ className: cn(
8651
+ "relative select-none overflow-hidden rounded-xl border shadow-sm",
8652
+ className
8653
+ ),
8654
+ style: { aspectRatio },
8655
+ onPointerDown,
8656
+ onPointerMove,
8657
+ onPointerUp,
8658
+ "data-slot": "compare",
8659
+ children: [
8660
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0", children: after }),
8661
+ /* @__PURE__ */ jsx(
8662
+ "div",
8663
+ {
8664
+ className: "absolute inset-0 overflow-hidden",
8665
+ style: { width: `${position}%` },
8666
+ children: /* @__PURE__ */ jsx(
8667
+ "div",
8668
+ {
8669
+ className: "h-full",
8670
+ style: { width: containerRef.current?.offsetWidth ?? "100%" },
8671
+ children: before
8672
+ }
8673
+ )
8674
+ }
8675
+ ),
8676
+ /* @__PURE__ */ jsx(
8677
+ "div",
8678
+ {
8679
+ className: "absolute inset-y-0 z-10 flex w-1 cursor-col-resize items-center bg-white shadow-lg",
8680
+ style: { left: `${position}%`, transform: "translateX(-50%)" },
8681
+ role: "slider",
8682
+ "aria-label": "Comparison slider",
8683
+ "aria-valuenow": Math.round(position),
8684
+ "aria-valuemin": 0,
8685
+ "aria-valuemax": 100,
8686
+ tabIndex: 0,
8687
+ onKeyDown,
8688
+ children: /* @__PURE__ */ jsx("div", { className: "flex size-8 items-center justify-center rounded-full bg-white shadow-md", children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M4 1L1 7L4 13M10 1L13 7L10 13", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) })
8689
+ }
8690
+ ),
8691
+ beforeLabel && /* @__PURE__ */ jsx("span", { className: "absolute left-3 top-3 rounded-md bg-black/50 px-2 py-1 text-xs font-medium text-white backdrop-blur-sm", children: beforeLabel }),
8692
+ afterLabel && /* @__PURE__ */ jsx("span", { className: "absolute right-3 top-3 rounded-md bg-black/50 px-2 py-1 text-xs font-medium text-white backdrop-blur-sm", children: afterLabel })
8693
+ ]
8694
+ }
8695
+ );
8696
+ }
8697
+ function seeded(seed) {
8698
+ const x = Math.sin(seed * 9301 + 49297) * 233280;
8699
+ return x - Math.floor(x);
8700
+ }
8701
+ function Confetti({
8702
+ active,
8703
+ count = 40,
8704
+ colors = [
8705
+ "hsl(var(--primary))",
8706
+ "hsl(var(--chart-1))",
8707
+ "hsl(var(--chart-2))",
8708
+ "hsl(var(--chart-3))",
8709
+ "hsl(var(--chart-4))"
8710
+ ],
8711
+ duration = 3e3,
8712
+ onComplete,
8713
+ className
8714
+ }) {
8715
+ const reduced = useReducedMotion();
8716
+ const [visible, setVisible] = useState(false);
8717
+ useEffect(() => {
8718
+ if (!active || reduced) return;
8719
+ setVisible(true);
8720
+ const timer = setTimeout(() => {
8721
+ setVisible(false);
8722
+ onComplete?.();
8723
+ }, duration);
8724
+ return () => clearTimeout(timer);
8725
+ }, [active, reduced, duration, onComplete]);
8726
+ const particles = useMemo(
8727
+ () => Array.from({ length: count }, (_, i) => {
8728
+ const r = (s) => seeded(i * 100 + s);
8729
+ return {
8730
+ id: i,
8731
+ color: colors[i % colors.length],
8732
+ x: 50 + (r(1) - 0.5) * 60,
8733
+ endX: (r(2) - 0.5) * 200,
8734
+ endY: -(100 + r(3) * 300),
8735
+ size: 4 + r(4) * 6,
8736
+ rotation: r(5) * 720,
8737
+ delay: r(6) * 0.3,
8738
+ animDuration: 1.5 + r(7) * 1.5
8739
+ };
8740
+ }),
8741
+ [count, colors]
8742
+ );
8743
+ if (!visible || reduced) return null;
8744
+ return /* @__PURE__ */ jsxs(
8745
+ "div",
8746
+ {
8747
+ className: cn("pointer-events-none fixed inset-0 z-[9999] overflow-hidden", className),
8748
+ "aria-hidden": "true",
8749
+ "data-slot": "confetti",
8750
+ children: [
8751
+ /* @__PURE__ */ jsx("style", { children: `
8752
+ @keyframes sf-confetti-burst {
8753
+ 0% {
8754
+ transform: translate(0, 0) rotate(0deg);
8755
+ opacity: 1;
8756
+ }
8757
+ 100% {
8758
+ transform: translate(var(--cx), var(--cy)) rotate(var(--cr));
8759
+ opacity: 0;
8760
+ }
8761
+ }
8762
+ ` }),
8763
+ particles.map((p) => /* @__PURE__ */ jsx(
8764
+ "div",
8765
+ {
8766
+ style: {
8767
+ position: "absolute",
8768
+ left: `${p.x}%`,
8769
+ bottom: 0,
8770
+ width: p.size,
8771
+ height: p.size * 0.6,
8772
+ backgroundColor: p.color,
8773
+ borderRadius: p.id % 3 === 0 ? "50%" : "1px",
8774
+ ["--cx"]: `${p.endX}px`,
8775
+ ["--cy"]: `${p.endY}px`,
8776
+ ["--cr"]: `${p.rotation}deg`,
8777
+ animation: `sf-confetti-burst ${p.animDuration}s cubic-bezier(0.25, 0.46, 0.45, 0.94) ${p.delay}s forwards`
8778
+ }
8779
+ },
8780
+ p.id
8781
+ ))
8782
+ ]
8783
+ }
8784
+ );
8785
+ }
8786
+ function pad(n) {
8787
+ return String(Math.max(0, Math.floor(n))).padStart(2, "0");
8788
+ }
8789
+ function Countdown({
8790
+ days,
8791
+ hours,
8792
+ minutes,
8793
+ seconds,
8794
+ showLabels = true,
8795
+ className
8796
+ }) {
8797
+ const units = [
8798
+ { value: days, label: "Days" },
8799
+ { value: hours, label: "Hours" },
8800
+ { value: minutes, label: "Minutes" },
8801
+ { value: seconds, label: "Seconds" }
8802
+ ];
8803
+ return /* @__PURE__ */ jsx(
8804
+ "div",
8805
+ {
8806
+ className: cn("flex items-center gap-2 md:gap-3", className),
8807
+ "data-slot": "countdown",
8808
+ role: "timer",
8809
+ "aria-label": `${days} days, ${hours} hours, ${minutes} minutes, ${seconds} seconds`,
8810
+ children: units.map((unit, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 md:gap-3", children: [
8811
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
8812
+ /* @__PURE__ */ jsx("div", { className: "flex size-14 items-center justify-center rounded-lg border bg-card text-2xl font-bold tabular-nums shadow-sm md:size-16 md:text-3xl", children: pad(unit.value) }),
8813
+ showLabels && /* @__PURE__ */ jsx("span", { className: "mt-1.5 text-[10px] uppercase tracking-wider text-muted-foreground", children: unit.label })
8814
+ ] }),
8815
+ i < units.length - 1 && /* @__PURE__ */ jsx("span", { className: "mb-5 text-xl font-bold text-muted-foreground", "aria-hidden": "true", children: ":" })
8816
+ ] }, unit.label))
8817
+ }
8818
+ );
8819
+ }
8820
+ function SafariMock({
8821
+ children,
8822
+ url = "https://example.com",
8823
+ className
8824
+ }) {
8825
+ return /* @__PURE__ */ jsxs(
8826
+ "div",
8827
+ {
8828
+ className: cn("overflow-hidden rounded-xl border bg-background shadow-xl", className),
8829
+ "data-slot": "safari-mock",
8830
+ children: [
8831
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b bg-muted/50 px-4 py-3", children: [
8832
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-1.5", children: [
8833
+ /* @__PURE__ */ jsx("div", { className: "size-3 rounded-full bg-[#ff5f57]" }),
8834
+ /* @__PURE__ */ jsx("div", { className: "size-3 rounded-full bg-[#febc2e]" }),
8835
+ /* @__PURE__ */ jsx("div", { className: "size-3 rounded-full bg-[#28c840]" })
8836
+ ] }),
8837
+ /* @__PURE__ */ jsxs("div", { className: "mx-auto flex max-w-md flex-1 items-center justify-center rounded-md bg-background/80 px-3 py-1 text-xs text-muted-foreground", children: [
8838
+ /* @__PURE__ */ jsx(
8839
+ "svg",
8840
+ {
8841
+ className: "mr-1.5 size-3 text-muted-foreground/50",
8842
+ fill: "none",
8843
+ stroke: "currentColor",
8844
+ viewBox: "0 0 24 24",
8845
+ "aria-hidden": "true",
8846
+ children: /* @__PURE__ */ jsx(
8847
+ "path",
8848
+ {
8849
+ strokeLinecap: "round",
8850
+ strokeLinejoin: "round",
8851
+ strokeWidth: 2,
8852
+ d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
8853
+ }
8854
+ )
8855
+ }
8856
+ ),
8857
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: url })
8858
+ ] })
8859
+ ] }),
8860
+ /* @__PURE__ */ jsx("div", { className: "overflow-hidden", children })
8861
+ ]
8862
+ }
8863
+ );
8864
+ }
8865
+ function IPhoneMock({
8866
+ children,
8867
+ className
8868
+ }) {
8869
+ return /* @__PURE__ */ jsxs(
8870
+ "div",
8871
+ {
8872
+ className: cn(
8873
+ "relative mx-auto w-[280px] rounded-[2.5rem] border-[6px] border-foreground/10 bg-background p-1.5 shadow-xl",
8874
+ className
8875
+ ),
8876
+ "data-slot": "iphone-mock",
8877
+ children: [
8878
+ /* @__PURE__ */ jsx("div", { className: "absolute left-1/2 top-2 z-10 h-5 w-24 -translate-x-1/2 rounded-full bg-foreground/10" }),
8879
+ /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[2rem] bg-background", children: [
8880
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-2 text-[10px] font-semibold text-foreground", children: [
8881
+ /* @__PURE__ */ jsx("span", { children: "9:41" }),
8882
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
8883
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-0.5", children: [
8884
+ /* @__PURE__ */ jsx("div", { className: "h-2 w-0.5 rounded-sm bg-foreground" }),
8885
+ /* @__PURE__ */ jsx("div", { className: "h-2.5 w-0.5 rounded-sm bg-foreground" }),
8886
+ /* @__PURE__ */ jsx("div", { className: "h-3 w-0.5 rounded-sm bg-foreground" }),
8887
+ /* @__PURE__ */ jsx("div", { className: "h-3.5 w-0.5 rounded-sm bg-foreground" })
8888
+ ] }),
8889
+ /* @__PURE__ */ jsx("span", { className: "ml-1", children: "100%" })
8890
+ ] })
8891
+ ] }),
8892
+ /* @__PURE__ */ jsx("div", { className: "overflow-hidden", children })
8893
+ ] }),
8894
+ /* @__PURE__ */ jsx("div", { className: "mx-auto mt-1.5 h-1 w-28 rounded-full bg-foreground/20" })
8895
+ ]
8896
+ }
8897
+ );
8898
+ }
8899
+ var DockContext = createContext(null);
8900
+ function useDock() {
8901
+ const ctx = useContext(DockContext);
8902
+ if (!ctx) throw new Error("DockItem must be used within a Dock");
8903
+ return ctx;
8904
+ }
8905
+ function Dock({
8906
+ children,
8907
+ magnification = 1.5,
8908
+ distance = 100,
8909
+ className,
8910
+ surface,
8911
+ radius,
8912
+ animated
8913
+ }) {
8914
+ const sf = useSaasflareProps({ surface, radius, animated });
8915
+ const reduced = useReducedMotion();
8916
+ const mouseX = useMotionValue(Infinity);
8917
+ return /* @__PURE__ */ jsx(DockContext.Provider, { value: { mouseX, magnification, distance, reduced }, children: /* @__PURE__ */ jsx(
8918
+ m.nav,
8919
+ {
8920
+ onMouseMove: (e) => mouseX.set(e.pageX),
8921
+ onMouseLeave: () => mouseX.set(Infinity),
8922
+ "data-slot": "dock",
8923
+ "data-surface": sf.surface,
8924
+ "data-radius": sf.radius,
8925
+ className: cn(
8926
+ "mx-auto flex h-14 items-end gap-2 rounded-2xl border surface-card px-3 pb-2",
8927
+ className
8928
+ ),
8929
+ role: "toolbar",
8930
+ "aria-label": "Dock",
8931
+ children
8932
+ }
8933
+ ) });
8934
+ }
8935
+ var BASE_SIZE = 40;
8936
+ function DockItem({
8937
+ children,
8938
+ label,
8939
+ onClick,
8940
+ className
8941
+ }) {
8942
+ const { mouseX, magnification, distance, reduced } = useDock();
8943
+ const ref = useRef(null);
8944
+ const distanceFromMouse = useTransform(mouseX, (val) => {
8945
+ const bounds = ref.current?.getBoundingClientRect();
8946
+ if (!bounds) return distance + 1;
8947
+ return val - (bounds.x + bounds.width / 2);
8948
+ });
8949
+ const maxSize = BASE_SIZE * magnification;
8950
+ const sizeTransform = useTransform(
8951
+ distanceFromMouse,
8952
+ [-distance, 0, distance],
8953
+ [BASE_SIZE, maxSize, BASE_SIZE]
8954
+ );
8955
+ const size = useSpring(sizeTransform, { stiffness: 300, damping: 25 });
8956
+ return /* @__PURE__ */ jsxs(
8957
+ m.button,
8958
+ {
8959
+ ref,
8960
+ onClick,
8961
+ style: reduced ? { width: BASE_SIZE, height: BASE_SIZE } : { width: size, height: size },
8962
+ className: cn(
8963
+ "relative flex items-center justify-center rounded-xl bg-muted transition-colors hover:bg-muted/80",
8964
+ "group",
8965
+ className
8966
+ ),
8967
+ "aria-label": label,
8968
+ "data-slot": "dock-item",
8969
+ children: [
8970
+ children,
8971
+ /* @__PURE__ */ jsx(
8972
+ "span",
8973
+ {
8974
+ className: "pointer-events-none absolute -top-9 left-1/2 -translate-x-1/2 whitespace-nowrap rounded-md bg-popover px-2 py-1 text-xs text-popover-foreground shadow-md opacity-0 transition-opacity group-hover:opacity-100",
8975
+ role: "tooltip",
8976
+ children: label
8977
+ }
8978
+ )
8979
+ ]
8980
+ }
8981
+ );
8982
+ }
8983
+ function FeatureCard({
8984
+ icon,
8985
+ title,
8986
+ description,
8987
+ className,
8988
+ surface,
8989
+ radius,
8990
+ animated
8991
+ }) {
8992
+ const sf = useSaasflareProps({ surface, radius, animated });
8993
+ return /* @__PURE__ */ jsxs(
8994
+ "div",
8995
+ {
8996
+ "data-slot": "feature-card",
8997
+ "data-surface": sf.surface,
8998
+ "data-radius": sf.radius,
8999
+ className: cn(
9000
+ "rounded-xl border surface-card p-6",
9001
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
9002
+ "motion-reduce:hover:transform-none",
9003
+ className
9004
+ ),
9005
+ children: [
9006
+ icon && /* @__PURE__ */ jsx("div", { className: "mb-4 flex size-10 items-center justify-center rounded-lg bg-primary/10 text-primary [&_svg]:size-5", children: icon }),
9007
+ /* @__PURE__ */ jsx("h3", { className: "text-base font-semibold", children: title }),
9008
+ /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: description })
9009
+ ]
9010
+ }
9011
+ );
9012
+ }
9013
+ function FlipWords({
9014
+ words,
9015
+ interval = 2500,
9016
+ className
9017
+ }) {
9018
+ const reduced = useReducedMotion();
9019
+ const [index, setIndex] = useState(0);
9020
+ const next = useCallback(() => {
9021
+ setIndex((prev) => (prev + 1) % words.length);
9022
+ }, [words.length]);
9023
+ useEffect(() => {
9024
+ if (reduced || words.length <= 1) return;
9025
+ const timer = setInterval(next, interval);
9026
+ return () => clearInterval(timer);
9027
+ }, [reduced, words.length, interval, next]);
9028
+ const longestWord = useMemo(
9029
+ () => words.reduce((a, b) => a.length >= b.length ? a : b, ""),
9030
+ [words]
9031
+ );
9032
+ if (reduced) {
9033
+ return /* @__PURE__ */ jsx("span", { className, children: words[0] });
9034
+ }
9035
+ return /* @__PURE__ */ jsxs(
9036
+ "span",
9037
+ {
9038
+ className: cn("relative inline-block text-left align-baseline", className),
9039
+ "data-slot": "flip-words",
9040
+ children: [
9041
+ /* @__PURE__ */ jsx("span", { className: "invisible", "aria-hidden": "true", children: longestWord }),
9042
+ /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx(
9043
+ m.span,
9044
+ {
9045
+ initial: { y: "100%", opacity: 0 },
9046
+ animate: { y: 0, opacity: 1 },
9047
+ exit: { y: "-100%", opacity: 0 },
9048
+ transition: springBouncy,
9049
+ className: "absolute inset-0",
9050
+ "aria-live": "polite",
9051
+ children: words[index]
9052
+ },
9053
+ words[index]
9054
+ ) })
9055
+ ]
9056
+ }
9057
+ );
9058
+ }
9059
+ function GalleryLightbox({
9060
+ images,
9061
+ open,
9062
+ index,
9063
+ onClose,
9064
+ onIndexChange,
9065
+ className
9066
+ }) {
9067
+ const sf = useSaasflareProps();
9068
+ const prev = useCallback(() => {
9069
+ onIndexChange((index - 1 + images.length) % images.length);
9070
+ }, [index, images.length, onIndexChange]);
9071
+ const next = useCallback(() => {
9072
+ onIndexChange((index + 1) % images.length);
9073
+ }, [index, images.length, onIndexChange]);
9074
+ useEffect(() => {
9075
+ if (!open) return;
9076
+ const onKey = (e) => {
9077
+ if (e.key === "Escape") onClose();
9078
+ if (e.key === "ArrowLeft") prev();
9079
+ if (e.key === "ArrowRight") next();
9080
+ };
9081
+ window.addEventListener("keydown", onKey);
9082
+ return () => window.removeEventListener("keydown", onKey);
9083
+ }, [open, onClose, prev, next]);
9084
+ useEffect(() => {
9085
+ if (open) {
9086
+ document.body.style.overflow = "hidden";
9087
+ return () => {
9088
+ document.body.style.overflow = "";
9089
+ };
9090
+ }
9091
+ }, [open]);
9092
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsxs(
9093
+ m.div,
9094
+ {
9095
+ initial: { opacity: 0 },
9096
+ animate: { opacity: 1 },
9097
+ exit: { opacity: 0 },
9098
+ className: cn(
9099
+ "fixed inset-0 z-50 flex items-center justify-center bg-black/90 backdrop-blur-sm",
9100
+ className
9101
+ ),
9102
+ onClick: onClose,
9103
+ role: "dialog",
9104
+ "aria-modal": "true",
9105
+ "aria-label": "Image gallery",
9106
+ "data-slot": "gallery-lightbox",
9107
+ children: [
9108
+ /* @__PURE__ */ jsx(
9109
+ "button",
9110
+ {
9111
+ type: "button",
9112
+ onClick: onClose,
9113
+ className: "absolute right-4 top-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
9114
+ "aria-label": "Close gallery",
9115
+ children: /* @__PURE__ */ jsx(XIcon, { weight: sf.iconWeight, className: "size-6" })
9116
+ }
9117
+ ),
9118
+ images.length > 1 && /* @__PURE__ */ jsx(
9119
+ "button",
9120
+ {
9121
+ type: "button",
9122
+ onClick: (e) => {
9123
+ e.stopPropagation();
9124
+ prev();
9125
+ },
9126
+ className: "absolute left-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
9127
+ "aria-label": "Previous image",
9128
+ children: /* @__PURE__ */ jsx(CaretLeftIcon, { weight: sf.iconWeight, className: "size-6" })
9129
+ }
9130
+ ),
9131
+ /* @__PURE__ */ jsx(
9132
+ m.img,
9133
+ {
9134
+ src: images[index],
9135
+ alt: `Image ${index + 1} of ${images.length}`,
9136
+ initial: { opacity: 0, scale: 0.95 },
9137
+ animate: { opacity: 1, scale: 1 },
9138
+ exit: { opacity: 0, scale: 0.95 },
9139
+ transition: { duration: 0.2 },
9140
+ className: "max-h-[85vh] max-w-[90vw] rounded-lg object-contain",
9141
+ onClick: (e) => e.stopPropagation()
9142
+ },
9143
+ index
9144
+ ),
9145
+ images.length > 1 && /* @__PURE__ */ jsx(
9146
+ "button",
9147
+ {
9148
+ type: "button",
9149
+ onClick: (e) => {
9150
+ e.stopPropagation();
9151
+ next();
9152
+ },
9153
+ className: "absolute right-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
9154
+ "aria-label": "Next image",
9155
+ children: /* @__PURE__ */ jsx(CaretRightIcon, { weight: sf.iconWeight, className: "size-6" })
9156
+ }
9157
+ ),
9158
+ images.length > 1 && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full bg-black/50 px-3 py-1 text-sm text-white backdrop-blur-sm", children: [
9159
+ index + 1,
9160
+ " / ",
9161
+ images.length
9162
+ ] })
9163
+ ]
9164
+ }
9165
+ ) });
9166
+ }
9167
+ function useMousePosition(options = {}) {
9168
+ const { ref, enabled = true, useRAF = true } = options;
9169
+ const [position, setPosition] = useState({ x: 0, y: 0 });
9170
+ const rafRef = useRef(void 0);
9171
+ const updatePosition = useCallback(
9172
+ (clientX, clientY) => {
9173
+ const perform = () => {
9174
+ if (ref?.current) {
9175
+ const rect = ref.current.getBoundingClientRect();
9176
+ setPosition({ x: clientX - rect.left, y: clientY - rect.top });
9177
+ } else {
9178
+ setPosition({ x: clientX, y: clientY });
9179
+ }
9180
+ };
9181
+ if (useRAF) {
9182
+ if (rafRef.current) cancelAnimationFrame(rafRef.current);
9183
+ rafRef.current = requestAnimationFrame(perform);
9184
+ } else {
9185
+ perform();
9186
+ }
9187
+ },
9188
+ [ref, useRAF]
9189
+ );
9190
+ useEffect(() => {
9191
+ if (!enabled) return;
9192
+ const target = ref?.current ?? window;
9193
+ const handler = (event) => {
9194
+ const e = event;
9195
+ updatePosition(e.clientX, e.clientY);
9196
+ };
9197
+ target.addEventListener("mousemove", handler, { passive: true });
9198
+ return () => {
9199
+ target.removeEventListener("mousemove", handler);
9200
+ if (rafRef.current) cancelAnimationFrame(rafRef.current);
9201
+ };
9202
+ }, [ref, enabled, updatePosition]);
9203
+ return position;
9204
+ }
9205
+ function GlowingEffect({
9206
+ color = "hsl(var(--primary))",
9207
+ spread = 150,
9208
+ blur = 20,
9209
+ opacity = 0.4,
9210
+ borderRadius = "inherit",
9211
+ className
9212
+ }) {
9213
+ const reduced = useReducedMotion();
9214
+ const ref = useRef(null);
9215
+ const pos = useMousePosition({ ref, enabled: !reduced });
9216
+ const [hovered, setHovered] = useState(false);
9217
+ if (reduced) return null;
9218
+ return /* @__PURE__ */ jsx(
9219
+ "div",
9220
+ {
9221
+ ref,
9222
+ className: cn("pointer-events-none absolute inset-0", className),
9223
+ style: { borderRadius },
9224
+ onMouseEnter: () => setHovered(true),
9225
+ onMouseLeave: () => setHovered(false),
9226
+ "aria-hidden": "true",
9227
+ "data-slot": "glowing-effect",
9228
+ children: /* @__PURE__ */ jsx(
9229
+ "div",
9230
+ {
9231
+ className: "absolute inset-0 transition-opacity duration-300",
9232
+ style: {
9233
+ opacity: hovered ? opacity : 0,
9234
+ background: `radial-gradient(${spread}px circle at ${pos.x}px ${pos.y}px, ${color}, transparent 70%)`,
9235
+ filter: `blur(${blur}px)`,
9236
+ borderRadius,
9237
+ /* Mask to show glow only on borders, not fill */
9238
+ maskImage: `
9239
+ linear-gradient(black, black),
9240
+ linear-gradient(black, black)
9241
+ `,
9242
+ maskComposite: "exclude",
9243
+ WebkitMaskComposite: "xor",
9244
+ maskClip: "border-box, content-box",
9245
+ WebkitMaskClip: "border-box, content-box",
9246
+ padding: "2px"
9247
+ }
9248
+ }
9249
+ )
9250
+ }
9251
+ );
9252
+ }
9253
+ function GradientText({
9254
+ children,
9255
+ colors = [
9256
+ "hsl(var(--primary))",
9257
+ "hsl(var(--chart-1))",
9258
+ "hsl(var(--chart-2))"
9259
+ ],
9260
+ animate = true,
9261
+ speed = 6,
9262
+ angle = 90,
9263
+ className
9264
+ }) {
9265
+ const reduced = useReducedMotion();
9266
+ const shouldAnimate = animate && !reduced;
9267
+ const gradient = `linear-gradient(${angle}deg, ${colors.join(", ")}, ${colors[0]})`;
9268
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
9269
+ shouldAnimate && /* @__PURE__ */ jsx("style", { children: `
9270
+ @keyframes sf-gradient-shift {
9271
+ 0% { background-position: 0% 50%; }
9272
+ 50% { background-position: 100% 50%; }
9273
+ 100% { background-position: 0% 50%; }
9274
+ }
9275
+ ` }),
9276
+ /* @__PURE__ */ jsx(
9277
+ "span",
9278
+ {
9279
+ className: cn(
9280
+ "bg-clip-text text-transparent",
9281
+ className
9282
+ ),
9283
+ style: {
9284
+ backgroundImage: gradient,
9285
+ backgroundSize: shouldAnimate ? "200% 200%" : "100% 100%",
9286
+ ...shouldAnimate && {
9287
+ animation: `sf-gradient-shift ${speed}s ease infinite`
9288
+ }
9289
+ },
9290
+ "data-slot": "gradient-text",
9291
+ children
9292
+ }
9293
+ )
9294
+ ] });
9295
+ }
9296
+ function HeroVideoDialog({
9297
+ videoSrc,
9298
+ thumbnailSrc,
9299
+ thumbnailAlt,
9300
+ aspectRatio = "16/9",
9301
+ className
9302
+ }) {
9303
+ const reduced = useReducedMotion();
9304
+ const sf = useSaasflareProps();
9305
+ const [open, setOpen] = useState(false);
9306
+ const close = useCallback(() => setOpen(false), []);
9307
+ const onKeyDown = useCallback(
9308
+ (e) => {
9309
+ if (e.key === "Escape") close();
9310
+ },
9311
+ [close]
9312
+ );
9313
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
9314
+ /* @__PURE__ */ jsxs(
9315
+ "button",
9316
+ {
9317
+ type: "button",
9318
+ onClick: () => setOpen(true),
9319
+ className: cn(
9320
+ "group relative w-full cursor-pointer overflow-hidden rounded-xl border shadow-lg",
9321
+ className
9322
+ ),
9323
+ style: { aspectRatio },
9324
+ "aria-label": `Play video: ${thumbnailAlt}`,
9325
+ "data-slot": "hero-video-dialog",
9326
+ children: [
9327
+ /* @__PURE__ */ jsx(
9328
+ "img",
9329
+ {
9330
+ src: thumbnailSrc,
9331
+ alt: thumbnailAlt,
9332
+ className: "size-full object-cover transition-transform duration-300 group-hover:scale-105"
9333
+ }
9334
+ ),
9335
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/20 transition-colors group-hover:bg-black/30", children: /* @__PURE__ */ jsx("div", { className: "flex size-16 items-center justify-center rounded-full bg-white/90 shadow-xl backdrop-blur-sm transition-transform group-hover:scale-110", children: /* @__PURE__ */ jsx(PlayIcon, { weight: sf.iconWeight, className: "ml-1 size-7 text-foreground" }) }) })
9336
+ ]
9337
+ }
9338
+ ),
9339
+ /* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsxs(
9340
+ m.div,
9341
+ {
9342
+ initial: reduced ? { opacity: 1 } : { opacity: 0 },
9343
+ animate: { opacity: 1 },
9344
+ exit: reduced ? { opacity: 0 } : { opacity: 0 },
9345
+ className: "fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm",
9346
+ onClick: close,
9347
+ onKeyDown,
9348
+ role: "dialog",
9349
+ "aria-modal": "true",
9350
+ "aria-label": "Video player",
9351
+ tabIndex: -1,
9352
+ children: [
9353
+ /* @__PURE__ */ jsx(
9354
+ "button",
9355
+ {
9356
+ type: "button",
9357
+ onClick: close,
9358
+ className: "absolute right-4 top-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
9359
+ "aria-label": "Close video",
9360
+ children: /* @__PURE__ */ jsx(XIcon, { weight: sf.iconWeight, className: "size-6" })
9361
+ }
9362
+ ),
9363
+ /* @__PURE__ */ jsx(
9364
+ m.div,
9365
+ {
9366
+ initial: reduced ? false : { scale: 0.9, opacity: 0 },
9367
+ animate: { scale: 1, opacity: 1 },
9368
+ exit: reduced ? { opacity: 0 } : { scale: 0.9, opacity: 0 },
9369
+ transition: reduced ? noMotion : springBouncy,
9370
+ className: "w-full max-w-5xl px-4",
9371
+ onClick: (e) => e.stopPropagation(),
9372
+ children: /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-xl", style: { aspectRatio }, children: /* @__PURE__ */ jsx(
9373
+ "iframe",
9374
+ {
9375
+ src: videoSrc,
9376
+ className: "size-full",
9377
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
9378
+ allowFullScreen: true,
9379
+ title: thumbnailAlt
9380
+ }
9381
+ ) })
9382
+ }
9383
+ )
9384
+ ]
9385
+ }
9386
+ ) })
9387
+ ] });
9388
+ }
9389
+ function Hotspot({ children, className }) {
9390
+ return /* @__PURE__ */ jsx("div", { className: cn("relative", className), "data-slot": "hotspot", children });
9391
+ }
9392
+ function HotspotMarker({
9393
+ x,
9394
+ y,
9395
+ label,
9396
+ description,
9397
+ color = "hsl(var(--primary))",
9398
+ className
9399
+ }) {
9400
+ const [hovered, setHovered] = useState(false);
9401
+ return /* @__PURE__ */ jsxs(
9402
+ "div",
9403
+ {
9404
+ className: cn("absolute z-10", className),
9405
+ style: { left: `${x}%`, top: `${y}%`, transform: "translate(-50%, -50%)" },
9406
+ onMouseEnter: () => setHovered(true),
9407
+ onMouseLeave: () => setHovered(false),
9408
+ "data-slot": "hotspot-marker",
9409
+ children: [
9410
+ /* @__PURE__ */ jsx(
9411
+ "div",
9412
+ {
9413
+ className: "absolute inset-0 animate-ping rounded-full opacity-30",
9414
+ style: { backgroundColor: color, width: 24, height: 24, margin: -4 },
9415
+ "aria-hidden": "true"
9416
+ }
9417
+ ),
9418
+ /* @__PURE__ */ jsx(
9419
+ "button",
9420
+ {
9421
+ type: "button",
9422
+ className: "relative size-4 rounded-full border-2 border-background shadow-md",
9423
+ style: { backgroundColor: color },
9424
+ "aria-label": label
9425
+ }
9426
+ ),
9427
+ hovered && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-full left-1/2 mb-2 -translate-x-1/2 whitespace-nowrap rounded-lg bg-popover px-3 py-2 text-sm shadow-lg", children: [
9428
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-popover-foreground", children: label }),
9429
+ description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: description })
9430
+ ] })
9431
+ ]
9432
+ }
9433
+ );
9434
+ }
9435
+ function ImageSwapHover({
9436
+ src,
9437
+ hoverSrc,
9438
+ alt,
9439
+ aspectRatio = "1/1",
9440
+ className
9441
+ }) {
9442
+ return /* @__PURE__ */ jsxs(
9443
+ "div",
9444
+ {
9445
+ className: cn("group relative overflow-hidden rounded-xl", className),
9446
+ style: { aspectRatio },
9447
+ "data-slot": "image-swap-hover",
9448
+ children: [
9449
+ /* @__PURE__ */ jsx(
9450
+ "img",
9451
+ {
9452
+ src,
9453
+ alt,
9454
+ className: "absolute inset-0 size-full object-cover transition-opacity duration-300 group-hover:opacity-0"
9455
+ }
9456
+ ),
9457
+ /* @__PURE__ */ jsx(
9458
+ "img",
9459
+ {
9460
+ src: hoverSrc,
9461
+ alt,
9462
+ className: "absolute inset-0 size-full object-cover opacity-0 transition-opacity duration-300 group-hover:opacity-100",
9463
+ "aria-hidden": "true"
9464
+ }
9465
+ )
9466
+ ]
9467
+ }
9468
+ );
9469
+ }
9470
+ function Marquee({
9471
+ children,
9472
+ reverse = false,
9473
+ speed = 40,
9474
+ pauseOnHover = true,
9475
+ gap = 48,
9476
+ repeat = 2,
9477
+ vertical = false,
9478
+ className
9479
+ }) {
9480
+ const reduced = useReducedMotion();
9481
+ if (reduced) {
9482
+ return /* @__PURE__ */ jsx(
9483
+ "div",
9484
+ {
9485
+ className: cn(
9486
+ "flex items-center overflow-hidden",
9487
+ vertical ? "flex-col" : "flex-row",
9488
+ className
9489
+ ),
9490
+ style: { gap },
9491
+ "data-slot": "marquee",
9492
+ children
9493
+ }
9494
+ );
9495
+ }
9496
+ const animationName = vertical ? "marquee-vertical" : "marquee-horizontal";
9497
+ const direction = reverse ? "reverse" : "normal";
9498
+ return /* @__PURE__ */ jsxs(
9499
+ "div",
9500
+ {
9501
+ className: cn(
9502
+ "group relative flex overflow-hidden",
9503
+ vertical ? "flex-col" : "flex-row",
9504
+ className
9505
+ ),
9506
+ "data-slot": "marquee",
9507
+ children: [
9508
+ /* @__PURE__ */ jsx("style", { children: `
9509
+ @keyframes marquee-horizontal {
9510
+ from { transform: translateX(0); }
9511
+ to { transform: translateX(-100%); }
9512
+ }
9513
+ @keyframes marquee-vertical {
9514
+ from { transform: translateY(0); }
9515
+ to { transform: translateY(-100%); }
9516
+ }
9517
+ ` }),
9518
+ Array.from({ length: repeat }, (_, i) => /* @__PURE__ */ jsx(
9519
+ "div",
9520
+ {
9521
+ className: cn(
9522
+ "flex shrink-0 items-center",
9523
+ vertical ? "flex-col" : "flex-row",
9524
+ pauseOnHover && "group-hover:[animation-play-state:paused]"
9525
+ ),
9526
+ style: {
9527
+ gap,
9528
+ animation: `${animationName} ${speed}s linear infinite`,
9529
+ animationDirection: direction
9530
+ },
9531
+ "aria-hidden": i > 0,
9532
+ children
9533
+ },
9534
+ i
9535
+ ))
9536
+ ]
9537
+ }
9538
+ );
9539
+ }
9540
+ function MouseGradientBlob({
9541
+ size = 500,
9542
+ colors = ["hsl(var(--primary))", "hsl(var(--chart-2))"],
9543
+ opacity = 0.15,
9544
+ blur = 80,
9545
+ className
9546
+ }) {
9547
+ const reduced = useReducedMotion();
9548
+ const mouseX = useMotionValue(0);
9549
+ const mouseY = useMotionValue(0);
9550
+ const blobX = useSpring(mouseX, { stiffness: 150, damping: 20 });
9551
+ const blobY = useSpring(mouseY, { stiffness: 150, damping: 20 });
9552
+ const onMouseMove = useCallback(
9553
+ (e) => {
9554
+ const target = e.currentTarget;
9555
+ const rect = target.getBoundingClientRect();
9556
+ mouseX.set(e.clientX - rect.left - size / 2);
9557
+ mouseY.set(e.clientY - rect.top - size / 2);
9558
+ },
9559
+ [mouseX, mouseY, size]
9560
+ );
9561
+ useEffect(() => {
9562
+ const parent = document.querySelector("[data-blob-container]");
9563
+ if (!parent || reduced) return;
9564
+ parent.addEventListener("mousemove", onMouseMove, { passive: true });
9565
+ return () => parent.removeEventListener("mousemove", onMouseMove);
9566
+ }, [onMouseMove, reduced]);
9567
+ if (reduced) return null;
9568
+ return /* @__PURE__ */ jsx(
9569
+ "div",
9570
+ {
9571
+ "data-blob-container": true,
9572
+ className: cn("pointer-events-none absolute inset-0 overflow-hidden", className),
9573
+ "aria-hidden": "true",
9574
+ children: /* @__PURE__ */ jsx(
9575
+ m.div,
9576
+ {
9577
+ style: {
9578
+ x: blobX,
9579
+ y: blobY,
9580
+ width: size,
9581
+ height: size,
9582
+ background: `radial-gradient(circle, ${colors[0]} 0%, ${colors[1]} 50%, transparent 70%)`,
9583
+ opacity,
9584
+ filter: `blur(${blur}px)`,
9585
+ borderRadius: "50%",
9586
+ position: "absolute",
9587
+ top: 0,
9588
+ left: 0
9589
+ }
9590
+ }
9591
+ )
9592
+ }
9593
+ );
9594
+ }
9595
+ function MovingBorder({
9596
+ children,
9597
+ colors = ["hsl(var(--primary))", "hsl(var(--chart-1))", "hsl(var(--chart-2))"],
9598
+ duration = 6,
9599
+ borderWidth = 1.5,
9600
+ borderRadius = "0.75rem",
9601
+ className
9602
+ }) {
9603
+ const reduced = useReducedMotion();
9604
+ const gradientStops = [...colors, colors[0]].join(", ");
9605
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
9606
+ !reduced && /* @__PURE__ */ jsx("style", { children: `
9607
+ @keyframes sf-border-rotate {
9608
+ from { --sf-border-angle: 0deg; }
9609
+ to { --sf-border-angle: 360deg; }
9610
+ }
9611
+ @property --sf-border-angle {
9612
+ syntax: "<angle>";
9613
+ initial-value: 0deg;
9614
+ inherits: false;
9615
+ }
9616
+ ` }),
9617
+ /* @__PURE__ */ jsx(
9618
+ "div",
9619
+ {
9620
+ className: cn("relative", className),
9621
+ style: {
9622
+ padding: borderWidth,
9623
+ borderRadius,
9624
+ background: reduced ? `linear-gradient(135deg, ${gradientStops})` : `conic-gradient(from var(--sf-border-angle, 0deg), ${gradientStops})`,
9625
+ ...reduced ? {} : { animation: `sf-border-rotate ${duration}s linear infinite` }
9626
+ },
9627
+ "data-slot": "moving-border",
9628
+ children: /* @__PURE__ */ jsx(
9629
+ "div",
9630
+ {
9631
+ className: "relative bg-background",
9632
+ style: { borderRadius: `calc(${borderRadius} - ${borderWidth}px)` },
9633
+ children
9634
+ }
9635
+ )
9636
+ }
9637
+ )
9638
+ ] });
9639
+ }
9640
+ var VARIANTS = {
9641
+ fade: {
9642
+ initial: { opacity: 0 },
9643
+ animate: { opacity: 1 },
9644
+ exit: { opacity: 0 }
9645
+ },
9646
+ slideUp: {
9647
+ initial: { opacity: 0, y: 16 },
9648
+ animate: { opacity: 1, y: 0 },
9649
+ exit: { opacity: 0, y: -16 }
9650
+ },
9651
+ slideDown: {
9652
+ initial: { opacity: 0, y: -16 },
9653
+ animate: { opacity: 1, y: 0 },
9654
+ exit: { opacity: 0, y: 16 }
9655
+ },
9656
+ scale: {
9657
+ initial: { opacity: 0, scale: 0.96 },
9658
+ animate: { opacity: 1, scale: 1 },
9659
+ exit: { opacity: 0, scale: 0.96 }
9660
+ }
9661
+ };
9662
+ function PageTransition({
9663
+ children,
9664
+ variant = "fade",
9665
+ duration = 0.3,
9666
+ transitionKey,
9667
+ className
9668
+ }) {
9669
+ const reduced = useReducedMotion();
9670
+ if (reduced) {
9671
+ return /* @__PURE__ */ jsx("div", { className, children });
9672
+ }
9673
+ const preset = VARIANTS[variant];
9674
+ return /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx(
9675
+ m.div,
9676
+ {
9677
+ initial: preset.initial,
9678
+ animate: preset.animate,
9679
+ exit: preset.exit,
9680
+ transition: { duration, ease: "easeInOut" },
9681
+ className: cn("will-change-[opacity,transform]", className),
9682
+ children
9683
+ },
9684
+ transitionKey
9685
+ ) });
9686
+ }
9687
+ function ParallaxSection({
9688
+ children,
9689
+ speed = 0.5,
9690
+ className
9691
+ }) {
9692
+ const reduced = useReducedMotion();
9693
+ const ref = useRef(null);
9694
+ const { scrollYProgress } = useScroll({
9695
+ target: ref,
9696
+ offset: ["start end", "end start"]
9697
+ });
9698
+ const offset = (1 - speed) * 100;
9699
+ const y = useTransform(scrollYProgress, [0, 1], [`-${offset}px`, `${offset}px`]);
9700
+ if (reduced) {
9701
+ return /* @__PURE__ */ jsx("div", { className, children });
9702
+ }
9703
+ return /* @__PURE__ */ jsx("div", { ref, className: cn("relative overflow-hidden", className), "data-slot": "parallax-section", children: /* @__PURE__ */ jsx(m.div, { style: { y }, children }) });
9704
+ }
9705
+ function seededRandom(seed) {
9706
+ const x = Math.sin(seed * 9301 + 49297) * 233280;
9707
+ return x - Math.floor(x);
9708
+ }
9709
+ function ParticlesBackground({
9710
+ count = 20,
9711
+ color = "hsl(var(--primary))",
9712
+ maxSize = 4,
9713
+ minSize = 1,
9714
+ maxOpacity = 0.3,
9715
+ speed = 1,
9716
+ className
9717
+ }) {
9718
+ const reduced = useReducedMotion();
9719
+ const particles = useMemo(
9720
+ () => Array.from({ length: count }, (_, i) => {
9721
+ const r = (seed) => seededRandom(i * 100 + seed);
9722
+ const size = minSize + r(1) * (maxSize - minSize);
9723
+ const duration = (15 + r(2) * 25) / speed;
9724
+ const delay = r(3) * -duration;
9725
+ return {
9726
+ id: i,
9727
+ size,
9728
+ x: r(4) * 100,
9729
+ y: r(5) * 100,
9730
+ opacity: 0.05 + r(6) * maxOpacity,
9731
+ duration,
9732
+ delay,
9733
+ driftX: (r(7) - 0.5) * 40,
9734
+ driftY: -20 - r(8) * 40
9735
+ };
9736
+ }),
9737
+ [count, minSize, maxSize, maxOpacity, speed]
9738
+ );
9739
+ if (reduced) return null;
9740
+ return /* @__PURE__ */ jsxs(
9741
+ "div",
9742
+ {
9743
+ className: cn("pointer-events-none absolute inset-0 overflow-hidden", className),
9744
+ "aria-hidden": "true",
9745
+ "data-slot": "particles-background",
9746
+ children: [
9747
+ /* @__PURE__ */ jsx("style", { children: `
9748
+ @keyframes sf-particle-drift {
9749
+ 0%, 100% { transform: translate(0, 0); }
9750
+ 50% { transform: translate(var(--drift-x), var(--drift-y)); }
9751
+ }
9752
+ ` }),
9753
+ particles.map((p) => /* @__PURE__ */ jsx(
9754
+ "div",
9755
+ {
9756
+ style: {
9757
+ position: "absolute",
9758
+ left: `${p.x}%`,
9759
+ top: `${p.y}%`,
9760
+ width: p.size,
9761
+ height: p.size,
9762
+ backgroundColor: color,
9763
+ borderRadius: "50%",
9764
+ opacity: p.opacity,
9765
+ ["--drift-x"]: `${p.driftX}px`,
9766
+ ["--drift-y"]: `${p.driftY}px`,
9767
+ animation: `sf-particle-drift ${p.duration}s ease-in-out ${p.delay}s infinite`
9768
+ }
9769
+ },
9770
+ p.id
9771
+ ))
9772
+ ]
9773
+ }
9774
+ );
9775
+ }
9776
+ function RetroGrid({
9777
+ gridColor = "hsl(var(--border))",
9778
+ gridSize = 60,
9779
+ angle = 65,
9780
+ opacity = 0.4,
9781
+ className
9782
+ }) {
9783
+ return /* @__PURE__ */ jsx(
9784
+ "div",
9785
+ {
9786
+ className: cn("pointer-events-none absolute inset-0 overflow-hidden", className),
9787
+ "aria-hidden": "true",
9788
+ "data-slot": "retro-grid",
9789
+ children: /* @__PURE__ */ jsx(
9790
+ "div",
9791
+ {
9792
+ style: {
9793
+ position: "absolute",
9794
+ inset: 0,
9795
+ backgroundImage: `
9796
+ linear-gradient(to right, ${gridColor} 1px, transparent 1px),
9797
+ linear-gradient(to bottom, ${gridColor} 1px, transparent 1px)
9798
+ `,
9799
+ backgroundSize: `${gridSize}px ${gridSize}px`,
9800
+ opacity,
9801
+ transform: `perspective(500px) rotateX(${angle}deg)`,
9802
+ transformOrigin: "bottom center",
9803
+ maskImage: "linear-gradient(to bottom, transparent 0%, black 30%, black 70%, transparent 100%)",
9804
+ WebkitMaskImage: "linear-gradient(to bottom, transparent 0%, black 30%, black 70%, transparent 100%)"
9805
+ }
9806
+ }
9807
+ )
9808
+ }
9809
+ );
9810
+ }
9811
+ var DIRECTION_OFFSET = {
9812
+ up: { x: 0, y: 24 },
9813
+ down: { x: 0, y: -24 },
9814
+ left: { x: -24, y: 0 },
9815
+ right: { x: 24, y: 0 },
9816
+ none: { x: 0, y: 0 }
9817
+ };
9818
+ function RevealOnScroll({
9819
+ children,
9820
+ direction = "up",
9821
+ delay = 0,
9822
+ rootMargin = "-80px",
9823
+ once = true,
9824
+ className
9825
+ }) {
9826
+ const reduced = useReducedMotion();
9827
+ const ref = useRef(null);
9828
+ const isInView = useInView(ref, { once, margin: rootMargin });
9829
+ if (reduced) {
9830
+ return /* @__PURE__ */ jsx("div", { className, children });
9831
+ }
9832
+ const offset = DIRECTION_OFFSET[direction];
9833
+ return /* @__PURE__ */ jsx(
9834
+ m.div,
9835
+ {
9836
+ ref,
9837
+ initial: { opacity: 0, x: offset.x, y: offset.y },
9838
+ animate: isInView ? { opacity: 1, x: 0, y: 0 } : { opacity: 0, x: offset.x, y: offset.y },
9839
+ transition: { ...springGentle, delay },
9840
+ className: cn("will-change-[opacity,transform]", className),
9841
+ "data-slot": "reveal-on-scroll",
9842
+ children
9843
+ }
9844
+ );
9845
+ }
9846
+ function ShimmerButton({
9847
+ children,
9848
+ shimmerColor = "rgba(255,255,255,0.2)",
9849
+ speed = 2.5,
9850
+ background = "hsl(var(--primary))",
9851
+ className,
9852
+ ...props
9853
+ }) {
9854
+ const reduced = useReducedMotion();
9855
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
9856
+ !reduced && /* @__PURE__ */ jsx("style", { children: `
9857
+ @keyframes sf-shimmer-slide {
9858
+ from { transform: translateX(-100%) rotate(-15deg); }
9859
+ to { transform: translateX(200%) rotate(-15deg); }
9860
+ }
9861
+ ` }),
9862
+ /* @__PURE__ */ jsxs(
9863
+ "button",
9864
+ {
9865
+ className: cn(
9866
+ "relative inline-flex h-10 items-center justify-center overflow-hidden rounded-md px-6 text-sm font-medium text-primary-foreground shadow-sm transition-all hover:brightness-110",
9867
+ className
9868
+ ),
9869
+ style: { background },
9870
+ "data-slot": "shimmer-button",
9871
+ ...props,
9872
+ children: [
9873
+ !reduced && /* @__PURE__ */ jsx(
9874
+ "div",
9875
+ {
9876
+ className: "pointer-events-none absolute inset-0",
9877
+ style: {
9878
+ background: `linear-gradient(
9879
+ -15deg,
9880
+ transparent 30%,
9881
+ ${shimmerColor} 50%,
9882
+ transparent 70%
9883
+ )`,
9884
+ backgroundSize: "200% 100%",
9885
+ animation: `sf-shimmer-slide ${speed}s ease-in-out infinite`
9886
+ },
9887
+ "aria-hidden": "true"
9888
+ }
9889
+ ),
9890
+ /* @__PURE__ */ jsx("span", { className: "relative z-10", children })
9891
+ ]
9892
+ }
9893
+ )
9894
+ ] });
9895
+ }
9896
+ var PROVIDERS = {
9897
+ google: {
9898
+ label: "Google",
9899
+ bg: "bg-white hover:bg-gray-50 border",
9900
+ fg: "text-gray-700",
9901
+ icon: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18A10.96 10.96 0 001 12c0 1.77.42 3.45 1.18 4.93l3.66-2.84z M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
9902
+ },
9903
+ apple: {
9904
+ label: "Apple",
9905
+ bg: "bg-black hover:bg-gray-900",
9906
+ fg: "text-white",
9907
+ icon: "M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.8-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"
9908
+ },
9909
+ github: {
9910
+ label: "GitHub",
9911
+ bg: "bg-[#24292f] hover:bg-[#1b1f23]",
9912
+ fg: "text-white",
9913
+ icon: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
9914
+ },
9915
+ microsoft: {
9916
+ label: "Microsoft",
9917
+ bg: "bg-white hover:bg-gray-50 border",
9918
+ fg: "text-gray-700",
9919
+ icon: "M3 3h8v8H3V3zm10 0h8v8h-8V3zM3 13h8v8H3v-8zm10 0h8v8h-8v-8z"
9920
+ },
9921
+ twitter: {
9922
+ label: "X (Twitter)",
9923
+ bg: "bg-black hover:bg-gray-900",
9924
+ fg: "text-white",
9925
+ icon: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"
9926
+ }
9927
+ };
9928
+ function SocialButton({
9929
+ provider,
9930
+ label: labelOverride,
9931
+ iconOnly = false,
9932
+ className,
9933
+ ...props
9934
+ }) {
9935
+ const config = PROVIDERS[provider];
9936
+ const displayLabel = labelOverride ?? `Continue with ${config.label}`;
9937
+ return /* @__PURE__ */ jsxs(
9938
+ "button",
9939
+ {
9940
+ type: "button",
9941
+ className: cn(
9942
+ "inline-flex items-center justify-center gap-3 rounded-lg px-4 py-2.5 text-sm font-medium transition-colors",
9943
+ config.bg,
9944
+ config.fg,
9945
+ iconOnly && "px-2.5",
9946
+ className
9947
+ ),
9948
+ "aria-label": displayLabel,
9949
+ "data-slot": "social-button",
9950
+ ...props,
9951
+ children: [
9952
+ /* @__PURE__ */ jsx("svg", { className: "size-5", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: config.icon }) }),
9953
+ !iconOnly && /* @__PURE__ */ jsx("span", { children: displayLabel })
9954
+ ]
9955
+ }
9956
+ );
9957
+ }
9958
+ function SpotlightCard({
9959
+ children,
9960
+ spotlightColor = "hsl(var(--primary))",
9961
+ spotlightSize = 250,
9962
+ spotlightOpacity = 0.08,
9963
+ className,
9964
+ surface,
9965
+ radius,
9966
+ animated
9967
+ }) {
9968
+ const sf = useSaasflareProps({ surface, radius, animated });
9969
+ const reduced = useReducedMotion();
9970
+ const cardRef = useRef(null);
9971
+ const position = useMousePosition({ ref: cardRef, enabled: !reduced });
9972
+ const [isHovered, setIsHovered] = useState(false);
9973
+ return /* @__PURE__ */ jsxs(
9974
+ m.div,
9975
+ {
9976
+ ref: cardRef,
9977
+ onMouseEnter: reduced ? void 0 : () => setIsHovered(true),
9978
+ onMouseLeave: reduced ? void 0 : () => setIsHovered(false),
9979
+ "data-slot": "spotlight-card",
9980
+ "data-surface": sf.surface,
9981
+ "data-radius": sf.radius,
9982
+ className: cn(
9983
+ "relative overflow-hidden rounded-xl border surface-card p-6 text-card-foreground",
9984
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
9985
+ "motion-reduce:hover:transform-none",
9986
+ className
9987
+ ),
9988
+ children: [
9989
+ !reduced && /* @__PURE__ */ jsx(
9990
+ "div",
9991
+ {
9992
+ className: "pointer-events-none absolute inset-0 transition-opacity duration-300",
9993
+ style: {
9994
+ opacity: isHovered ? 1 : 0,
9995
+ background: `radial-gradient(${spotlightSize}px circle at ${position.x}px ${position.y}px, ${spotlightColor} 0%, transparent 70%)`,
9996
+ ...spotlightOpacity < 1 && { opacity: isHovered ? spotlightOpacity : 0 }
9997
+ },
9998
+ "aria-hidden": "true"
9999
+ }
10000
+ ),
10001
+ /* @__PURE__ */ jsx("div", { className: "relative z-10", children })
10002
+ ]
10003
+ }
10004
+ );
10005
+ }
10006
+ function StatCard({
10007
+ value,
10008
+ label,
10009
+ icon,
10010
+ className,
10011
+ surface,
10012
+ radius,
10013
+ animated
10014
+ }) {
10015
+ const sf = useSaasflareProps({ surface, radius, animated });
10016
+ return /* @__PURE__ */ jsxs(
10017
+ "div",
10018
+ {
10019
+ "data-slot": "stat-card",
10020
+ "data-surface": sf.surface,
10021
+ "data-radius": sf.radius,
10022
+ className: cn(
10023
+ "flex flex-col items-center rounded-xl border surface-card p-6 text-center",
10024
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
10025
+ "motion-reduce:hover:transform-none",
10026
+ className
10027
+ ),
10028
+ children: [
10029
+ icon && /* @__PURE__ */ jsx("div", { className: "mb-3 text-primary [&_svg]:size-6", children: icon }),
10030
+ /* @__PURE__ */ jsx("p", { className: "text-3xl font-bold tracking-tight", children: value }),
10031
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: label })
10032
+ ]
10033
+ }
10034
+ );
10035
+ }
10036
+ function Steps({
10037
+ children,
10038
+ current = 0,
10039
+ direction = "horizontal",
10040
+ className
10041
+ }) {
10042
+ const items = Children.toArray(children);
10043
+ return /* @__PURE__ */ jsx(
10044
+ "div",
10045
+ {
10046
+ className: cn(
10047
+ "flex",
10048
+ direction === "horizontal" ? "flex-row items-start" : "flex-col",
10049
+ className
10050
+ ),
10051
+ "data-slot": "steps",
10052
+ role: "list",
10053
+ children: items.map((child, i) => {
10054
+ const status = i < current ? "completed" : i === current ? "active" : "pending";
10055
+ const isLast = i === items.length - 1;
10056
+ return /* @__PURE__ */ jsxs(
10057
+ "div",
10058
+ {
10059
+ className: cn(
10060
+ "flex",
10061
+ direction === "horizontal" ? "flex-1 flex-col items-center" : "flex-row gap-4"
10062
+ ),
10063
+ role: "listitem",
10064
+ "aria-current": status === "active" ? "step" : void 0,
10065
+ children: [
10066
+ /* @__PURE__ */ jsxs("div", { className: cn(
10067
+ "flex items-center",
10068
+ direction === "horizontal" ? "w-full" : "flex-col"
10069
+ ), children: [
10070
+ /* @__PURE__ */ jsx(
10071
+ "div",
10072
+ {
10073
+ className: cn(
10074
+ "flex size-9 shrink-0 items-center justify-center rounded-full border-2 text-sm font-semibold transition-colors",
10075
+ status === "completed" && "border-primary bg-primary text-primary-foreground",
10076
+ status === "active" && "border-primary bg-background text-primary",
10077
+ status === "pending" && "border-muted-foreground/30 bg-background text-muted-foreground"
10078
+ ),
10079
+ children: status === "completed" ? /* @__PURE__ */ jsx("svg", { className: "size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) }) : child.props.icon ?? i + 1
10080
+ }
10081
+ ),
10082
+ !isLast && /* @__PURE__ */ jsx(
10083
+ "div",
10084
+ {
10085
+ className: cn(
10086
+ direction === "horizontal" ? "h-0.5 flex-1" : "w-0.5 min-h-8 flex-1",
10087
+ status === "completed" ? "bg-primary" : "bg-border"
10088
+ )
10089
+ }
10090
+ )
10091
+ ] }),
10092
+ /* @__PURE__ */ jsxs("div", { className: cn(
10093
+ direction === "horizontal" ? "mt-2 text-center" : "pb-8"
10094
+ ), children: [
10095
+ /* @__PURE__ */ jsx("p", { className: cn(
10096
+ "text-sm font-medium",
10097
+ status === "pending" && "text-muted-foreground"
10098
+ ), children: child.props.title }),
10099
+ child.props.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: child.props.description })
10100
+ ] })
10101
+ ]
10102
+ },
10103
+ i
10104
+ );
10105
+ })
10106
+ }
10107
+ );
10108
+ }
10109
+ function Step(_props) {
10110
+ return null;
10111
+ }
10112
+ function StickyScrollReveal({
10113
+ items,
10114
+ className
10115
+ }) {
10116
+ const reduced = useReducedMotion();
10117
+ const containerRef = useRef(null);
10118
+ if (reduced) {
10119
+ return /* @__PURE__ */ jsx("div", { className: cn("space-y-16", className), "data-slot": "sticky-scroll-reveal", children: items.map((item, i) => /* @__PURE__ */ jsxs("div", { className: "grid gap-8 md:grid-cols-2", children: [
10120
+ /* @__PURE__ */ jsxs("div", { children: [
10121
+ /* @__PURE__ */ jsx("h3", { className: "text-2xl font-bold", children: item.title }),
10122
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-muted-foreground", children: item.description })
10123
+ ] }),
10124
+ item.content && /* @__PURE__ */ jsx("div", { className: "rounded-xl border bg-muted/50 p-4", children: item.content })
10125
+ ] }, i)) });
10126
+ }
10127
+ return /* @__PURE__ */ jsx(
10128
+ "div",
10129
+ {
10130
+ ref: containerRef,
10131
+ className: cn("relative", className),
10132
+ "data-slot": "sticky-scroll-reveal",
10133
+ children: /* @__PURE__ */ jsxs("div", { className: "relative grid gap-8 md:grid-cols-2", children: [
10134
+ /* @__PURE__ */ jsx("div", { className: "relative md:h-fit", children: /* @__PURE__ */ jsx("div", { className: "sticky top-32 space-y-24", children: items.map((item, i) => /* @__PURE__ */ jsx(
10135
+ StickyItem,
10136
+ {
10137
+ item,
10138
+ index: i,
10139
+ total: items.length,
10140
+ containerRef
10141
+ },
10142
+ i
10143
+ )) }) }),
10144
+ /* @__PURE__ */ jsx("div", { className: "space-y-24", children: items.map((item, i) => /* @__PURE__ */ jsx("div", { className: "sticky top-32", children: /* @__PURE__ */ jsx(
10145
+ StickyContent,
10146
+ {
10147
+ content: item.content,
10148
+ index: i,
10149
+ total: items.length,
10150
+ containerRef
10151
+ }
10152
+ ) }, i)) })
10153
+ ] })
10154
+ }
10155
+ );
10156
+ }
10157
+ function StickyItem({
10158
+ item,
10159
+ index,
10160
+ total,
10161
+ containerRef
10162
+ }) {
10163
+ const { scrollYProgress } = useScroll({
10164
+ target: containerRef,
10165
+ offset: ["start start", "end end"]
10166
+ });
10167
+ const sectionStart = index / total;
10168
+ const sectionEnd = (index + 1) / total;
10169
+ const opacity = useTransform(
10170
+ scrollYProgress,
10171
+ [sectionStart, sectionStart + 0.05, sectionEnd - 0.05, sectionEnd],
10172
+ [0.3, 1, 1, 0.3]
10173
+ );
10174
+ return /* @__PURE__ */ jsxs(m.div, { style: { opacity }, children: [
10175
+ /* @__PURE__ */ jsx("h3", { className: "text-2xl font-bold", children: item.title }),
10176
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-muted-foreground", children: item.description })
10177
+ ] });
10178
+ }
10179
+ function StickyContent({
10180
+ content,
10181
+ index,
10182
+ total,
10183
+ containerRef
10184
+ }) {
10185
+ const { scrollYProgress } = useScroll({
10186
+ target: containerRef,
10187
+ offset: ["start start", "end end"]
10188
+ });
10189
+ const sectionStart = index / total;
10190
+ const sectionEnd = (index + 1) / total;
10191
+ const opacity = useTransform(
10192
+ scrollYProgress,
10193
+ [sectionStart, sectionStart + 0.05, sectionEnd - 0.05, sectionEnd],
10194
+ [0, 1, 1, 0]
10195
+ );
10196
+ if (!content) return null;
10197
+ return /* @__PURE__ */ jsx(
10198
+ m.div,
10199
+ {
10200
+ style: { opacity },
10201
+ className: "overflow-hidden rounded-xl border bg-muted/50 p-4",
10202
+ children: content
10203
+ }
10204
+ );
10205
+ }
10206
+ function TeamCard({
10207
+ name,
10208
+ role,
10209
+ photo,
10210
+ bio,
10211
+ socials,
10212
+ className,
10213
+ surface,
10214
+ radius,
10215
+ animated
10216
+ }) {
10217
+ const sf = useSaasflareProps({ surface, radius, animated });
10218
+ return /* @__PURE__ */ jsxs(
10219
+ "div",
10220
+ {
10221
+ "data-slot": "team-card",
10222
+ "data-surface": sf.surface,
10223
+ "data-radius": sf.radius,
10224
+ className: cn(
10225
+ "flex flex-col items-center rounded-xl border surface-card p-6 text-center",
10226
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
10227
+ "motion-reduce:hover:transform-none",
10228
+ className
10229
+ ),
10230
+ children: [
10231
+ photo && /* @__PURE__ */ jsx(
10232
+ "img",
10233
+ {
10234
+ src: photo,
10235
+ alt: name,
10236
+ className: "mb-4 size-24 rounded-full object-cover"
10237
+ }
10238
+ ),
10239
+ /* @__PURE__ */ jsx("h3", { className: "text-base font-semibold", children: name }),
10240
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: role }),
10241
+ bio && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: bio }),
10242
+ socials && socials.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 flex gap-2", children: socials.map((s) => /* @__PURE__ */ jsx(
10243
+ "a",
10244
+ {
10245
+ href: s.url,
10246
+ target: "_blank",
10247
+ rel: "noopener noreferrer",
10248
+ className: "rounded-md p-2 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
10249
+ "aria-label": s.label,
10250
+ children: s.icon
10251
+ },
10252
+ s.label
10253
+ )) })
10254
+ ]
10255
+ }
10256
+ );
10257
+ }
10258
+ function TestimonialCard({
10259
+ quote,
10260
+ name,
10261
+ role,
10262
+ avatar,
10263
+ rating,
10264
+ className,
10265
+ surface,
10266
+ radius,
10267
+ animated
10268
+ }) {
10269
+ const sf = useSaasflareProps({ surface, radius, animated });
10270
+ return /* @__PURE__ */ jsxs(
10271
+ "div",
10272
+ {
10273
+ "data-slot": "testimonial-card",
10274
+ "data-surface": sf.surface,
10275
+ "data-radius": sf.radius,
10276
+ className: cn(
10277
+ "flex flex-col rounded-xl border surface-card p-6",
10278
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
10279
+ "motion-reduce:hover:transform-none",
10280
+ className
10281
+ ),
10282
+ children: [
10283
+ rating && /* @__PURE__ */ jsx("div", { className: "mb-3 flex gap-0.5", "aria-label": `${rating} out of 5 stars`, children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx(
10284
+ "svg",
10285
+ {
10286
+ className: cn("size-4", i < rating ? "text-warning" : "text-muted-foreground/20"),
10287
+ viewBox: "0 0 20 20",
10288
+ fill: "currentColor",
10289
+ "aria-hidden": "true",
10290
+ children: /* @__PURE__ */ jsx("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" })
10291
+ },
10292
+ i
10293
+ )) }),
10294
+ /* @__PURE__ */ jsxs("blockquote", { className: "flex-1 text-sm leading-relaxed text-foreground", children: [
10295
+ "\u201C",
10296
+ quote,
10297
+ "\u201D"
10298
+ ] }),
10299
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-3", children: [
10300
+ avatar && /* @__PURE__ */ jsx(
10301
+ "img",
10302
+ {
10303
+ src: avatar,
10304
+ alt: name,
10305
+ className: "size-10 rounded-full object-cover"
10306
+ }
10307
+ ),
10308
+ /* @__PURE__ */ jsxs("div", { children: [
10309
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: name }),
10310
+ role && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: role })
10311
+ ] })
10312
+ ] })
10313
+ ]
10314
+ }
10315
+ );
10316
+ }
10317
+ function TextGenerateEffect({
10318
+ text,
10319
+ stagger = 0.05,
10320
+ duration = 0.4,
10321
+ once = true,
10322
+ as: Tag = "p",
10323
+ className
10324
+ }) {
10325
+ const reduced = useReducedMotion();
10326
+ const ref = useRef(null);
10327
+ const isInView = useInView(ref, { once, margin: "-50px" });
10328
+ const words = useMemo(() => text.split(/\s+/), [text]);
10329
+ if (reduced) {
10330
+ return /* @__PURE__ */ jsx(Tag, { className, children: text });
10331
+ }
10332
+ return /* @__PURE__ */ jsx(
10333
+ Tag,
10334
+ {
10335
+ ref,
10336
+ className: cn("inline", className),
10337
+ "data-slot": "text-generate-effect",
10338
+ children: words.map((word, i) => /* @__PURE__ */ jsxs(
10339
+ m.span,
10340
+ {
10341
+ initial: { opacity: 0, filter: "blur(4px)" },
10342
+ animate: isInView ? { opacity: 1, filter: "blur(0px)" } : { opacity: 0, filter: "blur(4px)" },
10343
+ transition: { duration, delay: i * stagger },
10344
+ className: "inline-block",
10345
+ children: [
10346
+ word,
10347
+ i < words.length - 1 && "\xA0"
10348
+ ]
10349
+ },
10350
+ `${word}-${i}`
10351
+ ))
10352
+ }
10353
+ );
10354
+ }
10355
+ function Timeline({ children, className }) {
10356
+ const reduced = useReducedMotion();
10357
+ const containerRef = useRef(null);
10358
+ const { scrollYProgress } = useScroll({
10359
+ target: containerRef,
10360
+ offset: ["start 80%", "end 50%"]
10361
+ });
10362
+ const beamHeight = useTransform(scrollYProgress, [0, 1], ["0%", "100%"]);
10363
+ return /* @__PURE__ */ jsxs(
10364
+ "div",
10365
+ {
10366
+ ref: containerRef,
10367
+ className: cn("relative", className),
10368
+ "data-slot": "timeline",
10369
+ children: [
10370
+ /* @__PURE__ */ jsx("div", { className: "absolute left-4 top-0 h-full w-0.5 bg-border md:left-1/2 md:-translate-x-px" }),
10371
+ !reduced && /* @__PURE__ */ jsx(
10372
+ m.div,
10373
+ {
10374
+ className: "absolute left-4 top-0 w-0.5 bg-primary md:left-1/2 md:-translate-x-px",
10375
+ style: { height: beamHeight }
10376
+ }
10377
+ ),
10378
+ /* @__PURE__ */ jsx("div", { className: "relative space-y-12", children })
10379
+ ]
10380
+ }
10381
+ );
10382
+ }
10383
+ function TimelineItem({
10384
+ title,
10385
+ date,
10386
+ children,
10387
+ className
10388
+ }) {
10389
+ const reduced = useReducedMotion();
10390
+ return /* @__PURE__ */ jsxs(
10391
+ m.div,
10392
+ {
10393
+ initial: reduced ? false : { opacity: 0, y: 16 },
10394
+ whileInView: { opacity: 1, y: 0 },
10395
+ viewport: { once: true, margin: "-80px" },
10396
+ transition: reduced ? { duration: 0 } : { duration: 0.5, ease: "easeOut" },
10397
+ className: cn("relative pl-12 md:pl-0", className),
10398
+ "data-slot": "timeline-item",
10399
+ children: [
10400
+ /* @__PURE__ */ jsx("div", { className: "absolute left-[11px] top-1.5 size-3 rounded-full border-2 border-primary bg-background md:left-1/2 md:-translate-x-1.5" }),
10401
+ /* @__PURE__ */ jsxs("div", { className: "md:ml-[calc(50%+2rem)] md:max-w-[calc(50%-3rem)]", children: [
10402
+ date && /* @__PURE__ */ jsx("span", { className: "mb-1 block text-sm text-muted-foreground", children: date }),
10403
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: title }),
10404
+ /* @__PURE__ */ jsx("div", { className: "mt-1 text-muted-foreground", children })
10405
+ ] })
10406
+ ]
10407
+ }
10408
+ );
10409
+ }
10410
+ function TracingBeam({
10411
+ children,
10412
+ color = "hsl(var(--primary))",
10413
+ trackColor = "hsl(var(--border))",
10414
+ className
10415
+ }) {
10416
+ const reduced = useReducedMotion();
10417
+ const containerRef = useRef(null);
10418
+ const { scrollYProgress } = useScroll({
10419
+ target: containerRef,
10420
+ offset: ["start 20%", "end 80%"]
10421
+ });
10422
+ const beamHeight = useTransform(scrollYProgress, [0, 1], ["0%", "100%"]);
10423
+ const dotY = useTransform(scrollYProgress, [0, 1], ["0%", "100%"]);
10424
+ if (reduced) {
10425
+ return /* @__PURE__ */ jsx("div", { className: cn("border-l-2 border-primary/30 pl-8", className), children });
10426
+ }
10427
+ return /* @__PURE__ */ jsxs(
10428
+ "div",
10429
+ {
10430
+ ref: containerRef,
10431
+ className: cn("relative pl-10", className),
10432
+ "data-slot": "tracing-beam",
10433
+ children: [
10434
+ /* @__PURE__ */ jsx(
10435
+ "div",
10436
+ {
10437
+ className: "absolute left-3 top-0 h-full w-px",
10438
+ style: { backgroundColor: trackColor }
10439
+ }
10440
+ ),
10441
+ /* @__PURE__ */ jsx(
10442
+ m.div,
10443
+ {
10444
+ className: "absolute left-3 top-0 w-px",
10445
+ style: { height: beamHeight, backgroundColor: color }
10446
+ }
10447
+ ),
10448
+ /* @__PURE__ */ jsx(
10449
+ m.div,
10450
+ {
10451
+ className: "absolute left-[9px] size-1.5 rounded-full",
10452
+ style: {
10453
+ top: dotY,
10454
+ backgroundColor: color,
10455
+ boxShadow: `0 0 8px ${color}`
10456
+ }
10457
+ }
10458
+ ),
10459
+ children
10460
+ ]
10461
+ }
10462
+ );
10463
+ }
8333
10464
 
8334
10465
  // src/types/theme-props.ts
8335
10466
  var PALETTES = [
@@ -8443,7 +10574,7 @@ function StatefulButton({
8443
10574
  }
8444
10575
  );
8445
10576
  }
8446
- var PROVIDERS = [
10577
+ var PROVIDERS2 = [
8447
10578
  "google",
8448
10579
  "github",
8449
10580
  "apple",
@@ -8921,4 +11052,4 @@ function UserAvatar({ src, name, initials, size = "md", className }) {
8921
11052
  ] });
8922
11053
  }
8923
11054
 
8924
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnimatedTooltip, AppleAuthButton, AspectRatio, AuroraBackground, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, BarList, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Callout, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CategoryBar, Checkbox, CodeBlock, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, Combobox, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxList, ComboboxSeparator, ComboboxTrigger, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DataToolbar, DataToolbarActions, DataToolbarFilters, DataToolbarSearch, DatePicker, DateRangePicker, DirectionProvider2 as DirectionProvider, DiscordAuthButton, DribbbleAuthButton, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Dropzone, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, FacebookAuthButton, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GitHubAuthButton, GitLabAuthButton, GoogleAuthButton, HoverCard, HoverCardContent, HoverCardTrigger, Icons, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Item9 as Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label5 as Label, LinkedInAuthButton, MediumAuthButton, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MetricCard, MicrosoftAuthButton, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NotificationCenter, NumberInput, PALETTES, PageHeader, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PayPalAuthButton, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PricingCard, Progress, ProgressCircle, RADII, RadioGroup4 as RadioGroup, RadioGroupItem, Rating, RedditAuthButton, PROVIDERS as SOCIAL_AUTH_PROVIDERS, STYLES, ScrollArea, ScrollBar, ScrollToTopButton, SearchField, SectionCard, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator5 as Separator, SettingsSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, SlackAuthButton, Slider, SocialAuthButton, SparkChart, Spinner, StatefulButton, StripeAuthButton, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TagInput, Textarea, ThemeModeMultiToggle, ThemeModeToggle, TikTokAuthButton, Toaster3 as Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TopLoadingBar, Tracker, TreeView, TypewriterText, UserAvatar, XAuthButton, badgeVariants, buttonGroupVariants, navigationMenuTriggerStyle, toggleVariants, useDirection2 as useDirection, useDisclosure, useFileDialog, useFocusTrap, useFormField, useInterval, useIsMobile, useMeasure, useMergedRef, usePagination, useSidebar };
11055
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnimatedTooltip, AppleAuthButton, AspectRatio, AudioPlayer, AuroraBackground, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, BarList, BentoGrid, BentoGridItem, BlurFade, BorderBeam, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Callout, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CategoryBar, Checkbox, CodeBlock, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, Combobox, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxList, ComboboxSeparator, ComboboxTrigger, Compare, Confetti, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, Countdown, DataToolbar, DataToolbarActions, DataToolbarFilters, DataToolbarSearch, DatePicker, DateRangePicker, DirectionProvider2 as DirectionProvider, DiscordAuthButton, Dock, DockItem, DribbbleAuthButton, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Dropzone, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, FacebookAuthButton, FeatureCard, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FlipWords, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GalleryLightbox, GitHubAuthButton, GitLabAuthButton, GlowingEffect, GoogleAuthButton, GradientText, HeroVideoDialog, Hotspot, HotspotMarker, HoverCard, HoverCardContent, HoverCardTrigger, IPhoneMock, Icons, ImageSwapHover, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Item9 as Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label5 as Label, LinkedInAuthButton, Marquee, MediumAuthButton, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MetricCard, MicrosoftAuthButton, MouseGradientBlob, MovingBorder, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NotificationCenter, NumberInput, PALETTES, PageHeader, PageTransition, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, ParallaxSection, ParticlesBackground, PayPalAuthButton, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PricingCard, Progress, ProgressCircle, RADII, RadioGroup4 as RadioGroup, RadioGroupItem, Rating, RedditAuthButton, RetroGrid, RevealOnScroll, PROVIDERS2 as SOCIAL_AUTH_PROVIDERS, STYLES, SafariMock, ScrollArea, ScrollBar, ScrollToTopButton, SearchField, SectionCard, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator5 as Separator, SettingsSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, ShimmerButton, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, SlackAuthButton, Slider, SocialAuthButton, SocialButton, SparkChart, Spinner, SpotlightCard, StatCard, StatefulButton, Step, Steps, StickyScrollReveal, StripeAuthButton, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TagInput, TeamCard, TestimonialCard, TextGenerateEffect, Textarea, ThemeModeMultiToggle, ThemeModeToggle, TikTokAuthButton, Timeline, TimelineItem, Toaster3 as Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TopLoadingBar, TracingBeam, Tracker, TreeView, TypewriterText, UserAvatar, XAuthButton, badgeVariants, buttonGroupVariants, navigationMenuTriggerStyle, toggleVariants, useCountdown, useDirection2 as useDirection, useDisclosure, useFileDialog, useFocusTrap, useFormField, useInterval, useIsMobile, useMeasure, useMergedRef, usePagination, useSidebar };