"use client";
import * as React from "react";
import { motion, useInView, useReducedMotion } from "motion/react";
import { ArrowRight, Check } from "lucide-react";
import { cn } from "@/lib/utils";
export interface CtaGradientBorderProps {
eyebrow?: string;
headline?: string;
description?: string;
primaryCta?: { label: string; href?: string };
secondaryCta?: { label: string; href?: string };
/** Small reassurance points under the buttons. */
reassurance?: string[];
/** Seconds for one full rotation of the border. */
duration?: number;
className?: string;
}
const EASE = [0.22, 1, 0.36, 1] as const;
export function CtaGradientBorder({
eyebrow = "Ready when you are",
headline = "Start building your next launch today",
description = "Join 18,000 teams shipping faster with Acme. Set up in minutes, invite your team, and see results before your first coffee gets cold.",
primaryCta = { label: "Start for free", href: "#" },
secondaryCta = { label: "Talk to sales", href: "#" },
reassurance = ["No credit card required", "14-day Pro trial", "Cancel anytime"],
duration = 6,
className,
}: CtaGradientBorderProps) {
const reduce = useReducedMotion();
const ref = React.useRef<HTMLDivElement>(null);
const inView = useInView(ref, { once: true, amount: 0.3 });
const conic =
"conic-gradient(from 0deg, transparent 0deg, #8b5cf6 60deg, #ec4899 110deg, #f59e0b 150deg, transparent 200deg, transparent 360deg)";
return (
<section className={cn("relative w-full overflow-hidden bg-background px-5 py-16 text-foreground sm:px-8 sm:py-20", className)}>
<div aria-hidden className="pointer-events-none absolute inset-0 bg-[radial-gradient(var(--color-border)_1px,transparent_1px)] bg-[size:20px_20px] [mask-image:radial-gradient(ellipse_60%_60%_at_50%_50%,#000,transparent)]" />
<motion.div
ref={ref}
initial={reduce ? { opacity: 0 } : { opacity: 0, y: 30, scale: 0.97 }}
animate={inView ? { opacity: 1, y: 0, scale: 1 } : undefined}
transition={{ duration: 0.8, ease: EASE }}
className="relative mx-auto max-w-4xl"
>
{/* Soft glow that follows the border */}
<div aria-hidden className="absolute -inset-px overflow-hidden rounded-[28px] opacity-60 blur-2xl">
<motion.div
className="absolute inset-[-100%]"
style={{ background: conic }}
animate={reduce ? undefined : { rotate: 360 }}
transition={{ duration, repeat: Infinity, ease: "linear" }}
/>
</div>
{/* Border ring */}
<div className="relative overflow-hidden rounded-[28px] p-px">
<div aria-hidden className="absolute inset-0 bg-border" />
<motion.div
aria-hidden
className="absolute inset-[-100%]"
style={{ background: conic }}
animate={reduce ? undefined : { rotate: 360 }}
transition={{ duration, repeat: Infinity, ease: "linear" }}
/>
<div className="relative overflow-hidden rounded-[27px] bg-card px-6 py-14 text-center sm:px-14 sm:py-16">
<div aria-hidden className="pointer-events-none absolute -top-24 left-1/2 h-48 w-[80%] -translate-x-1/2 rounded-full bg-fuchsia-500/10 blur-3xl dark:bg-fuchsia-500/15" />
<p className="relative inline-flex items-center gap-2 rounded-full border bg-background/60 px-3 py-1 text-xs font-medium text-muted-foreground">
<span className="size-1.5 rounded-full bg-linear-to-r from-violet-500 to-pink-500" />
{eyebrow}
</p>
<h2 className="relative mx-auto mt-6 max-w-2xl text-balance text-3xl font-semibold tracking-tight sm:text-5xl">{headline}</h2>
<p className="relative mx-auto mt-5 max-w-xl text-pretty leading-relaxed text-muted-foreground">{description}</p>
<div className="relative mt-9 flex flex-col items-center justify-center gap-3 sm:flex-row">
<a
href={primaryCta.href ?? "#"}
className="group relative inline-flex h-12 w-full items-center justify-center gap-2 overflow-hidden rounded-full bg-foreground px-7 text-sm font-semibold text-background shadow-lg transition hover:opacity-95 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card sm:w-auto"
>
<span aria-hidden className="absolute inset-y-0 -left-1/2 w-1/2 -skew-x-12 bg-linear-to-r from-transparent via-white/25 to-transparent transition-transform duration-700 group-hover:translate-x-[300%] dark:via-black/15" />
{primaryCta.label}
<ArrowRight className="size-4 transition-transform group-hover:translate-x-0.5" aria-hidden />
</a>
<a
href={secondaryCta.href ?? "#"}
className="inline-flex h-12 w-full items-center justify-center rounded-full border bg-background px-7 text-sm font-semibold transition hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring sm:w-auto"
>
{secondaryCta.label}
</a>
</div>
{reassurance.length > 0 && (
<ul className="relative mt-7 flex flex-wrap items-center justify-center gap-x-5 gap-y-2 text-xs text-muted-foreground sm:text-sm">
{reassurance.map((r) => (
<li key={r} className="flex items-center gap-1.5">
<Check className="size-3.5 text-emerald-600 dark:text-emerald-400" aria-hidden />
{r}
</li>
))}
</ul>
)}
</div>
</div>
</motion.div>
</section>
);
}