@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.js CHANGED
@@ -342,6 +342,30 @@ function useFocusTrap(active) {
342
342
  }, [active]);
343
343
  return setRef;
344
344
  }
345
+ function useCountdown(target) {
346
+ const targetMs = new Date(target).getTime();
347
+ const calculate = () => {
348
+ const diff = Math.max(0, targetMs - Date.now());
349
+ return {
350
+ days: Math.floor(diff / (1e3 * 60 * 60 * 24)),
351
+ hours: Math.floor(diff / (1e3 * 60 * 60) % 24),
352
+ minutes: Math.floor(diff / (1e3 * 60) % 60),
353
+ seconds: Math.floor(diff / 1e3 % 60),
354
+ totalMs: diff,
355
+ isExpired: diff <= 0
356
+ };
357
+ };
358
+ const [value, setValue] = React5.useState(calculate);
359
+ React5.useEffect(() => {
360
+ const timer = setInterval(() => {
361
+ const next = calculate();
362
+ setValue(next);
363
+ if (next.isExpired) clearInterval(timer);
364
+ }, 1e3);
365
+ return () => clearInterval(timer);
366
+ }, [targetMs]);
367
+ return value;
368
+ }
345
369
  function useFileDialog(options = {}) {
346
370
  const { accept, multiple = false, directory = false, capture, onChange } = options;
347
371
  const [files, setFiles] = React5.useState([]);
@@ -3298,10 +3322,10 @@ var Observer = class {
3298
3322
  });
3299
3323
  }
3300
3324
  };
3301
- this.custom = (jsx84, data) => {
3325
+ this.custom = (jsx120, data) => {
3302
3326
  const id = (data == null ? void 0 : data.id) || toastsCounter++;
3303
3327
  this.create({
3304
- jsx: jsx84(id),
3328
+ jsx: jsx120(id),
3305
3329
  id,
3306
3330
  ...data
3307
3331
  });
@@ -8378,6 +8402,2113 @@ function AuroraBackground({
8378
8402
  }
8379
8403
  );
8380
8404
  }
8405
+ function formatTime(s) {
8406
+ if (!isFinite(s) || s < 0) return "0:00";
8407
+ const m37 = Math.floor(s / 60);
8408
+ const sec = Math.floor(s % 60);
8409
+ return `${m37}:${String(sec).padStart(2, "0")}`;
8410
+ }
8411
+ function AudioPlayer({
8412
+ src,
8413
+ title,
8414
+ className,
8415
+ surface,
8416
+ radius,
8417
+ animated
8418
+ }) {
8419
+ const sf = chunk2GOPD64T_js.useSaasflareProps({ surface, radius, animated });
8420
+ const audioRef = React5.useRef(null);
8421
+ const [playing, setPlaying] = React5.useState(false);
8422
+ const [current, setCurrent] = React5.useState(0);
8423
+ const [duration, setDuration] = React5.useState(0);
8424
+ const toggle = React5.useCallback(() => {
8425
+ const audio = audioRef.current;
8426
+ if (!audio) return;
8427
+ if (playing) {
8428
+ audio.pause();
8429
+ } else {
8430
+ audio.play();
8431
+ }
8432
+ setPlaying(!playing);
8433
+ }, [playing]);
8434
+ React5.useEffect(() => {
8435
+ const audio = audioRef.current;
8436
+ if (!audio) return;
8437
+ const onTime = () => setCurrent(audio.currentTime);
8438
+ const onMeta = () => setDuration(audio.duration);
8439
+ const onEnded = () => setPlaying(false);
8440
+ audio.addEventListener("timeupdate", onTime);
8441
+ audio.addEventListener("loadedmetadata", onMeta);
8442
+ audio.addEventListener("ended", onEnded);
8443
+ return () => {
8444
+ audio.removeEventListener("timeupdate", onTime);
8445
+ audio.removeEventListener("loadedmetadata", onMeta);
8446
+ audio.removeEventListener("ended", onEnded);
8447
+ };
8448
+ }, []);
8449
+ const seek = React5.useCallback((e) => {
8450
+ const audio = audioRef.current;
8451
+ if (!audio) return;
8452
+ audio.currentTime = Number(e.target.value);
8453
+ }, []);
8454
+ const progress = duration > 0 ? current / duration * 100 : 0;
8455
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8456
+ "div",
8457
+ {
8458
+ "data-slot": "audio-player",
8459
+ "data-surface": sf.surface,
8460
+ "data-radius": sf.radius,
8461
+ className: chunk2GOPD64T_js.cn(
8462
+ "flex items-center gap-3 rounded-xl border surface-card px-4 py-3",
8463
+ "transition-all duration-200 hover:shadow-md",
8464
+ className
8465
+ ),
8466
+ children: [
8467
+ /* @__PURE__ */ jsxRuntime.jsx("audio", { ref: audioRef, src, preload: "metadata" }),
8468
+ /* @__PURE__ */ jsxRuntime.jsx(
8469
+ "button",
8470
+ {
8471
+ type: "button",
8472
+ onClick: toggle,
8473
+ className: "flex size-9 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground transition-colors hover:bg-primary/90",
8474
+ "aria-label": playing ? "Pause" : "Play",
8475
+ children: playing ? /* @__PURE__ */ jsxRuntime.jsx(chunkR3AVBLJ3_js.PauseIcon, { weight: sf.iconWeight, className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(chunkR3AVBLJ3_js.PlayIcon, { weight: sf.iconWeight, className: "ml-0.5 size-4" })
8476
+ }
8477
+ ),
8478
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col gap-1", children: [
8479
+ title && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium truncate", children: title }),
8480
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8481
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] tabular-nums text-muted-foreground", children: formatTime(current) }),
8482
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1", children: [
8483
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1 rounded-full bg-muted", children: /* @__PURE__ */ jsxRuntime.jsx(
8484
+ "div",
8485
+ {
8486
+ className: "h-1 rounded-full bg-primary transition-[width]",
8487
+ style: { width: `${progress}%` }
8488
+ }
8489
+ ) }),
8490
+ /* @__PURE__ */ jsxRuntime.jsx(
8491
+ "input",
8492
+ {
8493
+ type: "range",
8494
+ min: 0,
8495
+ max: duration || 0,
8496
+ value: current,
8497
+ onChange: seek,
8498
+ className: "absolute inset-0 h-1 w-full cursor-pointer opacity-0",
8499
+ "aria-label": "Seek"
8500
+ }
8501
+ )
8502
+ ] }),
8503
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] tabular-nums text-muted-foreground", children: formatTime(duration) })
8504
+ ] })
8505
+ ] })
8506
+ ]
8507
+ }
8508
+ );
8509
+ }
8510
+ var COL_MAP = {
8511
+ 2: "md:grid-cols-2",
8512
+ 3: "md:grid-cols-3",
8513
+ 4: "md:grid-cols-4"
8514
+ };
8515
+ function BentoGrid({
8516
+ children,
8517
+ columns = 3,
8518
+ gap = 4,
8519
+ className
8520
+ }) {
8521
+ return /* @__PURE__ */ jsxRuntime.jsx(
8522
+ "div",
8523
+ {
8524
+ className: chunk2GOPD64T_js.cn(
8525
+ "grid grid-cols-1",
8526
+ COL_MAP[columns],
8527
+ className
8528
+ ),
8529
+ style: { gap: `${gap * 0.25}rem` },
8530
+ "data-slot": "bento-grid",
8531
+ children
8532
+ }
8533
+ );
8534
+ }
8535
+ var COL_SPAN_MAP = {
8536
+ 1: "",
8537
+ 2: "md:col-span-2",
8538
+ 3: "md:col-span-3",
8539
+ 4: "md:col-span-4"
8540
+ };
8541
+ var ROW_SPAN_MAP = {
8542
+ 1: "",
8543
+ 2: "md:row-span-2",
8544
+ 3: "md:row-span-3"
8545
+ };
8546
+ function BentoGridItem({
8547
+ children,
8548
+ colSpan = 1,
8549
+ rowSpan = 1,
8550
+ index = 0,
8551
+ className,
8552
+ surface,
8553
+ radius,
8554
+ animated
8555
+ }) {
8556
+ const sf = chunk2GOPD64T_js.useSaasflareProps({ surface, radius, animated });
8557
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
8558
+ return /* @__PURE__ */ jsxRuntime.jsx(
8559
+ react.m.div,
8560
+ {
8561
+ initial: reduced ? false : { opacity: 0, y: 16 },
8562
+ whileInView: reduced ? void 0 : { opacity: 1, y: 0 },
8563
+ viewport: { once: true, margin: "-60px" },
8564
+ transition: reduced ? chunkITALEYDI_js.noMotion : { ...chunkITALEYDI_js.springGentle, delay: index * 0.08 },
8565
+ "data-slot": "bento-grid-item",
8566
+ "data-surface": sf.surface,
8567
+ "data-radius": sf.radius,
8568
+ className: chunk2GOPD64T_js.cn(
8569
+ "rounded-xl border surface-card p-6 text-card-foreground",
8570
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
8571
+ "motion-reduce:hover:transform-none",
8572
+ COL_SPAN_MAP[colSpan],
8573
+ ROW_SPAN_MAP[rowSpan],
8574
+ className
8575
+ ),
8576
+ children
8577
+ }
8578
+ );
8579
+ }
8580
+ function BlurFade({
8581
+ children,
8582
+ delay = 0,
8583
+ blur = 8,
8584
+ yOffset = 12,
8585
+ duration = 0.5,
8586
+ once = true,
8587
+ className
8588
+ }) {
8589
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
8590
+ const ref = React5.useRef(null);
8591
+ const isInView = react.useInView(ref, { once, margin: "-50px" });
8592
+ if (reduced) {
8593
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children });
8594
+ }
8595
+ return /* @__PURE__ */ jsxRuntime.jsx(
8596
+ react.m.div,
8597
+ {
8598
+ ref,
8599
+ initial: { opacity: 0, y: yOffset, filter: `blur(${blur}px)` },
8600
+ animate: isInView ? { opacity: 1, y: 0, filter: "blur(0px)" } : { opacity: 0, y: yOffset, filter: `blur(${blur}px)` },
8601
+ transition: { duration, delay, ease: "easeOut" },
8602
+ className: chunk2GOPD64T_js.cn("will-change-[opacity,transform,filter]", className),
8603
+ "data-slot": "blur-fade",
8604
+ children
8605
+ }
8606
+ );
8607
+ }
8608
+ function BorderBeam({
8609
+ color = "hsl(var(--primary))",
8610
+ colorFrom = "transparent",
8611
+ duration = 6,
8612
+ size = 150,
8613
+ borderRadius = "inherit",
8614
+ className
8615
+ }) {
8616
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
8617
+ if (reduced) return null;
8618
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8619
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
8620
+ @keyframes sf-border-beam {
8621
+ 0% { offset-distance: 0%; }
8622
+ 100% { offset-distance: 100%; }
8623
+ }
8624
+ ` }),
8625
+ /* @__PURE__ */ jsxRuntime.jsx(
8626
+ "div",
8627
+ {
8628
+ className: chunk2GOPD64T_js.cn("pointer-events-none absolute inset-0", className),
8629
+ style: { borderRadius },
8630
+ "aria-hidden": "true",
8631
+ "data-slot": "border-beam",
8632
+ children: /* @__PURE__ */ jsxRuntime.jsx(
8633
+ "div",
8634
+ {
8635
+ style: {
8636
+ position: "absolute",
8637
+ inset: 0,
8638
+ borderRadius,
8639
+ /* The beam travels along the rect path */
8640
+ offsetPath: `rect(0 auto auto 0 round ${borderRadius})`,
8641
+ animation: `sf-border-beam ${duration}s linear infinite`,
8642
+ background: `linear-gradient(to left, ${color}, ${colorFrom})`,
8643
+ width: size,
8644
+ height: size,
8645
+ opacity: 0.7,
8646
+ filter: "blur(4px)"
8647
+ }
8648
+ }
8649
+ )
8650
+ }
8651
+ )
8652
+ ] });
8653
+ }
8654
+ function Compare({
8655
+ before,
8656
+ after,
8657
+ beforeLabel,
8658
+ afterLabel,
8659
+ initialPosition = 50,
8660
+ aspectRatio = "16/9",
8661
+ className
8662
+ }) {
8663
+ const [position, setPosition] = React5.useState(initialPosition);
8664
+ const containerRef = React5.useRef(null);
8665
+ const dragging = React5.useRef(false);
8666
+ const updatePosition = React5.useCallback((clientX) => {
8667
+ if (!containerRef.current) return;
8668
+ const rect = containerRef.current.getBoundingClientRect();
8669
+ const x = Math.max(0, Math.min(clientX - rect.left, rect.width));
8670
+ setPosition(x / rect.width * 100);
8671
+ }, []);
8672
+ const onPointerDown = React5.useCallback(
8673
+ (e) => {
8674
+ dragging.current = true;
8675
+ e.target.setPointerCapture(e.pointerId);
8676
+ updatePosition(e.clientX);
8677
+ },
8678
+ [updatePosition]
8679
+ );
8680
+ const onPointerMove = React5.useCallback(
8681
+ (e) => {
8682
+ if (!dragging.current) return;
8683
+ updatePosition(e.clientX);
8684
+ },
8685
+ [updatePosition]
8686
+ );
8687
+ const onPointerUp = React5.useCallback(() => {
8688
+ dragging.current = false;
8689
+ }, []);
8690
+ const onKeyDown = React5.useCallback((e) => {
8691
+ if (e.key === "ArrowLeft") setPosition((p) => Math.max(0, p - 2));
8692
+ else if (e.key === "ArrowRight") setPosition((p) => Math.min(100, p + 2));
8693
+ }, []);
8694
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8695
+ "div",
8696
+ {
8697
+ ref: containerRef,
8698
+ className: chunk2GOPD64T_js.cn(
8699
+ "relative select-none overflow-hidden rounded-xl border shadow-sm",
8700
+ className
8701
+ ),
8702
+ style: { aspectRatio },
8703
+ onPointerDown,
8704
+ onPointerMove,
8705
+ onPointerUp,
8706
+ "data-slot": "compare",
8707
+ children: [
8708
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0", children: after }),
8709
+ /* @__PURE__ */ jsxRuntime.jsx(
8710
+ "div",
8711
+ {
8712
+ className: "absolute inset-0 overflow-hidden",
8713
+ style: { width: `${position}%` },
8714
+ children: /* @__PURE__ */ jsxRuntime.jsx(
8715
+ "div",
8716
+ {
8717
+ className: "h-full",
8718
+ style: { width: containerRef.current?.offsetWidth ?? "100%" },
8719
+ children: before
8720
+ }
8721
+ )
8722
+ }
8723
+ ),
8724
+ /* @__PURE__ */ jsxRuntime.jsx(
8725
+ "div",
8726
+ {
8727
+ className: "absolute inset-y-0 z-10 flex w-1 cursor-col-resize items-center bg-white shadow-lg",
8728
+ style: { left: `${position}%`, transform: "translateX(-50%)" },
8729
+ role: "slider",
8730
+ "aria-label": "Comparison slider",
8731
+ "aria-valuenow": Math.round(position),
8732
+ "aria-valuemin": 0,
8733
+ "aria-valuemax": 100,
8734
+ tabIndex: 0,
8735
+ onKeyDown,
8736
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-8 items-center justify-center rounded-full bg-white shadow-md", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 1L1 7L4 13M10 1L13 7L10 13", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) })
8737
+ }
8738
+ ),
8739
+ beforeLabel && /* @__PURE__ */ jsxRuntime.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 }),
8740
+ afterLabel && /* @__PURE__ */ jsxRuntime.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 })
8741
+ ]
8742
+ }
8743
+ );
8744
+ }
8745
+ function seeded(seed) {
8746
+ const x = Math.sin(seed * 9301 + 49297) * 233280;
8747
+ return x - Math.floor(x);
8748
+ }
8749
+ function Confetti({
8750
+ active,
8751
+ count = 40,
8752
+ colors = [
8753
+ "hsl(var(--primary))",
8754
+ "hsl(var(--chart-1))",
8755
+ "hsl(var(--chart-2))",
8756
+ "hsl(var(--chart-3))",
8757
+ "hsl(var(--chart-4))"
8758
+ ],
8759
+ duration = 3e3,
8760
+ onComplete,
8761
+ className
8762
+ }) {
8763
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
8764
+ const [visible, setVisible] = React5.useState(false);
8765
+ React5.useEffect(() => {
8766
+ if (!active || reduced) return;
8767
+ setVisible(true);
8768
+ const timer = setTimeout(() => {
8769
+ setVisible(false);
8770
+ onComplete?.();
8771
+ }, duration);
8772
+ return () => clearTimeout(timer);
8773
+ }, [active, reduced, duration, onComplete]);
8774
+ const particles = React5.useMemo(
8775
+ () => Array.from({ length: count }, (_, i) => {
8776
+ const r = (s) => seeded(i * 100 + s);
8777
+ return {
8778
+ id: i,
8779
+ color: colors[i % colors.length],
8780
+ x: 50 + (r(1) - 0.5) * 60,
8781
+ endX: (r(2) - 0.5) * 200,
8782
+ endY: -(100 + r(3) * 300),
8783
+ size: 4 + r(4) * 6,
8784
+ rotation: r(5) * 720,
8785
+ delay: r(6) * 0.3,
8786
+ animDuration: 1.5 + r(7) * 1.5
8787
+ };
8788
+ }),
8789
+ [count, colors]
8790
+ );
8791
+ if (!visible || reduced) return null;
8792
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8793
+ "div",
8794
+ {
8795
+ className: chunk2GOPD64T_js.cn("pointer-events-none fixed inset-0 z-[9999] overflow-hidden", className),
8796
+ "aria-hidden": "true",
8797
+ "data-slot": "confetti",
8798
+ children: [
8799
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
8800
+ @keyframes sf-confetti-burst {
8801
+ 0% {
8802
+ transform: translate(0, 0) rotate(0deg);
8803
+ opacity: 1;
8804
+ }
8805
+ 100% {
8806
+ transform: translate(var(--cx), var(--cy)) rotate(var(--cr));
8807
+ opacity: 0;
8808
+ }
8809
+ }
8810
+ ` }),
8811
+ particles.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
8812
+ "div",
8813
+ {
8814
+ style: {
8815
+ position: "absolute",
8816
+ left: `${p.x}%`,
8817
+ bottom: 0,
8818
+ width: p.size,
8819
+ height: p.size * 0.6,
8820
+ backgroundColor: p.color,
8821
+ borderRadius: p.id % 3 === 0 ? "50%" : "1px",
8822
+ ["--cx"]: `${p.endX}px`,
8823
+ ["--cy"]: `${p.endY}px`,
8824
+ ["--cr"]: `${p.rotation}deg`,
8825
+ animation: `sf-confetti-burst ${p.animDuration}s cubic-bezier(0.25, 0.46, 0.45, 0.94) ${p.delay}s forwards`
8826
+ }
8827
+ },
8828
+ p.id
8829
+ ))
8830
+ ]
8831
+ }
8832
+ );
8833
+ }
8834
+ function pad(n) {
8835
+ return String(Math.max(0, Math.floor(n))).padStart(2, "0");
8836
+ }
8837
+ function Countdown({
8838
+ days,
8839
+ hours,
8840
+ minutes,
8841
+ seconds,
8842
+ showLabels = true,
8843
+ className
8844
+ }) {
8845
+ const units = [
8846
+ { value: days, label: "Days" },
8847
+ { value: hours, label: "Hours" },
8848
+ { value: minutes, label: "Minutes" },
8849
+ { value: seconds, label: "Seconds" }
8850
+ ];
8851
+ return /* @__PURE__ */ jsxRuntime.jsx(
8852
+ "div",
8853
+ {
8854
+ className: chunk2GOPD64T_js.cn("flex items-center gap-2 md:gap-3", className),
8855
+ "data-slot": "countdown",
8856
+ role: "timer",
8857
+ "aria-label": `${days} days, ${hours} hours, ${minutes} minutes, ${seconds} seconds`,
8858
+ children: units.map((unit, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 md:gap-3", children: [
8859
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [
8860
+ /* @__PURE__ */ jsxRuntime.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) }),
8861
+ showLabels && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1.5 text-[10px] uppercase tracking-wider text-muted-foreground", children: unit.label })
8862
+ ] }),
8863
+ i < units.length - 1 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-5 text-xl font-bold text-muted-foreground", "aria-hidden": "true", children: ":" })
8864
+ ] }, unit.label))
8865
+ }
8866
+ );
8867
+ }
8868
+ function SafariMock({
8869
+ children,
8870
+ url = "https://example.com",
8871
+ className
8872
+ }) {
8873
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8874
+ "div",
8875
+ {
8876
+ className: chunk2GOPD64T_js.cn("overflow-hidden rounded-xl border bg-background shadow-xl", className),
8877
+ "data-slot": "safari-mock",
8878
+ children: [
8879
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-b bg-muted/50 px-4 py-3", children: [
8880
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1.5", children: [
8881
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "size-3 rounded-full bg-[#ff5f57]" }),
8882
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "size-3 rounded-full bg-[#febc2e]" }),
8883
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "size-3 rounded-full bg-[#28c840]" })
8884
+ ] }),
8885
+ /* @__PURE__ */ jsxRuntime.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: [
8886
+ /* @__PURE__ */ jsxRuntime.jsx(
8887
+ "svg",
8888
+ {
8889
+ className: "mr-1.5 size-3 text-muted-foreground/50",
8890
+ fill: "none",
8891
+ stroke: "currentColor",
8892
+ viewBox: "0 0 24 24",
8893
+ "aria-hidden": "true",
8894
+ children: /* @__PURE__ */ jsxRuntime.jsx(
8895
+ "path",
8896
+ {
8897
+ strokeLinecap: "round",
8898
+ strokeLinejoin: "round",
8899
+ strokeWidth: 2,
8900
+ 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"
8901
+ }
8902
+ )
8903
+ }
8904
+ ),
8905
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: url })
8906
+ ] })
8907
+ ] }),
8908
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden", children })
8909
+ ]
8910
+ }
8911
+ );
8912
+ }
8913
+ function IPhoneMock({
8914
+ children,
8915
+ className
8916
+ }) {
8917
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8918
+ "div",
8919
+ {
8920
+ className: chunk2GOPD64T_js.cn(
8921
+ "relative mx-auto w-[280px] rounded-[2.5rem] border-[6px] border-foreground/10 bg-background p-1.5 shadow-xl",
8922
+ className
8923
+ ),
8924
+ "data-slot": "iphone-mock",
8925
+ children: [
8926
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-1/2 top-2 z-10 h-5 w-24 -translate-x-1/2 rounded-full bg-foreground/10" }),
8927
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-[2rem] bg-background", children: [
8928
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-2 text-[10px] font-semibold text-foreground", children: [
8929
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "9:41" }),
8930
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
8931
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-0.5", children: [
8932
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-0.5 rounded-sm bg-foreground" }),
8933
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2.5 w-0.5 rounded-sm bg-foreground" }),
8934
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 w-0.5 rounded-sm bg-foreground" }),
8935
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3.5 w-0.5 rounded-sm bg-foreground" })
8936
+ ] }),
8937
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", children: "100%" })
8938
+ ] })
8939
+ ] }),
8940
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden", children })
8941
+ ] }),
8942
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto mt-1.5 h-1 w-28 rounded-full bg-foreground/20" })
8943
+ ]
8944
+ }
8945
+ );
8946
+ }
8947
+ var DockContext = React5.createContext(null);
8948
+ function useDock() {
8949
+ const ctx = React5.useContext(DockContext);
8950
+ if (!ctx) throw new Error("DockItem must be used within a Dock");
8951
+ return ctx;
8952
+ }
8953
+ function Dock({
8954
+ children,
8955
+ magnification = 1.5,
8956
+ distance = 100,
8957
+ className,
8958
+ surface,
8959
+ radius,
8960
+ animated
8961
+ }) {
8962
+ const sf = chunk2GOPD64T_js.useSaasflareProps({ surface, radius, animated });
8963
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
8964
+ const mouseX = react.useMotionValue(Infinity);
8965
+ return /* @__PURE__ */ jsxRuntime.jsx(DockContext.Provider, { value: { mouseX, magnification, distance, reduced }, children: /* @__PURE__ */ jsxRuntime.jsx(
8966
+ react.m.nav,
8967
+ {
8968
+ onMouseMove: (e) => mouseX.set(e.pageX),
8969
+ onMouseLeave: () => mouseX.set(Infinity),
8970
+ "data-slot": "dock",
8971
+ "data-surface": sf.surface,
8972
+ "data-radius": sf.radius,
8973
+ className: chunk2GOPD64T_js.cn(
8974
+ "mx-auto flex h-14 items-end gap-2 rounded-2xl border surface-card px-3 pb-2",
8975
+ className
8976
+ ),
8977
+ role: "toolbar",
8978
+ "aria-label": "Dock",
8979
+ children
8980
+ }
8981
+ ) });
8982
+ }
8983
+ var BASE_SIZE = 40;
8984
+ function DockItem({
8985
+ children,
8986
+ label,
8987
+ onClick,
8988
+ className
8989
+ }) {
8990
+ const { mouseX, magnification, distance, reduced } = useDock();
8991
+ const ref = React5.useRef(null);
8992
+ const distanceFromMouse = react.useTransform(mouseX, (val) => {
8993
+ const bounds = ref.current?.getBoundingClientRect();
8994
+ if (!bounds) return distance + 1;
8995
+ return val - (bounds.x + bounds.width / 2);
8996
+ });
8997
+ const maxSize = BASE_SIZE * magnification;
8998
+ const sizeTransform = react.useTransform(
8999
+ distanceFromMouse,
9000
+ [-distance, 0, distance],
9001
+ [BASE_SIZE, maxSize, BASE_SIZE]
9002
+ );
9003
+ const size = react.useSpring(sizeTransform, { stiffness: 300, damping: 25 });
9004
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9005
+ react.m.button,
9006
+ {
9007
+ ref,
9008
+ onClick,
9009
+ style: reduced ? { width: BASE_SIZE, height: BASE_SIZE } : { width: size, height: size },
9010
+ className: chunk2GOPD64T_js.cn(
9011
+ "relative flex items-center justify-center rounded-xl bg-muted transition-colors hover:bg-muted/80",
9012
+ "group",
9013
+ className
9014
+ ),
9015
+ "aria-label": label,
9016
+ "data-slot": "dock-item",
9017
+ children: [
9018
+ children,
9019
+ /* @__PURE__ */ jsxRuntime.jsx(
9020
+ "span",
9021
+ {
9022
+ 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",
9023
+ role: "tooltip",
9024
+ children: label
9025
+ }
9026
+ )
9027
+ ]
9028
+ }
9029
+ );
9030
+ }
9031
+ function FeatureCard({
9032
+ icon,
9033
+ title,
9034
+ description,
9035
+ className,
9036
+ surface,
9037
+ radius,
9038
+ animated
9039
+ }) {
9040
+ const sf = chunk2GOPD64T_js.useSaasflareProps({ surface, radius, animated });
9041
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9042
+ "div",
9043
+ {
9044
+ "data-slot": "feature-card",
9045
+ "data-surface": sf.surface,
9046
+ "data-radius": sf.radius,
9047
+ className: chunk2GOPD64T_js.cn(
9048
+ "rounded-xl border surface-card p-6",
9049
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
9050
+ "motion-reduce:hover:transform-none",
9051
+ className
9052
+ ),
9053
+ children: [
9054
+ icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 flex size-10 items-center justify-center rounded-lg bg-primary/10 text-primary [&_svg]:size-5", children: icon }),
9055
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-semibold", children: title }),
9056
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: description })
9057
+ ]
9058
+ }
9059
+ );
9060
+ }
9061
+ function FlipWords({
9062
+ words,
9063
+ interval = 2500,
9064
+ className
9065
+ }) {
9066
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9067
+ const [index, setIndex] = React5.useState(0);
9068
+ const next = React5.useCallback(() => {
9069
+ setIndex((prev) => (prev + 1) % words.length);
9070
+ }, [words.length]);
9071
+ React5.useEffect(() => {
9072
+ if (reduced || words.length <= 1) return;
9073
+ const timer = setInterval(next, interval);
9074
+ return () => clearInterval(timer);
9075
+ }, [reduced, words.length, interval, next]);
9076
+ const longestWord = React5.useMemo(
9077
+ () => words.reduce((a, b) => a.length >= b.length ? a : b, ""),
9078
+ [words]
9079
+ );
9080
+ if (reduced) {
9081
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className, children: words[0] });
9082
+ }
9083
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9084
+ "span",
9085
+ {
9086
+ className: chunk2GOPD64T_js.cn("relative inline-block text-left align-baseline", className),
9087
+ "data-slot": "flip-words",
9088
+ children: [
9089
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "invisible", "aria-hidden": "true", children: longestWord }),
9090
+ /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsxRuntime.jsx(
9091
+ react.m.span,
9092
+ {
9093
+ initial: { y: "100%", opacity: 0 },
9094
+ animate: { y: 0, opacity: 1 },
9095
+ exit: { y: "-100%", opacity: 0 },
9096
+ transition: chunkITALEYDI_js.springBouncy,
9097
+ className: "absolute inset-0",
9098
+ "aria-live": "polite",
9099
+ children: words[index]
9100
+ },
9101
+ words[index]
9102
+ ) })
9103
+ ]
9104
+ }
9105
+ );
9106
+ }
9107
+ function GalleryLightbox({
9108
+ images,
9109
+ open,
9110
+ index,
9111
+ onClose,
9112
+ onIndexChange,
9113
+ className
9114
+ }) {
9115
+ const sf = chunk2GOPD64T_js.useSaasflareProps();
9116
+ const prev = React5.useCallback(() => {
9117
+ onIndexChange((index - 1 + images.length) % images.length);
9118
+ }, [index, images.length, onIndexChange]);
9119
+ const next = React5.useCallback(() => {
9120
+ onIndexChange((index + 1) % images.length);
9121
+ }, [index, images.length, onIndexChange]);
9122
+ React5.useEffect(() => {
9123
+ if (!open) return;
9124
+ const onKey = (e) => {
9125
+ if (e.key === "Escape") onClose();
9126
+ if (e.key === "ArrowLeft") prev();
9127
+ if (e.key === "ArrowRight") next();
9128
+ };
9129
+ window.addEventListener("keydown", onKey);
9130
+ return () => window.removeEventListener("keydown", onKey);
9131
+ }, [open, onClose, prev, next]);
9132
+ React5.useEffect(() => {
9133
+ if (open) {
9134
+ document.body.style.overflow = "hidden";
9135
+ return () => {
9136
+ document.body.style.overflow = "";
9137
+ };
9138
+ }
9139
+ }, [open]);
9140
+ return /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsxs(
9141
+ react.m.div,
9142
+ {
9143
+ initial: { opacity: 0 },
9144
+ animate: { opacity: 1 },
9145
+ exit: { opacity: 0 },
9146
+ className: chunk2GOPD64T_js.cn(
9147
+ "fixed inset-0 z-50 flex items-center justify-center bg-black/90 backdrop-blur-sm",
9148
+ className
9149
+ ),
9150
+ onClick: onClose,
9151
+ role: "dialog",
9152
+ "aria-modal": "true",
9153
+ "aria-label": "Image gallery",
9154
+ "data-slot": "gallery-lightbox",
9155
+ children: [
9156
+ /* @__PURE__ */ jsxRuntime.jsx(
9157
+ "button",
9158
+ {
9159
+ type: "button",
9160
+ onClick: onClose,
9161
+ className: "absolute right-4 top-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
9162
+ "aria-label": "Close gallery",
9163
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunkR3AVBLJ3_js.XIcon, { weight: sf.iconWeight, className: "size-6" })
9164
+ }
9165
+ ),
9166
+ images.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
9167
+ "button",
9168
+ {
9169
+ type: "button",
9170
+ onClick: (e) => {
9171
+ e.stopPropagation();
9172
+ prev();
9173
+ },
9174
+ className: "absolute left-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
9175
+ "aria-label": "Previous image",
9176
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunkR3AVBLJ3_js.CaretLeftIcon, { weight: sf.iconWeight, className: "size-6" })
9177
+ }
9178
+ ),
9179
+ /* @__PURE__ */ jsxRuntime.jsx(
9180
+ react.m.img,
9181
+ {
9182
+ src: images[index],
9183
+ alt: `Image ${index + 1} of ${images.length}`,
9184
+ initial: { opacity: 0, scale: 0.95 },
9185
+ animate: { opacity: 1, scale: 1 },
9186
+ exit: { opacity: 0, scale: 0.95 },
9187
+ transition: { duration: 0.2 },
9188
+ className: "max-h-[85vh] max-w-[90vw] rounded-lg object-contain",
9189
+ onClick: (e) => e.stopPropagation()
9190
+ },
9191
+ index
9192
+ ),
9193
+ images.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
9194
+ "button",
9195
+ {
9196
+ type: "button",
9197
+ onClick: (e) => {
9198
+ e.stopPropagation();
9199
+ next();
9200
+ },
9201
+ className: "absolute right-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
9202
+ "aria-label": "Next image",
9203
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunkR3AVBLJ3_js.CaretRightIcon, { weight: sf.iconWeight, className: "size-6" })
9204
+ }
9205
+ ),
9206
+ images.length > 1 && /* @__PURE__ */ jsxRuntime.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: [
9207
+ index + 1,
9208
+ " / ",
9209
+ images.length
9210
+ ] })
9211
+ ]
9212
+ }
9213
+ ) });
9214
+ }
9215
+ function useMousePosition(options = {}) {
9216
+ const { ref, enabled = true, useRAF = true } = options;
9217
+ const [position, setPosition] = React5.useState({ x: 0, y: 0 });
9218
+ const rafRef = React5.useRef(void 0);
9219
+ const updatePosition = React5.useCallback(
9220
+ (clientX, clientY) => {
9221
+ const perform = () => {
9222
+ if (ref?.current) {
9223
+ const rect = ref.current.getBoundingClientRect();
9224
+ setPosition({ x: clientX - rect.left, y: clientY - rect.top });
9225
+ } else {
9226
+ setPosition({ x: clientX, y: clientY });
9227
+ }
9228
+ };
9229
+ if (useRAF) {
9230
+ if (rafRef.current) cancelAnimationFrame(rafRef.current);
9231
+ rafRef.current = requestAnimationFrame(perform);
9232
+ } else {
9233
+ perform();
9234
+ }
9235
+ },
9236
+ [ref, useRAF]
9237
+ );
9238
+ React5.useEffect(() => {
9239
+ if (!enabled) return;
9240
+ const target = ref?.current ?? window;
9241
+ const handler = (event) => {
9242
+ const e = event;
9243
+ updatePosition(e.clientX, e.clientY);
9244
+ };
9245
+ target.addEventListener("mousemove", handler, { passive: true });
9246
+ return () => {
9247
+ target.removeEventListener("mousemove", handler);
9248
+ if (rafRef.current) cancelAnimationFrame(rafRef.current);
9249
+ };
9250
+ }, [ref, enabled, updatePosition]);
9251
+ return position;
9252
+ }
9253
+ function GlowingEffect({
9254
+ color = "hsl(var(--primary))",
9255
+ spread = 150,
9256
+ blur = 20,
9257
+ opacity = 0.4,
9258
+ borderRadius = "inherit",
9259
+ className
9260
+ }) {
9261
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9262
+ const ref = React5.useRef(null);
9263
+ const pos = useMousePosition({ ref, enabled: !reduced });
9264
+ const [hovered, setHovered] = React5.useState(false);
9265
+ if (reduced) return null;
9266
+ return /* @__PURE__ */ jsxRuntime.jsx(
9267
+ "div",
9268
+ {
9269
+ ref,
9270
+ className: chunk2GOPD64T_js.cn("pointer-events-none absolute inset-0", className),
9271
+ style: { borderRadius },
9272
+ onMouseEnter: () => setHovered(true),
9273
+ onMouseLeave: () => setHovered(false),
9274
+ "aria-hidden": "true",
9275
+ "data-slot": "glowing-effect",
9276
+ children: /* @__PURE__ */ jsxRuntime.jsx(
9277
+ "div",
9278
+ {
9279
+ className: "absolute inset-0 transition-opacity duration-300",
9280
+ style: {
9281
+ opacity: hovered ? opacity : 0,
9282
+ background: `radial-gradient(${spread}px circle at ${pos.x}px ${pos.y}px, ${color}, transparent 70%)`,
9283
+ filter: `blur(${blur}px)`,
9284
+ borderRadius,
9285
+ /* Mask to show glow only on borders, not fill */
9286
+ maskImage: `
9287
+ linear-gradient(black, black),
9288
+ linear-gradient(black, black)
9289
+ `,
9290
+ maskComposite: "exclude",
9291
+ WebkitMaskComposite: "xor",
9292
+ maskClip: "border-box, content-box",
9293
+ WebkitMaskClip: "border-box, content-box",
9294
+ padding: "2px"
9295
+ }
9296
+ }
9297
+ )
9298
+ }
9299
+ );
9300
+ }
9301
+ function GradientText({
9302
+ children,
9303
+ colors = [
9304
+ "hsl(var(--primary))",
9305
+ "hsl(var(--chart-1))",
9306
+ "hsl(var(--chart-2))"
9307
+ ],
9308
+ animate = true,
9309
+ speed = 6,
9310
+ angle = 90,
9311
+ className
9312
+ }) {
9313
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9314
+ const shouldAnimate = animate && !reduced;
9315
+ const gradient = `linear-gradient(${angle}deg, ${colors.join(", ")}, ${colors[0]})`;
9316
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9317
+ shouldAnimate && /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
9318
+ @keyframes sf-gradient-shift {
9319
+ 0% { background-position: 0% 50%; }
9320
+ 50% { background-position: 100% 50%; }
9321
+ 100% { background-position: 0% 50%; }
9322
+ }
9323
+ ` }),
9324
+ /* @__PURE__ */ jsxRuntime.jsx(
9325
+ "span",
9326
+ {
9327
+ className: chunk2GOPD64T_js.cn(
9328
+ "bg-clip-text text-transparent",
9329
+ className
9330
+ ),
9331
+ style: {
9332
+ backgroundImage: gradient,
9333
+ backgroundSize: shouldAnimate ? "200% 200%" : "100% 100%",
9334
+ ...shouldAnimate && {
9335
+ animation: `sf-gradient-shift ${speed}s ease infinite`
9336
+ }
9337
+ },
9338
+ "data-slot": "gradient-text",
9339
+ children
9340
+ }
9341
+ )
9342
+ ] });
9343
+ }
9344
+ function HeroVideoDialog({
9345
+ videoSrc,
9346
+ thumbnailSrc,
9347
+ thumbnailAlt,
9348
+ aspectRatio = "16/9",
9349
+ className
9350
+ }) {
9351
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9352
+ const sf = chunk2GOPD64T_js.useSaasflareProps();
9353
+ const [open, setOpen] = React5.useState(false);
9354
+ const close = React5.useCallback(() => setOpen(false), []);
9355
+ const onKeyDown = React5.useCallback(
9356
+ (e) => {
9357
+ if (e.key === "Escape") close();
9358
+ },
9359
+ [close]
9360
+ );
9361
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9362
+ /* @__PURE__ */ jsxRuntime.jsxs(
9363
+ "button",
9364
+ {
9365
+ type: "button",
9366
+ onClick: () => setOpen(true),
9367
+ className: chunk2GOPD64T_js.cn(
9368
+ "group relative w-full cursor-pointer overflow-hidden rounded-xl border shadow-lg",
9369
+ className
9370
+ ),
9371
+ style: { aspectRatio },
9372
+ "aria-label": `Play video: ${thumbnailAlt}`,
9373
+ "data-slot": "hero-video-dialog",
9374
+ children: [
9375
+ /* @__PURE__ */ jsxRuntime.jsx(
9376
+ "img",
9377
+ {
9378
+ src: thumbnailSrc,
9379
+ alt: thumbnailAlt,
9380
+ className: "size-full object-cover transition-transform duration-300 group-hover:scale-105"
9381
+ }
9382
+ ),
9383
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/20 transition-colors group-hover:bg-black/30", children: /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(chunkR3AVBLJ3_js.PlayIcon, { weight: sf.iconWeight, className: "ml-1 size-7 text-foreground" }) }) })
9384
+ ]
9385
+ }
9386
+ ),
9387
+ /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsxs(
9388
+ react.m.div,
9389
+ {
9390
+ initial: reduced ? { opacity: 1 } : { opacity: 0 },
9391
+ animate: { opacity: 1 },
9392
+ exit: reduced ? { opacity: 0 } : { opacity: 0 },
9393
+ className: "fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm",
9394
+ onClick: close,
9395
+ onKeyDown,
9396
+ role: "dialog",
9397
+ "aria-modal": "true",
9398
+ "aria-label": "Video player",
9399
+ tabIndex: -1,
9400
+ children: [
9401
+ /* @__PURE__ */ jsxRuntime.jsx(
9402
+ "button",
9403
+ {
9404
+ type: "button",
9405
+ onClick: close,
9406
+ className: "absolute right-4 top-4 z-10 rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/20",
9407
+ "aria-label": "Close video",
9408
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunkR3AVBLJ3_js.XIcon, { weight: sf.iconWeight, className: "size-6" })
9409
+ }
9410
+ ),
9411
+ /* @__PURE__ */ jsxRuntime.jsx(
9412
+ react.m.div,
9413
+ {
9414
+ initial: reduced ? false : { scale: 0.9, opacity: 0 },
9415
+ animate: { scale: 1, opacity: 1 },
9416
+ exit: reduced ? { opacity: 0 } : { scale: 0.9, opacity: 0 },
9417
+ transition: reduced ? chunkITALEYDI_js.noMotion : chunkITALEYDI_js.springBouncy,
9418
+ className: "w-full max-w-5xl px-4",
9419
+ onClick: (e) => e.stopPropagation(),
9420
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-xl", style: { aspectRatio }, children: /* @__PURE__ */ jsxRuntime.jsx(
9421
+ "iframe",
9422
+ {
9423
+ src: videoSrc,
9424
+ className: "size-full",
9425
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
9426
+ allowFullScreen: true,
9427
+ title: thumbnailAlt
9428
+ }
9429
+ ) })
9430
+ }
9431
+ )
9432
+ ]
9433
+ }
9434
+ ) })
9435
+ ] });
9436
+ }
9437
+ function Hotspot({ children, className }) {
9438
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunk2GOPD64T_js.cn("relative", className), "data-slot": "hotspot", children });
9439
+ }
9440
+ function HotspotMarker({
9441
+ x,
9442
+ y,
9443
+ label,
9444
+ description,
9445
+ color = "hsl(var(--primary))",
9446
+ className
9447
+ }) {
9448
+ const [hovered, setHovered] = React5.useState(false);
9449
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9450
+ "div",
9451
+ {
9452
+ className: chunk2GOPD64T_js.cn("absolute z-10", className),
9453
+ style: { left: `${x}%`, top: `${y}%`, transform: "translate(-50%, -50%)" },
9454
+ onMouseEnter: () => setHovered(true),
9455
+ onMouseLeave: () => setHovered(false),
9456
+ "data-slot": "hotspot-marker",
9457
+ children: [
9458
+ /* @__PURE__ */ jsxRuntime.jsx(
9459
+ "div",
9460
+ {
9461
+ className: "absolute inset-0 animate-ping rounded-full opacity-30",
9462
+ style: { backgroundColor: color, width: 24, height: 24, margin: -4 },
9463
+ "aria-hidden": "true"
9464
+ }
9465
+ ),
9466
+ /* @__PURE__ */ jsxRuntime.jsx(
9467
+ "button",
9468
+ {
9469
+ type: "button",
9470
+ className: "relative size-4 rounded-full border-2 border-background shadow-md",
9471
+ style: { backgroundColor: color },
9472
+ "aria-label": label
9473
+ }
9474
+ ),
9475
+ hovered && /* @__PURE__ */ jsxRuntime.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: [
9476
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-popover-foreground", children: label }),
9477
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: description })
9478
+ ] })
9479
+ ]
9480
+ }
9481
+ );
9482
+ }
9483
+ function ImageSwapHover({
9484
+ src,
9485
+ hoverSrc,
9486
+ alt,
9487
+ aspectRatio = "1/1",
9488
+ className
9489
+ }) {
9490
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9491
+ "div",
9492
+ {
9493
+ className: chunk2GOPD64T_js.cn("group relative overflow-hidden rounded-xl", className),
9494
+ style: { aspectRatio },
9495
+ "data-slot": "image-swap-hover",
9496
+ children: [
9497
+ /* @__PURE__ */ jsxRuntime.jsx(
9498
+ "img",
9499
+ {
9500
+ src,
9501
+ alt,
9502
+ className: "absolute inset-0 size-full object-cover transition-opacity duration-300 group-hover:opacity-0"
9503
+ }
9504
+ ),
9505
+ /* @__PURE__ */ jsxRuntime.jsx(
9506
+ "img",
9507
+ {
9508
+ src: hoverSrc,
9509
+ alt,
9510
+ className: "absolute inset-0 size-full object-cover opacity-0 transition-opacity duration-300 group-hover:opacity-100",
9511
+ "aria-hidden": "true"
9512
+ }
9513
+ )
9514
+ ]
9515
+ }
9516
+ );
9517
+ }
9518
+ function Marquee({
9519
+ children,
9520
+ reverse = false,
9521
+ speed = 40,
9522
+ pauseOnHover = true,
9523
+ gap = 48,
9524
+ repeat = 2,
9525
+ vertical = false,
9526
+ className
9527
+ }) {
9528
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9529
+ if (reduced) {
9530
+ return /* @__PURE__ */ jsxRuntime.jsx(
9531
+ "div",
9532
+ {
9533
+ className: chunk2GOPD64T_js.cn(
9534
+ "flex items-center overflow-hidden",
9535
+ vertical ? "flex-col" : "flex-row",
9536
+ className
9537
+ ),
9538
+ style: { gap },
9539
+ "data-slot": "marquee",
9540
+ children
9541
+ }
9542
+ );
9543
+ }
9544
+ const animationName = vertical ? "marquee-vertical" : "marquee-horizontal";
9545
+ const direction = reverse ? "reverse" : "normal";
9546
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9547
+ "div",
9548
+ {
9549
+ className: chunk2GOPD64T_js.cn(
9550
+ "group relative flex overflow-hidden",
9551
+ vertical ? "flex-col" : "flex-row",
9552
+ className
9553
+ ),
9554
+ "data-slot": "marquee",
9555
+ children: [
9556
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
9557
+ @keyframes marquee-horizontal {
9558
+ from { transform: translateX(0); }
9559
+ to { transform: translateX(-100%); }
9560
+ }
9561
+ @keyframes marquee-vertical {
9562
+ from { transform: translateY(0); }
9563
+ to { transform: translateY(-100%); }
9564
+ }
9565
+ ` }),
9566
+ Array.from({ length: repeat }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx(
9567
+ "div",
9568
+ {
9569
+ className: chunk2GOPD64T_js.cn(
9570
+ "flex shrink-0 items-center",
9571
+ vertical ? "flex-col" : "flex-row",
9572
+ pauseOnHover && "group-hover:[animation-play-state:paused]"
9573
+ ),
9574
+ style: {
9575
+ gap,
9576
+ animation: `${animationName} ${speed}s linear infinite`,
9577
+ animationDirection: direction
9578
+ },
9579
+ "aria-hidden": i > 0,
9580
+ children
9581
+ },
9582
+ i
9583
+ ))
9584
+ ]
9585
+ }
9586
+ );
9587
+ }
9588
+ function MouseGradientBlob({
9589
+ size = 500,
9590
+ colors = ["hsl(var(--primary))", "hsl(var(--chart-2))"],
9591
+ opacity = 0.15,
9592
+ blur = 80,
9593
+ className
9594
+ }) {
9595
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9596
+ const mouseX = react.useMotionValue(0);
9597
+ const mouseY = react.useMotionValue(0);
9598
+ const blobX = react.useSpring(mouseX, { stiffness: 150, damping: 20 });
9599
+ const blobY = react.useSpring(mouseY, { stiffness: 150, damping: 20 });
9600
+ const onMouseMove = React5.useCallback(
9601
+ (e) => {
9602
+ const target = e.currentTarget;
9603
+ const rect = target.getBoundingClientRect();
9604
+ mouseX.set(e.clientX - rect.left - size / 2);
9605
+ mouseY.set(e.clientY - rect.top - size / 2);
9606
+ },
9607
+ [mouseX, mouseY, size]
9608
+ );
9609
+ React5.useEffect(() => {
9610
+ const parent = document.querySelector("[data-blob-container]");
9611
+ if (!parent || reduced) return;
9612
+ parent.addEventListener("mousemove", onMouseMove, { passive: true });
9613
+ return () => parent.removeEventListener("mousemove", onMouseMove);
9614
+ }, [onMouseMove, reduced]);
9615
+ if (reduced) return null;
9616
+ return /* @__PURE__ */ jsxRuntime.jsx(
9617
+ "div",
9618
+ {
9619
+ "data-blob-container": true,
9620
+ className: chunk2GOPD64T_js.cn("pointer-events-none absolute inset-0 overflow-hidden", className),
9621
+ "aria-hidden": "true",
9622
+ children: /* @__PURE__ */ jsxRuntime.jsx(
9623
+ react.m.div,
9624
+ {
9625
+ style: {
9626
+ x: blobX,
9627
+ y: blobY,
9628
+ width: size,
9629
+ height: size,
9630
+ background: `radial-gradient(circle, ${colors[0]} 0%, ${colors[1]} 50%, transparent 70%)`,
9631
+ opacity,
9632
+ filter: `blur(${blur}px)`,
9633
+ borderRadius: "50%",
9634
+ position: "absolute",
9635
+ top: 0,
9636
+ left: 0
9637
+ }
9638
+ }
9639
+ )
9640
+ }
9641
+ );
9642
+ }
9643
+ function MovingBorder({
9644
+ children,
9645
+ colors = ["hsl(var(--primary))", "hsl(var(--chart-1))", "hsl(var(--chart-2))"],
9646
+ duration = 6,
9647
+ borderWidth = 1.5,
9648
+ borderRadius = "0.75rem",
9649
+ className
9650
+ }) {
9651
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9652
+ const gradientStops = [...colors, colors[0]].join(", ");
9653
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9654
+ !reduced && /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
9655
+ @keyframes sf-border-rotate {
9656
+ from { --sf-border-angle: 0deg; }
9657
+ to { --sf-border-angle: 360deg; }
9658
+ }
9659
+ @property --sf-border-angle {
9660
+ syntax: "<angle>";
9661
+ initial-value: 0deg;
9662
+ inherits: false;
9663
+ }
9664
+ ` }),
9665
+ /* @__PURE__ */ jsxRuntime.jsx(
9666
+ "div",
9667
+ {
9668
+ className: chunk2GOPD64T_js.cn("relative", className),
9669
+ style: {
9670
+ padding: borderWidth,
9671
+ borderRadius,
9672
+ background: reduced ? `linear-gradient(135deg, ${gradientStops})` : `conic-gradient(from var(--sf-border-angle, 0deg), ${gradientStops})`,
9673
+ ...reduced ? {} : { animation: `sf-border-rotate ${duration}s linear infinite` }
9674
+ },
9675
+ "data-slot": "moving-border",
9676
+ children: /* @__PURE__ */ jsxRuntime.jsx(
9677
+ "div",
9678
+ {
9679
+ className: "relative bg-background",
9680
+ style: { borderRadius: `calc(${borderRadius} - ${borderWidth}px)` },
9681
+ children
9682
+ }
9683
+ )
9684
+ }
9685
+ )
9686
+ ] });
9687
+ }
9688
+ var VARIANTS = {
9689
+ fade: {
9690
+ initial: { opacity: 0 },
9691
+ animate: { opacity: 1 },
9692
+ exit: { opacity: 0 }
9693
+ },
9694
+ slideUp: {
9695
+ initial: { opacity: 0, y: 16 },
9696
+ animate: { opacity: 1, y: 0 },
9697
+ exit: { opacity: 0, y: -16 }
9698
+ },
9699
+ slideDown: {
9700
+ initial: { opacity: 0, y: -16 },
9701
+ animate: { opacity: 1, y: 0 },
9702
+ exit: { opacity: 0, y: 16 }
9703
+ },
9704
+ scale: {
9705
+ initial: { opacity: 0, scale: 0.96 },
9706
+ animate: { opacity: 1, scale: 1 },
9707
+ exit: { opacity: 0, scale: 0.96 }
9708
+ }
9709
+ };
9710
+ function PageTransition({
9711
+ children,
9712
+ variant = "fade",
9713
+ duration = 0.3,
9714
+ transitionKey,
9715
+ className
9716
+ }) {
9717
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9718
+ if (reduced) {
9719
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children });
9720
+ }
9721
+ const preset = VARIANTS[variant];
9722
+ return /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsxRuntime.jsx(
9723
+ react.m.div,
9724
+ {
9725
+ initial: preset.initial,
9726
+ animate: preset.animate,
9727
+ exit: preset.exit,
9728
+ transition: { duration, ease: "easeInOut" },
9729
+ className: chunk2GOPD64T_js.cn("will-change-[opacity,transform]", className),
9730
+ children
9731
+ },
9732
+ transitionKey
9733
+ ) });
9734
+ }
9735
+ function ParallaxSection({
9736
+ children,
9737
+ speed = 0.5,
9738
+ className
9739
+ }) {
9740
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9741
+ const ref = React5.useRef(null);
9742
+ const { scrollYProgress } = react.useScroll({
9743
+ target: ref,
9744
+ offset: ["start end", "end start"]
9745
+ });
9746
+ const offset = (1 - speed) * 100;
9747
+ const y = react.useTransform(scrollYProgress, [0, 1], [`-${offset}px`, `${offset}px`]);
9748
+ if (reduced) {
9749
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children });
9750
+ }
9751
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: chunk2GOPD64T_js.cn("relative overflow-hidden", className), "data-slot": "parallax-section", children: /* @__PURE__ */ jsxRuntime.jsx(react.m.div, { style: { y }, children }) });
9752
+ }
9753
+ function seededRandom(seed) {
9754
+ const x = Math.sin(seed * 9301 + 49297) * 233280;
9755
+ return x - Math.floor(x);
9756
+ }
9757
+ function ParticlesBackground({
9758
+ count = 20,
9759
+ color = "hsl(var(--primary))",
9760
+ maxSize = 4,
9761
+ minSize = 1,
9762
+ maxOpacity = 0.3,
9763
+ speed = 1,
9764
+ className
9765
+ }) {
9766
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9767
+ const particles = React5.useMemo(
9768
+ () => Array.from({ length: count }, (_, i) => {
9769
+ const r = (seed) => seededRandom(i * 100 + seed);
9770
+ const size = minSize + r(1) * (maxSize - minSize);
9771
+ const duration = (15 + r(2) * 25) / speed;
9772
+ const delay = r(3) * -duration;
9773
+ return {
9774
+ id: i,
9775
+ size,
9776
+ x: r(4) * 100,
9777
+ y: r(5) * 100,
9778
+ opacity: 0.05 + r(6) * maxOpacity,
9779
+ duration,
9780
+ delay,
9781
+ driftX: (r(7) - 0.5) * 40,
9782
+ driftY: -20 - r(8) * 40
9783
+ };
9784
+ }),
9785
+ [count, minSize, maxSize, maxOpacity, speed]
9786
+ );
9787
+ if (reduced) return null;
9788
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9789
+ "div",
9790
+ {
9791
+ className: chunk2GOPD64T_js.cn("pointer-events-none absolute inset-0 overflow-hidden", className),
9792
+ "aria-hidden": "true",
9793
+ "data-slot": "particles-background",
9794
+ children: [
9795
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
9796
+ @keyframes sf-particle-drift {
9797
+ 0%, 100% { transform: translate(0, 0); }
9798
+ 50% { transform: translate(var(--drift-x), var(--drift-y)); }
9799
+ }
9800
+ ` }),
9801
+ particles.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
9802
+ "div",
9803
+ {
9804
+ style: {
9805
+ position: "absolute",
9806
+ left: `${p.x}%`,
9807
+ top: `${p.y}%`,
9808
+ width: p.size,
9809
+ height: p.size,
9810
+ backgroundColor: color,
9811
+ borderRadius: "50%",
9812
+ opacity: p.opacity,
9813
+ ["--drift-x"]: `${p.driftX}px`,
9814
+ ["--drift-y"]: `${p.driftY}px`,
9815
+ animation: `sf-particle-drift ${p.duration}s ease-in-out ${p.delay}s infinite`
9816
+ }
9817
+ },
9818
+ p.id
9819
+ ))
9820
+ ]
9821
+ }
9822
+ );
9823
+ }
9824
+ function RetroGrid({
9825
+ gridColor = "hsl(var(--border))",
9826
+ gridSize = 60,
9827
+ angle = 65,
9828
+ opacity = 0.4,
9829
+ className
9830
+ }) {
9831
+ return /* @__PURE__ */ jsxRuntime.jsx(
9832
+ "div",
9833
+ {
9834
+ className: chunk2GOPD64T_js.cn("pointer-events-none absolute inset-0 overflow-hidden", className),
9835
+ "aria-hidden": "true",
9836
+ "data-slot": "retro-grid",
9837
+ children: /* @__PURE__ */ jsxRuntime.jsx(
9838
+ "div",
9839
+ {
9840
+ style: {
9841
+ position: "absolute",
9842
+ inset: 0,
9843
+ backgroundImage: `
9844
+ linear-gradient(to right, ${gridColor} 1px, transparent 1px),
9845
+ linear-gradient(to bottom, ${gridColor} 1px, transparent 1px)
9846
+ `,
9847
+ backgroundSize: `${gridSize}px ${gridSize}px`,
9848
+ opacity,
9849
+ transform: `perspective(500px) rotateX(${angle}deg)`,
9850
+ transformOrigin: "bottom center",
9851
+ maskImage: "linear-gradient(to bottom, transparent 0%, black 30%, black 70%, transparent 100%)",
9852
+ WebkitMaskImage: "linear-gradient(to bottom, transparent 0%, black 30%, black 70%, transparent 100%)"
9853
+ }
9854
+ }
9855
+ )
9856
+ }
9857
+ );
9858
+ }
9859
+ var DIRECTION_OFFSET = {
9860
+ up: { x: 0, y: 24 },
9861
+ down: { x: 0, y: -24 },
9862
+ left: { x: -24, y: 0 },
9863
+ right: { x: 24, y: 0 },
9864
+ none: { x: 0, y: 0 }
9865
+ };
9866
+ function RevealOnScroll({
9867
+ children,
9868
+ direction = "up",
9869
+ delay = 0,
9870
+ rootMargin = "-80px",
9871
+ once = true,
9872
+ className
9873
+ }) {
9874
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9875
+ const ref = React5.useRef(null);
9876
+ const isInView = react.useInView(ref, { once, margin: rootMargin });
9877
+ if (reduced) {
9878
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children });
9879
+ }
9880
+ const offset = DIRECTION_OFFSET[direction];
9881
+ return /* @__PURE__ */ jsxRuntime.jsx(
9882
+ react.m.div,
9883
+ {
9884
+ ref,
9885
+ initial: { opacity: 0, x: offset.x, y: offset.y },
9886
+ animate: isInView ? { opacity: 1, x: 0, y: 0 } : { opacity: 0, x: offset.x, y: offset.y },
9887
+ transition: { ...chunkITALEYDI_js.springGentle, delay },
9888
+ className: chunk2GOPD64T_js.cn("will-change-[opacity,transform]", className),
9889
+ "data-slot": "reveal-on-scroll",
9890
+ children
9891
+ }
9892
+ );
9893
+ }
9894
+ function ShimmerButton({
9895
+ children,
9896
+ shimmerColor = "rgba(255,255,255,0.2)",
9897
+ speed = 2.5,
9898
+ background = "hsl(var(--primary))",
9899
+ className,
9900
+ ...props
9901
+ }) {
9902
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
9903
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9904
+ !reduced && /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
9905
+ @keyframes sf-shimmer-slide {
9906
+ from { transform: translateX(-100%) rotate(-15deg); }
9907
+ to { transform: translateX(200%) rotate(-15deg); }
9908
+ }
9909
+ ` }),
9910
+ /* @__PURE__ */ jsxRuntime.jsxs(
9911
+ "button",
9912
+ {
9913
+ className: chunk2GOPD64T_js.cn(
9914
+ "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",
9915
+ className
9916
+ ),
9917
+ style: { background },
9918
+ "data-slot": "shimmer-button",
9919
+ ...props,
9920
+ children: [
9921
+ !reduced && /* @__PURE__ */ jsxRuntime.jsx(
9922
+ "div",
9923
+ {
9924
+ className: "pointer-events-none absolute inset-0",
9925
+ style: {
9926
+ background: `linear-gradient(
9927
+ -15deg,
9928
+ transparent 30%,
9929
+ ${shimmerColor} 50%,
9930
+ transparent 70%
9931
+ )`,
9932
+ backgroundSize: "200% 100%",
9933
+ animation: `sf-shimmer-slide ${speed}s ease-in-out infinite`
9934
+ },
9935
+ "aria-hidden": "true"
9936
+ }
9937
+ ),
9938
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10", children })
9939
+ ]
9940
+ }
9941
+ )
9942
+ ] });
9943
+ }
9944
+ var PROVIDERS = {
9945
+ google: {
9946
+ label: "Google",
9947
+ bg: "bg-white hover:bg-gray-50 border",
9948
+ fg: "text-gray-700",
9949
+ 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"
9950
+ },
9951
+ apple: {
9952
+ label: "Apple",
9953
+ bg: "bg-black hover:bg-gray-900",
9954
+ fg: "text-white",
9955
+ 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"
9956
+ },
9957
+ github: {
9958
+ label: "GitHub",
9959
+ bg: "bg-[#24292f] hover:bg-[#1b1f23]",
9960
+ fg: "text-white",
9961
+ 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"
9962
+ },
9963
+ microsoft: {
9964
+ label: "Microsoft",
9965
+ bg: "bg-white hover:bg-gray-50 border",
9966
+ fg: "text-gray-700",
9967
+ icon: "M3 3h8v8H3V3zm10 0h8v8h-8V3zM3 13h8v8H3v-8zm10 0h8v8h-8v-8z"
9968
+ },
9969
+ twitter: {
9970
+ label: "X (Twitter)",
9971
+ bg: "bg-black hover:bg-gray-900",
9972
+ fg: "text-white",
9973
+ 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"
9974
+ }
9975
+ };
9976
+ function SocialButton({
9977
+ provider,
9978
+ label: labelOverride,
9979
+ iconOnly = false,
9980
+ className,
9981
+ ...props
9982
+ }) {
9983
+ const config = PROVIDERS[provider];
9984
+ const displayLabel = labelOverride ?? `Continue with ${config.label}`;
9985
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9986
+ "button",
9987
+ {
9988
+ type: "button",
9989
+ className: chunk2GOPD64T_js.cn(
9990
+ "inline-flex items-center justify-center gap-3 rounded-lg px-4 py-2.5 text-sm font-medium transition-colors",
9991
+ config.bg,
9992
+ config.fg,
9993
+ iconOnly && "px-2.5",
9994
+ className
9995
+ ),
9996
+ "aria-label": displayLabel,
9997
+ "data-slot": "social-button",
9998
+ ...props,
9999
+ children: [
10000
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "size-5", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: config.icon }) }),
10001
+ !iconOnly && /* @__PURE__ */ jsxRuntime.jsx("span", { children: displayLabel })
10002
+ ]
10003
+ }
10004
+ );
10005
+ }
10006
+ function SpotlightCard({
10007
+ children,
10008
+ spotlightColor = "hsl(var(--primary))",
10009
+ spotlightSize = 250,
10010
+ spotlightOpacity = 0.08,
10011
+ className,
10012
+ surface,
10013
+ radius,
10014
+ animated
10015
+ }) {
10016
+ const sf = chunk2GOPD64T_js.useSaasflareProps({ surface, radius, animated });
10017
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
10018
+ const cardRef = React5.useRef(null);
10019
+ const position = useMousePosition({ ref: cardRef, enabled: !reduced });
10020
+ const [isHovered, setIsHovered] = React5.useState(false);
10021
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10022
+ react.m.div,
10023
+ {
10024
+ ref: cardRef,
10025
+ onMouseEnter: reduced ? void 0 : () => setIsHovered(true),
10026
+ onMouseLeave: reduced ? void 0 : () => setIsHovered(false),
10027
+ "data-slot": "spotlight-card",
10028
+ "data-surface": sf.surface,
10029
+ "data-radius": sf.radius,
10030
+ className: chunk2GOPD64T_js.cn(
10031
+ "relative overflow-hidden rounded-xl border surface-card p-6 text-card-foreground",
10032
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
10033
+ "motion-reduce:hover:transform-none",
10034
+ className
10035
+ ),
10036
+ children: [
10037
+ !reduced && /* @__PURE__ */ jsxRuntime.jsx(
10038
+ "div",
10039
+ {
10040
+ className: "pointer-events-none absolute inset-0 transition-opacity duration-300",
10041
+ style: {
10042
+ opacity: isHovered ? 1 : 0,
10043
+ background: `radial-gradient(${spotlightSize}px circle at ${position.x}px ${position.y}px, ${spotlightColor} 0%, transparent 70%)`,
10044
+ ...spotlightOpacity < 1 && { opacity: isHovered ? spotlightOpacity : 0 }
10045
+ },
10046
+ "aria-hidden": "true"
10047
+ }
10048
+ ),
10049
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-10", children })
10050
+ ]
10051
+ }
10052
+ );
10053
+ }
10054
+ function StatCard({
10055
+ value,
10056
+ label,
10057
+ icon,
10058
+ className,
10059
+ surface,
10060
+ radius,
10061
+ animated
10062
+ }) {
10063
+ const sf = chunk2GOPD64T_js.useSaasflareProps({ surface, radius, animated });
10064
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10065
+ "div",
10066
+ {
10067
+ "data-slot": "stat-card",
10068
+ "data-surface": sf.surface,
10069
+ "data-radius": sf.radius,
10070
+ className: chunk2GOPD64T_js.cn(
10071
+ "flex flex-col items-center rounded-xl border surface-card p-6 text-center",
10072
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
10073
+ "motion-reduce:hover:transform-none",
10074
+ className
10075
+ ),
10076
+ children: [
10077
+ icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3 text-primary [&_svg]:size-6", children: icon }),
10078
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-3xl font-bold tracking-tight", children: value }),
10079
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: label })
10080
+ ]
10081
+ }
10082
+ );
10083
+ }
10084
+ function Steps({
10085
+ children,
10086
+ current = 0,
10087
+ direction = "horizontal",
10088
+ className
10089
+ }) {
10090
+ const items = React5.Children.toArray(children);
10091
+ return /* @__PURE__ */ jsxRuntime.jsx(
10092
+ "div",
10093
+ {
10094
+ className: chunk2GOPD64T_js.cn(
10095
+ "flex",
10096
+ direction === "horizontal" ? "flex-row items-start" : "flex-col",
10097
+ className
10098
+ ),
10099
+ "data-slot": "steps",
10100
+ role: "list",
10101
+ children: items.map((child, i) => {
10102
+ const status = i < current ? "completed" : i === current ? "active" : "pending";
10103
+ const isLast = i === items.length - 1;
10104
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10105
+ "div",
10106
+ {
10107
+ className: chunk2GOPD64T_js.cn(
10108
+ "flex",
10109
+ direction === "horizontal" ? "flex-1 flex-col items-center" : "flex-row gap-4"
10110
+ ),
10111
+ role: "listitem",
10112
+ "aria-current": status === "active" ? "step" : void 0,
10113
+ children: [
10114
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunk2GOPD64T_js.cn(
10115
+ "flex items-center",
10116
+ direction === "horizontal" ? "w-full" : "flex-col"
10117
+ ), children: [
10118
+ /* @__PURE__ */ jsxRuntime.jsx(
10119
+ "div",
10120
+ {
10121
+ className: chunk2GOPD64T_js.cn(
10122
+ "flex size-9 shrink-0 items-center justify-center rounded-full border-2 text-sm font-semibold transition-colors",
10123
+ status === "completed" && "border-primary bg-primary text-primary-foreground",
10124
+ status === "active" && "border-primary bg-background text-primary",
10125
+ status === "pending" && "border-muted-foreground/30 bg-background text-muted-foreground"
10126
+ ),
10127
+ children: status === "completed" ? /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) }) : child.props.icon ?? i + 1
10128
+ }
10129
+ ),
10130
+ !isLast && /* @__PURE__ */ jsxRuntime.jsx(
10131
+ "div",
10132
+ {
10133
+ className: chunk2GOPD64T_js.cn(
10134
+ direction === "horizontal" ? "h-0.5 flex-1" : "w-0.5 min-h-8 flex-1",
10135
+ status === "completed" ? "bg-primary" : "bg-border"
10136
+ )
10137
+ }
10138
+ )
10139
+ ] }),
10140
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunk2GOPD64T_js.cn(
10141
+ direction === "horizontal" ? "mt-2 text-center" : "pb-8"
10142
+ ), children: [
10143
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: chunk2GOPD64T_js.cn(
10144
+ "text-sm font-medium",
10145
+ status === "pending" && "text-muted-foreground"
10146
+ ), children: child.props.title }),
10147
+ child.props.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: child.props.description })
10148
+ ] })
10149
+ ]
10150
+ },
10151
+ i
10152
+ );
10153
+ })
10154
+ }
10155
+ );
10156
+ }
10157
+ function Step(_props) {
10158
+ return null;
10159
+ }
10160
+ function StickyScrollReveal({
10161
+ items,
10162
+ className
10163
+ }) {
10164
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
10165
+ const containerRef = React5.useRef(null);
10166
+ if (reduced) {
10167
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunk2GOPD64T_js.cn("space-y-16", className), "data-slot": "sticky-scroll-reveal", children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-8 md:grid-cols-2", children: [
10168
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10169
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-2xl font-bold", children: item.title }),
10170
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-muted-foreground", children: item.description })
10171
+ ] }),
10172
+ item.content && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl border bg-muted/50 p-4", children: item.content })
10173
+ ] }, i)) });
10174
+ }
10175
+ return /* @__PURE__ */ jsxRuntime.jsx(
10176
+ "div",
10177
+ {
10178
+ ref: containerRef,
10179
+ className: chunk2GOPD64T_js.cn("relative", className),
10180
+ "data-slot": "sticky-scroll-reveal",
10181
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative grid gap-8 md:grid-cols-2", children: [
10182
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative md:h-fit", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-32 space-y-24", children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(
10183
+ StickyItem,
10184
+ {
10185
+ item,
10186
+ index: i,
10187
+ total: items.length,
10188
+ containerRef
10189
+ },
10190
+ i
10191
+ )) }) }),
10192
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-24", children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-32", children: /* @__PURE__ */ jsxRuntime.jsx(
10193
+ StickyContent,
10194
+ {
10195
+ content: item.content,
10196
+ index: i,
10197
+ total: items.length,
10198
+ containerRef
10199
+ }
10200
+ ) }, i)) })
10201
+ ] })
10202
+ }
10203
+ );
10204
+ }
10205
+ function StickyItem({
10206
+ item,
10207
+ index,
10208
+ total,
10209
+ containerRef
10210
+ }) {
10211
+ const { scrollYProgress } = react.useScroll({
10212
+ target: containerRef,
10213
+ offset: ["start start", "end end"]
10214
+ });
10215
+ const sectionStart = index / total;
10216
+ const sectionEnd = (index + 1) / total;
10217
+ const opacity = react.useTransform(
10218
+ scrollYProgress,
10219
+ [sectionStart, sectionStart + 0.05, sectionEnd - 0.05, sectionEnd],
10220
+ [0.3, 1, 1, 0.3]
10221
+ );
10222
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.m.div, { style: { opacity }, children: [
10223
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-2xl font-bold", children: item.title }),
10224
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-muted-foreground", children: item.description })
10225
+ ] });
10226
+ }
10227
+ function StickyContent({
10228
+ content,
10229
+ index,
10230
+ total,
10231
+ containerRef
10232
+ }) {
10233
+ const { scrollYProgress } = react.useScroll({
10234
+ target: containerRef,
10235
+ offset: ["start start", "end end"]
10236
+ });
10237
+ const sectionStart = index / total;
10238
+ const sectionEnd = (index + 1) / total;
10239
+ const opacity = react.useTransform(
10240
+ scrollYProgress,
10241
+ [sectionStart, sectionStart + 0.05, sectionEnd - 0.05, sectionEnd],
10242
+ [0, 1, 1, 0]
10243
+ );
10244
+ if (!content) return null;
10245
+ return /* @__PURE__ */ jsxRuntime.jsx(
10246
+ react.m.div,
10247
+ {
10248
+ style: { opacity },
10249
+ className: "overflow-hidden rounded-xl border bg-muted/50 p-4",
10250
+ children: content
10251
+ }
10252
+ );
10253
+ }
10254
+ function TeamCard({
10255
+ name,
10256
+ role,
10257
+ photo,
10258
+ bio,
10259
+ socials,
10260
+ className,
10261
+ surface,
10262
+ radius,
10263
+ animated
10264
+ }) {
10265
+ const sf = chunk2GOPD64T_js.useSaasflareProps({ surface, radius, animated });
10266
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10267
+ "div",
10268
+ {
10269
+ "data-slot": "team-card",
10270
+ "data-surface": sf.surface,
10271
+ "data-radius": sf.radius,
10272
+ className: chunk2GOPD64T_js.cn(
10273
+ "flex flex-col items-center rounded-xl border surface-card p-6 text-center",
10274
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
10275
+ "motion-reduce:hover:transform-none",
10276
+ className
10277
+ ),
10278
+ children: [
10279
+ photo && /* @__PURE__ */ jsxRuntime.jsx(
10280
+ "img",
10281
+ {
10282
+ src: photo,
10283
+ alt: name,
10284
+ className: "mb-4 size-24 rounded-full object-cover"
10285
+ }
10286
+ ),
10287
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-semibold", children: name }),
10288
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: role }),
10289
+ bio && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: bio }),
10290
+ socials && socials.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 flex gap-2", children: socials.map((s) => /* @__PURE__ */ jsxRuntime.jsx(
10291
+ "a",
10292
+ {
10293
+ href: s.url,
10294
+ target: "_blank",
10295
+ rel: "noopener noreferrer",
10296
+ className: "rounded-md p-2 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
10297
+ "aria-label": s.label,
10298
+ children: s.icon
10299
+ },
10300
+ s.label
10301
+ )) })
10302
+ ]
10303
+ }
10304
+ );
10305
+ }
10306
+ function TestimonialCard({
10307
+ quote,
10308
+ name,
10309
+ role,
10310
+ avatar,
10311
+ rating,
10312
+ className,
10313
+ surface,
10314
+ radius,
10315
+ animated
10316
+ }) {
10317
+ const sf = chunk2GOPD64T_js.useSaasflareProps({ surface, radius, animated });
10318
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10319
+ "div",
10320
+ {
10321
+ "data-slot": "testimonial-card",
10322
+ "data-surface": sf.surface,
10323
+ "data-radius": sf.radius,
10324
+ className: chunk2GOPD64T_js.cn(
10325
+ "flex flex-col rounded-xl border surface-card p-6",
10326
+ "transition-all duration-200 hover:-translate-y-px hover:shadow-md",
10327
+ "motion-reduce:hover:transform-none",
10328
+ className
10329
+ ),
10330
+ children: [
10331
+ rating && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3 flex gap-0.5", "aria-label": `${rating} out of 5 stars`, children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx(
10332
+ "svg",
10333
+ {
10334
+ className: chunk2GOPD64T_js.cn("size-4", i < rating ? "text-warning" : "text-muted-foreground/20"),
10335
+ viewBox: "0 0 20 20",
10336
+ fill: "currentColor",
10337
+ "aria-hidden": "true",
10338
+ children: /* @__PURE__ */ jsxRuntime.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" })
10339
+ },
10340
+ i
10341
+ )) }),
10342
+ /* @__PURE__ */ jsxRuntime.jsxs("blockquote", { className: "flex-1 text-sm leading-relaxed text-foreground", children: [
10343
+ "\u201C",
10344
+ quote,
10345
+ "\u201D"
10346
+ ] }),
10347
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex items-center gap-3", children: [
10348
+ avatar && /* @__PURE__ */ jsxRuntime.jsx(
10349
+ "img",
10350
+ {
10351
+ src: avatar,
10352
+ alt: name,
10353
+ className: "size-10 rounded-full object-cover"
10354
+ }
10355
+ ),
10356
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10357
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold", children: name }),
10358
+ role && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: role })
10359
+ ] })
10360
+ ] })
10361
+ ]
10362
+ }
10363
+ );
10364
+ }
10365
+ function TextGenerateEffect({
10366
+ text,
10367
+ stagger = 0.05,
10368
+ duration = 0.4,
10369
+ once = true,
10370
+ as: Tag = "p",
10371
+ className
10372
+ }) {
10373
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
10374
+ const ref = React5.useRef(null);
10375
+ const isInView = react.useInView(ref, { once, margin: "-50px" });
10376
+ const words = React5.useMemo(() => text.split(/\s+/), [text]);
10377
+ if (reduced) {
10378
+ return /* @__PURE__ */ jsxRuntime.jsx(Tag, { className, children: text });
10379
+ }
10380
+ return /* @__PURE__ */ jsxRuntime.jsx(
10381
+ Tag,
10382
+ {
10383
+ ref,
10384
+ className: chunk2GOPD64T_js.cn("inline", className),
10385
+ "data-slot": "text-generate-effect",
10386
+ children: words.map((word, i) => /* @__PURE__ */ jsxRuntime.jsxs(
10387
+ react.m.span,
10388
+ {
10389
+ initial: { opacity: 0, filter: "blur(4px)" },
10390
+ animate: isInView ? { opacity: 1, filter: "blur(0px)" } : { opacity: 0, filter: "blur(4px)" },
10391
+ transition: { duration, delay: i * stagger },
10392
+ className: "inline-block",
10393
+ children: [
10394
+ word,
10395
+ i < words.length - 1 && "\xA0"
10396
+ ]
10397
+ },
10398
+ `${word}-${i}`
10399
+ ))
10400
+ }
10401
+ );
10402
+ }
10403
+ function Timeline({ children, className }) {
10404
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
10405
+ const containerRef = React5.useRef(null);
10406
+ const { scrollYProgress } = react.useScroll({
10407
+ target: containerRef,
10408
+ offset: ["start 80%", "end 50%"]
10409
+ });
10410
+ const beamHeight = react.useTransform(scrollYProgress, [0, 1], ["0%", "100%"]);
10411
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10412
+ "div",
10413
+ {
10414
+ ref: containerRef,
10415
+ className: chunk2GOPD64T_js.cn("relative", className),
10416
+ "data-slot": "timeline",
10417
+ children: [
10418
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-4 top-0 h-full w-0.5 bg-border md:left-1/2 md:-translate-x-px" }),
10419
+ !reduced && /* @__PURE__ */ jsxRuntime.jsx(
10420
+ react.m.div,
10421
+ {
10422
+ className: "absolute left-4 top-0 w-0.5 bg-primary md:left-1/2 md:-translate-x-px",
10423
+ style: { height: beamHeight }
10424
+ }
10425
+ ),
10426
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative space-y-12", children })
10427
+ ]
10428
+ }
10429
+ );
10430
+ }
10431
+ function TimelineItem({
10432
+ title,
10433
+ date,
10434
+ children,
10435
+ className
10436
+ }) {
10437
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
10438
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10439
+ react.m.div,
10440
+ {
10441
+ initial: reduced ? false : { opacity: 0, y: 16 },
10442
+ whileInView: { opacity: 1, y: 0 },
10443
+ viewport: { once: true, margin: "-80px" },
10444
+ transition: reduced ? { duration: 0 } : { duration: 0.5, ease: "easeOut" },
10445
+ className: chunk2GOPD64T_js.cn("relative pl-12 md:pl-0", className),
10446
+ "data-slot": "timeline-item",
10447
+ children: [
10448
+ /* @__PURE__ */ jsxRuntime.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" }),
10449
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:ml-[calc(50%+2rem)] md:max-w-[calc(50%-3rem)]", children: [
10450
+ date && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block text-sm text-muted-foreground", children: date }),
10451
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold", children: title }),
10452
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-muted-foreground", children })
10453
+ ] })
10454
+ ]
10455
+ }
10456
+ );
10457
+ }
10458
+ function TracingBeam({
10459
+ children,
10460
+ color = "hsl(var(--primary))",
10461
+ trackColor = "hsl(var(--border))",
10462
+ className
10463
+ }) {
10464
+ const reduced = chunk2GOPD64T_js.useReducedMotion();
10465
+ const containerRef = React5.useRef(null);
10466
+ const { scrollYProgress } = react.useScroll({
10467
+ target: containerRef,
10468
+ offset: ["start 20%", "end 80%"]
10469
+ });
10470
+ const beamHeight = react.useTransform(scrollYProgress, [0, 1], ["0%", "100%"]);
10471
+ const dotY = react.useTransform(scrollYProgress, [0, 1], ["0%", "100%"]);
10472
+ if (reduced) {
10473
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunk2GOPD64T_js.cn("border-l-2 border-primary/30 pl-8", className), children });
10474
+ }
10475
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10476
+ "div",
10477
+ {
10478
+ ref: containerRef,
10479
+ className: chunk2GOPD64T_js.cn("relative pl-10", className),
10480
+ "data-slot": "tracing-beam",
10481
+ children: [
10482
+ /* @__PURE__ */ jsxRuntime.jsx(
10483
+ "div",
10484
+ {
10485
+ className: "absolute left-3 top-0 h-full w-px",
10486
+ style: { backgroundColor: trackColor }
10487
+ }
10488
+ ),
10489
+ /* @__PURE__ */ jsxRuntime.jsx(
10490
+ react.m.div,
10491
+ {
10492
+ className: "absolute left-3 top-0 w-px",
10493
+ style: { height: beamHeight, backgroundColor: color }
10494
+ }
10495
+ ),
10496
+ /* @__PURE__ */ jsxRuntime.jsx(
10497
+ react.m.div,
10498
+ {
10499
+ className: "absolute left-[9px] size-1.5 rounded-full",
10500
+ style: {
10501
+ top: dotY,
10502
+ backgroundColor: color,
10503
+ boxShadow: `0 0 8px ${color}`
10504
+ }
10505
+ }
10506
+ ),
10507
+ children
10508
+ ]
10509
+ }
10510
+ );
10511
+ }
8381
10512
 
8382
10513
  // src/types/theme-props.ts
8383
10514
  var PALETTES = [
@@ -8491,7 +10622,7 @@ function StatefulButton({
8491
10622
  }
8492
10623
  );
8493
10624
  }
8494
- var PROVIDERS = [
10625
+ var PROVIDERS2 = [
8495
10626
  "google",
8496
10627
  "github",
8497
10628
  "apple",
@@ -9226,6 +11357,7 @@ exports.AlertTitle = AlertTitle;
9226
11357
  exports.AnimatedTooltip = AnimatedTooltip;
9227
11358
  exports.AppleAuthButton = AppleAuthButton;
9228
11359
  exports.AspectRatio = AspectRatio;
11360
+ exports.AudioPlayer = AudioPlayer;
9229
11361
  exports.AuroraBackground = AuroraBackground;
9230
11362
  exports.Avatar = Avatar;
9231
11363
  exports.AvatarBadge = AvatarBadge;
@@ -9235,6 +11367,10 @@ exports.AvatarGroupCount = AvatarGroupCount;
9235
11367
  exports.AvatarImage = AvatarImage;
9236
11368
  exports.Badge = Badge;
9237
11369
  exports.BarList = BarList;
11370
+ exports.BentoGrid = BentoGrid;
11371
+ exports.BentoGridItem = BentoGridItem;
11372
+ exports.BlurFade = BlurFade;
11373
+ exports.BorderBeam = BorderBeam;
9238
11374
  exports.Breadcrumb = Breadcrumb;
9239
11375
  exports.BreadcrumbEllipsis = BreadcrumbEllipsis;
9240
11376
  exports.BreadcrumbItem = BreadcrumbItem;
@@ -9268,6 +11404,8 @@ exports.ComboboxItem = ComboboxItem;
9268
11404
  exports.ComboboxList = ComboboxList;
9269
11405
  exports.ComboboxSeparator = ComboboxSeparator;
9270
11406
  exports.ComboboxTrigger = ComboboxTrigger;
11407
+ exports.Compare = Compare;
11408
+ exports.Confetti = Confetti;
9271
11409
  exports.ContextMenu = ContextMenu;
9272
11410
  exports.ContextMenuCheckboxItem = ContextMenuCheckboxItem;
9273
11411
  exports.ContextMenuContent = ContextMenuContent;
@@ -9283,6 +11421,7 @@ exports.ContextMenuSub = ContextMenuSub;
9283
11421
  exports.ContextMenuSubContent = ContextMenuSubContent;
9284
11422
  exports.ContextMenuSubTrigger = ContextMenuSubTrigger;
9285
11423
  exports.ContextMenuTrigger = ContextMenuTrigger;
11424
+ exports.Countdown = Countdown;
9286
11425
  exports.DataToolbar = DataToolbar;
9287
11426
  exports.DataToolbarActions = DataToolbarActions;
9288
11427
  exports.DataToolbarFilters = DataToolbarFilters;
@@ -9291,6 +11430,8 @@ exports.DatePicker = DatePicker;
9291
11430
  exports.DateRangePicker = DateRangePicker;
9292
11431
  exports.DirectionProvider = DirectionProvider2;
9293
11432
  exports.DiscordAuthButton = DiscordAuthButton;
11433
+ exports.Dock = Dock;
11434
+ exports.DockItem = DockItem;
9294
11435
  exports.DribbbleAuthButton = DribbbleAuthButton;
9295
11436
  exports.DropdownMenu = DropdownMenu;
9296
11437
  exports.DropdownMenuCheckboxItem = DropdownMenuCheckboxItem;
@@ -9316,6 +11457,7 @@ exports.EmptyMedia = EmptyMedia;
9316
11457
  exports.EmptyState = EmptyState;
9317
11458
  exports.EmptyTitle = EmptyTitle;
9318
11459
  exports.FacebookAuthButton = FacebookAuthButton;
11460
+ exports.FeatureCard = FeatureCard;
9319
11461
  exports.Field = Field;
9320
11462
  exports.FieldContent = FieldContent;
9321
11463
  exports.FieldDescription = FieldDescription;
@@ -9326,6 +11468,7 @@ exports.FieldLegend = FieldLegend;
9326
11468
  exports.FieldSeparator = FieldSeparator;
9327
11469
  exports.FieldSet = FieldSet;
9328
11470
  exports.FieldTitle = FieldTitle;
11471
+ exports.FlipWords = FlipWords;
9329
11472
  exports.Form = Form;
9330
11473
  exports.FormControl = FormControl;
9331
11474
  exports.FormDescription = FormDescription;
@@ -9333,13 +11476,21 @@ exports.FormField = FormField;
9333
11476
  exports.FormItem = FormItem;
9334
11477
  exports.FormLabel = FormLabel;
9335
11478
  exports.FormMessage = FormMessage;
11479
+ exports.GalleryLightbox = GalleryLightbox;
9336
11480
  exports.GitHubAuthButton = GitHubAuthButton;
9337
11481
  exports.GitLabAuthButton = GitLabAuthButton;
11482
+ exports.GlowingEffect = GlowingEffect;
9338
11483
  exports.GoogleAuthButton = GoogleAuthButton;
11484
+ exports.GradientText = GradientText;
11485
+ exports.HeroVideoDialog = HeroVideoDialog;
11486
+ exports.Hotspot = Hotspot;
11487
+ exports.HotspotMarker = HotspotMarker;
9339
11488
  exports.HoverCard = HoverCard;
9340
11489
  exports.HoverCardContent = HoverCardContent;
9341
11490
  exports.HoverCardTrigger = HoverCardTrigger;
11491
+ exports.IPhoneMock = IPhoneMock;
9342
11492
  exports.Icons = Icons;
11493
+ exports.ImageSwapHover = ImageSwapHover;
9343
11494
  exports.Input = Input;
9344
11495
  exports.InputGroup = InputGroup;
9345
11496
  exports.InputGroupAddon = InputGroupAddon;
@@ -9361,6 +11512,7 @@ exports.Kbd = Kbd;
9361
11512
  exports.KbdGroup = KbdGroup;
9362
11513
  exports.Label = Label5;
9363
11514
  exports.LinkedInAuthButton = LinkedInAuthButton;
11515
+ exports.Marquee = Marquee;
9364
11516
  exports.MediumAuthButton = MediumAuthButton;
9365
11517
  exports.Menubar = Menubar;
9366
11518
  exports.MenubarCheckboxItem = MenubarCheckboxItem;
@@ -9380,6 +11532,8 @@ exports.MenubarSubTrigger = MenubarSubTrigger;
9380
11532
  exports.MenubarTrigger = MenubarTrigger;
9381
11533
  exports.MetricCard = MetricCard;
9382
11534
  exports.MicrosoftAuthButton = MicrosoftAuthButton;
11535
+ exports.MouseGradientBlob = MouseGradientBlob;
11536
+ exports.MovingBorder = MovingBorder;
9383
11537
  exports.NativeSelect = NativeSelect;
9384
11538
  exports.NativeSelectOptGroup = NativeSelectOptGroup;
9385
11539
  exports.NativeSelectOption = NativeSelectOption;
@@ -9395,6 +11549,7 @@ exports.NotificationCenter = NotificationCenter;
9395
11549
  exports.NumberInput = NumberInput;
9396
11550
  exports.PALETTES = PALETTES;
9397
11551
  exports.PageHeader = PageHeader;
11552
+ exports.PageTransition = PageTransition;
9398
11553
  exports.Pagination = Pagination;
9399
11554
  exports.PaginationContent = PaginationContent;
9400
11555
  exports.PaginationEllipsis = PaginationEllipsis;
@@ -9402,6 +11557,8 @@ exports.PaginationItem = PaginationItem;
9402
11557
  exports.PaginationLink = PaginationLink;
9403
11558
  exports.PaginationNext = PaginationNext;
9404
11559
  exports.PaginationPrevious = PaginationPrevious;
11560
+ exports.ParallaxSection = ParallaxSection;
11561
+ exports.ParticlesBackground = ParticlesBackground;
9405
11562
  exports.PayPalAuthButton = PayPalAuthButton;
9406
11563
  exports.Popover = Popover;
9407
11564
  exports.PopoverAnchor = PopoverAnchor;
@@ -9415,8 +11572,11 @@ exports.RadioGroup = RadioGroup4;
9415
11572
  exports.RadioGroupItem = RadioGroupItem;
9416
11573
  exports.Rating = Rating;
9417
11574
  exports.RedditAuthButton = RedditAuthButton;
9418
- exports.SOCIAL_AUTH_PROVIDERS = PROVIDERS;
11575
+ exports.RetroGrid = RetroGrid;
11576
+ exports.RevealOnScroll = RevealOnScroll;
11577
+ exports.SOCIAL_AUTH_PROVIDERS = PROVIDERS2;
9419
11578
  exports.STYLES = STYLES;
11579
+ exports.SafariMock = SafariMock;
9420
11580
  exports.ScrollArea = ScrollArea;
9421
11581
  exports.ScrollBar = ScrollBar;
9422
11582
  exports.ScrollToTopButton = ScrollToTopButton;
@@ -9442,6 +11602,7 @@ exports.SheetFooter = SheetFooter;
9442
11602
  exports.SheetHeader = SheetHeader;
9443
11603
  exports.SheetTitle = SheetTitle;
9444
11604
  exports.SheetTrigger = SheetTrigger;
11605
+ exports.ShimmerButton = ShimmerButton;
9445
11606
  exports.Sidebar = Sidebar;
9446
11607
  exports.SidebarContent = SidebarContent;
9447
11608
  exports.SidebarFooter = SidebarFooter;
@@ -9469,9 +11630,15 @@ exports.Skeleton = Skeleton;
9469
11630
  exports.SlackAuthButton = SlackAuthButton;
9470
11631
  exports.Slider = Slider;
9471
11632
  exports.SocialAuthButton = SocialAuthButton;
11633
+ exports.SocialButton = SocialButton;
9472
11634
  exports.SparkChart = SparkChart;
9473
11635
  exports.Spinner = Spinner;
11636
+ exports.SpotlightCard = SpotlightCard;
11637
+ exports.StatCard = StatCard;
9474
11638
  exports.StatefulButton = StatefulButton;
11639
+ exports.Step = Step;
11640
+ exports.Steps = Steps;
11641
+ exports.StickyScrollReveal = StickyScrollReveal;
9475
11642
  exports.StripeAuthButton = StripeAuthButton;
9476
11643
  exports.Switch = Switch;
9477
11644
  exports.Table = Table;
@@ -9487,10 +11654,15 @@ exports.TabsContent = TabsContent;
9487
11654
  exports.TabsList = TabsList;
9488
11655
  exports.TabsTrigger = TabsTrigger;
9489
11656
  exports.TagInput = TagInput;
11657
+ exports.TeamCard = TeamCard;
11658
+ exports.TestimonialCard = TestimonialCard;
11659
+ exports.TextGenerateEffect = TextGenerateEffect;
9490
11660
  exports.Textarea = Textarea;
9491
11661
  exports.ThemeModeMultiToggle = ThemeModeMultiToggle;
9492
11662
  exports.ThemeModeToggle = ThemeModeToggle;
9493
11663
  exports.TikTokAuthButton = TikTokAuthButton;
11664
+ exports.Timeline = Timeline;
11665
+ exports.TimelineItem = TimelineItem;
9494
11666
  exports.Toaster = Toaster3;
9495
11667
  exports.Toggle = Toggle;
9496
11668
  exports.ToggleGroup = ToggleGroup;
@@ -9500,6 +11672,7 @@ exports.TooltipContent = TooltipContent;
9500
11672
  exports.TooltipProvider = TooltipProvider;
9501
11673
  exports.TooltipTrigger = TooltipTrigger;
9502
11674
  exports.TopLoadingBar = TopLoadingBar;
11675
+ exports.TracingBeam = TracingBeam;
9503
11676
  exports.Tracker = Tracker;
9504
11677
  exports.TreeView = TreeView;
9505
11678
  exports.TypewriterText = TypewriterText;
@@ -9509,6 +11682,7 @@ exports.badgeVariants = badgeVariants;
9509
11682
  exports.buttonGroupVariants = buttonGroupVariants;
9510
11683
  exports.navigationMenuTriggerStyle = navigationMenuTriggerStyle;
9511
11684
  exports.toggleVariants = toggleVariants;
11685
+ exports.useCountdown = useCountdown;
9512
11686
  exports.useDirection = useDirection2;
9513
11687
  exports.useDisclosure = useDisclosure;
9514
11688
  exports.useFileDialog = useFileDialog;