aboutsummaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/buzz-marquee.tsx21
-rw-r--r--components/cta-band.tsx34
-rw-r--r--components/dashboard-mock.tsx133
-rw-r--r--components/faq-list.tsx26
-rw-r--r--components/glow-orbs.tsx14
-rw-r--r--components/logo.tsx61
-rw-r--r--components/request-form.tsx145
-rw-r--r--components/section.tsx40
-rw-r--r--components/site-footer.tsx95
-rw-r--r--components/site-header.tsx130
-rw-r--r--components/solutions-tabs.tsx53
-rw-r--r--components/ui/accordion.tsx74
-rw-r--r--components/ui/badge.tsx52
-rw-r--r--components/ui/button.tsx59
-rw-r--r--components/ui/card.tsx103
-rw-r--r--components/ui/dialog.tsx160
-rw-r--r--components/ui/input.tsx20
-rw-r--r--components/ui/label.tsx20
-rw-r--r--components/ui/navigation-menu.tsx168
-rw-r--r--components/ui/separator.tsx25
-rw-r--r--components/ui/sheet.tsx138
-rw-r--r--components/ui/tabs.tsx82
-rw-r--r--components/ui/textarea.tsx18
23 files changed, 1671 insertions, 0 deletions
diff --git a/components/buzz-marquee.tsx b/components/buzz-marquee.tsx
new file mode 100644
index 0000000..6d9b33c
--- /dev/null
+++ b/components/buzz-marquee.tsx
@@ -0,0 +1,21 @@
+import { allTerms } from "@/lib/buzz";
+
+export function BuzzMarquee() {
+ const loop = [...allTerms, ...allTerms];
+ return (
+ <div className="relative overflow-hidden border-y border-white/10 bg-violet-500/5 py-3">
+ <div className="pointer-events-none absolute inset-y-0 left-0 z-10 w-16 bg-gradient-to-r from-background to-transparent" />
+ <div className="pointer-events-none absolute inset-y-0 right-0 z-10 w-16 bg-gradient-to-l from-background to-transparent" />
+ <div className="marquee-track flex w-max gap-8">
+ {loop.map((term, i) => (
+ <span
+ key={`${term}-${i}`}
+ className="font-mono text-[11px] uppercase tracking-[0.16em] whitespace-nowrap text-violet-200/70"
+ >
+ {term}
+ </span>
+ ))}
+ </div>
+ </div>
+ );
+}
diff --git a/components/cta-band.tsx b/components/cta-band.tsx
new file mode 100644
index 0000000..cf00d62
--- /dev/null
+++ b/components/cta-band.tsx
@@ -0,0 +1,34 @@
+import Link from "next/link";
+import { buttonVariants } from "@/components/ui/button";
+import { cn } from "@/lib/utils";
+
+export function CtaBand({
+ title = "Request access to The Agentic Cloud.",
+ body = "Invitation-based. An outcomes partner will assess whether your operating thesis, your lake, and our attention-free runtime are prepared to compound.",
+}: {
+ title?: string;
+ body?: string;
+}) {
+ return (
+ <section className="border-t border-white/10 px-5 py-20 sm:px-8 md:py-24">
+ <div className="relative mx-auto flex max-w-6xl flex-col items-start justify-between gap-8 overflow-hidden rounded-3xl border border-white/10 bg-gradient-to-br from-violet-600/25 via-fuchsia-600/15 to-cyan-500/15 px-6 py-10 shadow-[0_0_80px_oklch(0.6_0.2_305/0.25)] sm:px-10 md:flex-row md:items-center">
+ <div className="pointer-events-none absolute -right-10 -top-16 size-56 rounded-full bg-fuchsia-500/30 blur-3xl" />
+ <div className="pointer-events-none absolute -bottom-16 -left-10 size-56 rounded-full bg-cyan-400/20 blur-3xl" />
+ <div className="relative max-w-xl">
+ <h2 className="font-heading text-3xl leading-tight text-foreground md:text-4xl">
+ {title}
+ </h2>
+ <p className="mt-3 text-sm leading-relaxed text-muted-foreground md:text-base">
+ {body}
+ </p>
+ </div>
+ <Link
+ href="/request-access"
+ className={cn(buttonVariants(), "relative h-11 shrink-0 px-5 text-sm")}
+ >
+ Request access
+ </Link>
+ </div>
+ </section>
+ );
+}
diff --git a/components/dashboard-mock.tsx b/components/dashboard-mock.tsx
new file mode 100644
index 0000000..e4407d4
--- /dev/null
+++ b/components/dashboard-mock.tsx
@@ -0,0 +1,133 @@
+export function DashboardMock() {
+ return (
+ <div className="relative overflow-hidden rounded-3xl border border-white/10 bg-black/30 shadow-[0_0_80px_oklch(0.55_0.22_305/0.35)] backdrop-blur-xl">
+ <div className="pointer-events-none absolute inset-0 bg-gradient-to-br from-violet-500/15 via-transparent to-cyan-400/10" />
+ <div className="relative flex items-center justify-between border-b border-white/10 px-4 py-3">
+ <div className="flex items-center gap-2">
+ <span className="size-2.5 rounded-full bg-fuchsia-400 shadow-[0_0_10px_#e879f9]" />
+ <span className="size-2.5 rounded-full bg-white/20" />
+ <span className="size-2.5 rounded-full bg-white/20" />
+ </div>
+ <p className="font-mono text-[10px] uppercase tracking-[0.18em] text-violet-200/80">
+ Agentic operating surface
+ </p>
+ <span className="hidden font-mono text-[10px] text-cyan-300 sm:inline">
+ PPoE 94.2
+ </span>
+ </div>
+ <div className="relative grid md:grid-cols-[188px_1fr_200px]">
+ <aside className="hidden border-r border-white/10 p-4 md:block">
+ {[
+ "Agents",
+ "Data fabric",
+ "Mesh",
+ "Quantum",
+ "Zero trust",
+ "Bio-sync",
+ "Carbon",
+ ].map((item, i) => (
+ <div
+ key={item}
+ className={`mb-1 rounded-lg px-2.5 py-1.5 text-xs ${
+ i === 0
+ ? "bg-gradient-to-r from-violet-500/30 to-fuchsia-500/20 text-violet-100"
+ : "text-violet-100/50"
+ }`}
+ >
+ {item}
+ </div>
+ ))}
+ </aside>
+ <div className="relative min-h-[280px] p-4 sm:min-h-[340px]">
+ <svg viewBox="0 0 520 320" className="h-full w-full" aria-hidden>
+ <defs>
+ <linearGradient id="line" x1="0" y1="0" x2="1" y2="1">
+ <stop offset="0%" stopColor="#c084fc" stopOpacity="0.2" />
+ <stop offset="50%" stopColor="#e879f9" stopOpacity="0.7" />
+ <stop offset="100%" stopColor="#67e8f9" stopOpacity="0.8" />
+ </linearGradient>
+ <filter id="glow">
+ <feGaussianBlur stdDeviation="3.5" result="coloredBlur" />
+ <feMerge>
+ <feMergeNode in="coloredBlur" />
+ <feMergeNode in="SourceGraphic" />
+ </feMerge>
+ </filter>
+ </defs>
+ <line x1="80" y1="160" x2="250" y2="70" stroke="url(#line)" />
+ <line x1="80" y1="160" x2="250" y2="250" stroke="url(#line)" />
+ <line x1="250" y1="70" x2="430" y2="160" stroke="url(#line)" />
+ <line x1="250" y1="250" x2="430" y2="160" stroke="url(#line)" />
+ <line x1="250" y1="70" x2="250" y2="250" stroke="#a78bfa" strokeOpacity="0.25" />
+ <line x1="80" y1="160" x2="430" y2="160" stroke="#67e8f9" strokeOpacity="0.15" />
+ <circle cx="80" cy="160" r="9" className="pulse-node" fill="#c084fc" filter="url(#glow)" />
+ <circle cx="250" cy="70" r="7" className="pulse-node-2" fill="#e879f9" filter="url(#glow)" />
+ <circle cx="250" cy="250" r="7" className="pulse-node-3" fill="#818cf8" filter="url(#glow)" />
+ <circle cx="430" cy="160" r="11" fill="#67e8f9" filter="url(#glow)" />
+ <circle cx="170" cy="110" r="4" fill="#c084fc" fillOpacity="0.6" />
+ <circle cx="340" cy="110" r="4" fill="#67e8f9" fillOpacity="0.6" />
+ <circle cx="170" cy="210" r="4" fill="#e879f9" fillOpacity="0.5" />
+ <circle cx="340" cy="210" r="4" fill="#a78bfa" fillOpacity="0.5" />
+ <text
+ x="80"
+ y="188"
+ textAnchor="middle"
+ fill="#ddd6fe"
+ fontSize="9"
+ fontFamily="ui-monospace, monospace"
+ >
+ AGENT
+ </text>
+ <text
+ x="250"
+ y="58"
+ textAnchor="middle"
+ fill="#f5d0fe"
+ fontSize="9"
+ fontFamily="ui-monospace, monospace"
+ >
+ LAKE
+ </text>
+ <text
+ x="250"
+ y="278"
+ textAnchor="middle"
+ fill="#c4b5fd"
+ fontSize="9"
+ fontFamily="ui-monospace, monospace"
+ >
+ MESH
+ </text>
+ <text
+ x="430"
+ y="188"
+ textAnchor="middle"
+ fill="#a5f3fc"
+ fontSize="9"
+ fontFamily="ui-monospace, monospace"
+ >
+ SYNERGY
+ </text>
+ </svg>
+ </div>
+ <aside className="hidden space-y-3 border-l border-white/10 p-4 md:block">
+ <Metric label="Agent velocity" value="+3.2×" />
+ <Metric label="Semantic coverage" value="87%" />
+ <Metric label="eBPF map health" value="99.4" />
+ <Metric label="ESG score" value="A−" />
+ </aside>
+ </div>
+ </div>
+ );
+}
+
+function Metric({ label, value }: { label: string; value: string }) {
+ return (
+ <div className="rounded-xl border border-white/10 bg-white/5 px-3 py-2.5">
+ <p className="font-mono text-[10px] uppercase tracking-wider text-violet-200/70">
+ {label}
+ </p>
+ <p className="mt-1 font-heading text-xl text-white">{value}</p>
+ </div>
+ );
+}
diff --git a/components/faq-list.tsx b/components/faq-list.tsx
new file mode 100644
index 0000000..564df71
--- /dev/null
+++ b/components/faq-list.tsx
@@ -0,0 +1,26 @@
+"use client";
+
+import {
+ Accordion,
+ AccordionContent,
+ AccordionItem,
+ AccordionTrigger,
+} from "@/components/ui/accordion";
+import { faqs } from "@/lib/content";
+
+export function FaqList() {
+ return (
+ <Accordion className="w-full" defaultValue={["what"]}>
+ {faqs.map((item) => (
+ <AccordionItem key={item.id} value={item.id}>
+ <AccordionTrigger className="py-4 text-base hover:no-underline">
+ {item.q}
+ </AccordionTrigger>
+ <AccordionContent className="text-muted-foreground leading-relaxed">
+ {item.a}
+ </AccordionContent>
+ </AccordionItem>
+ ))}
+ </Accordion>
+ );
+}
diff --git a/components/glow-orbs.tsx b/components/glow-orbs.tsx
new file mode 100644
index 0000000..f9a7072
--- /dev/null
+++ b/components/glow-orbs.tsx
@@ -0,0 +1,14 @@
+export function GlowOrbs() {
+ return (
+ <div
+ className="pointer-events-none fixed inset-0 -z-10 overflow-hidden"
+ aria-hidden
+ >
+ <div className="orb orb-a" />
+ <div className="orb orb-b" />
+ <div className="orb orb-c" />
+ <div className="orb orb-d" />
+ <div className="noise" />
+ </div>
+ );
+}
diff --git a/components/logo.tsx b/components/logo.tsx
new file mode 100644
index 0000000..a512203
--- /dev/null
+++ b/components/logo.tsx
@@ -0,0 +1,61 @@
+import { cn } from "@/lib/utils";
+
+export function Logo({
+ className,
+ markClassName,
+ wordmark = true,
+}: {
+ className?: string;
+ markClassName?: string;
+ wordmark?: boolean;
+}) {
+ return (
+ <span className={cn("inline-flex items-center gap-2.5", className)}>
+ <svg
+ viewBox="0 0 32 32"
+ fill="none"
+ className={cn("size-7 shrink-0", markClassName)}
+ aria-hidden
+ >
+ <rect
+ x="1"
+ y="1"
+ width="30"
+ height="30"
+ rx="9"
+ className="fill-primary/10 stroke-primary/45"
+ strokeWidth="1"
+ />
+ <ellipse
+ cx="16"
+ cy="18.5"
+ rx="9.5"
+ ry="5.2"
+ className="stroke-primary/80"
+ strokeWidth="1.4"
+ />
+ <ellipse
+ cx="16"
+ cy="16"
+ rx="7"
+ ry="3.6"
+ className="stroke-primary"
+ strokeWidth="1.3"
+ />
+ <circle cx="10.5" cy="16.2" r="1.35" className="fill-primary" />
+ <circle cx="16" cy="14.4" r="1.5" className="fill-primary" />
+ <circle cx="21.5" cy="16.2" r="1.35" className="fill-primary" />
+ <path
+ d="M10.5 16.2L16 14.4L21.5 16.2"
+ className="stroke-primary/70"
+ strokeWidth="1"
+ />
+ </svg>
+ {wordmark ? (
+ <span className="text-[15px] font-medium tracking-tight text-foreground">
+ The Agentic Cloud
+ </span>
+ ) : null}
+ </span>
+ );
+}
diff --git a/components/request-form.tsx b/components/request-form.tsx
new file mode 100644
index 0000000..8f61337
--- /dev/null
+++ b/components/request-form.tsx
@@ -0,0 +1,145 @@
+"use client";
+
+import { useState } from "react";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import { Textarea } from "@/components/ui/textarea";
+
+const consumerDomains = [
+ "gmail.com",
+ "yahoo.com",
+ "hotmail.com",
+ "outlook.com",
+ "icloud.com",
+ "aol.com",
+ "proton.me",
+ "protonmail.com",
+];
+
+type Status = "idle" | "loading" | "success" | "error";
+
+export function RequestForm() {
+ const [status, setStatus] = useState<Status>("idle");
+ const [error, setError] = useState("");
+
+ async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
+ e.preventDefault();
+ setError("");
+ const form = e.currentTarget;
+ const data = new FormData(form);
+ const name = String(data.get("name") || "").trim();
+ const email = String(data.get("email") || "").trim();
+ const company = String(data.get("company") || "").trim();
+ const role = String(data.get("role") || "").trim();
+ const outcomes = String(data.get("outcomes") || "").trim();
+
+ if (!name || !email || !company || !role || !outcomes) {
+ setStatus("error");
+ setError("Every field is required. Alignment begins with completeness.");
+ return;
+ }
+
+ const domain = email.split("@")[1]?.toLowerCase();
+ if (!domain || !email.includes("@")) {
+ setStatus("error");
+ setError("Please provide an institutional email.");
+ return;
+ }
+ if (consumerDomains.includes(domain)) {
+ setStatus("error");
+ setError(
+ "Consumer inboxes cannot attest PPoE. Please use your institutional email."
+ );
+ return;
+ }
+
+ setStatus("loading");
+ await new Promise((r) => setTimeout(r, 900));
+ setStatus("success");
+ }
+
+ if (status === "success") {
+ return (
+ <div className="rounded-3xl border border-fuchsia-400/30 bg-gradient-to-br from-violet-500/20 to-cyan-500/10 p-8">
+ <p className="font-mono text-[11px] uppercase tracking-[0.2em] text-primary">
+ Request received
+ </p>
+ <h2 className="mt-3 font-heading text-3xl text-foreground">
+ An outcomes partner will be in touch.
+ </h2>
+ <p className="mt-3 text-sm leading-relaxed text-muted-foreground">
+ Fit is a mutual decision. If your operating thesis, your lake, and
+ our fabric are prepared to compound, we will schedule a working
+ session — not a demo.
+ </p>
+ </div>
+ );
+ }
+
+ return (
+ <form onSubmit={onSubmit} className="space-y-5" noValidate>
+ <Field id="name" label="Full name" autoComplete="name" />
+ <Field
+ id="email"
+ label="Institutional email"
+ type="email"
+ autoComplete="email"
+ />
+ <Field id="company" label="Institution" autoComplete="organization" />
+ <Field id="role" label="Role" placeholder="Chief Transformation Officer" />
+ <div className="space-y-2">
+ <Label htmlFor="outcomes">
+ What outcomes are you looking to operationalize?
+ </Label>
+ <Textarea
+ id="outcomes"
+ name="outcomes"
+ rows={5}
+ className="min-h-28 text-sm"
+ placeholder="Be specific about the thesis, not the tools. The fabric will meet you there."
+ />
+ </div>
+ {status === "error" && error ? (
+ <p className="text-sm text-destructive" role="alert">
+ {error}
+ </p>
+ ) : null}
+ <Button
+ type="submit"
+ disabled={status === "loading"}
+ className="h-11 w-full px-5 sm:w-auto"
+ >
+ {status === "loading" ? "Attesting request…" : "Request access"}
+ </Button>
+ </form>
+ );
+}
+
+function Field({
+ id,
+ label,
+ type = "text",
+ autoComplete,
+ placeholder,
+}: {
+ id: string;
+ label: string;
+ type?: string;
+ autoComplete?: string;
+ placeholder?: string;
+}) {
+ return (
+ <div className="space-y-2">
+ <Label htmlFor={id}>{label}</Label>
+ <Input
+ id={id}
+ name={id}
+ type={type}
+ autoComplete={autoComplete}
+ placeholder={placeholder}
+ className="h-10"
+ />
+ </div>
+ );
+}
diff --git a/components/section.tsx b/components/section.tsx
new file mode 100644
index 0000000..59120bf
--- /dev/null
+++ b/components/section.tsx
@@ -0,0 +1,40 @@
+import { cn } from "@/lib/utils";
+
+export function Section({
+ children,
+ className,
+ innerClassName,
+ id,
+}: {
+ children: React.ReactNode;
+ className?: string;
+ innerClassName?: string;
+ id?: string;
+}) {
+ return (
+ <section id={id} className={cn("px-5 py-20 sm:px-8 md:py-28", className)}>
+ <div className={cn("mx-auto w-full max-w-6xl", innerClassName)}>
+ {children}
+ </div>
+ </section>
+ );
+}
+
+export function Eyebrow({
+ children,
+ className,
+}: {
+ children: React.ReactNode;
+ className?: string;
+}) {
+ return (
+ <p
+ className={cn(
+ "inline-flex items-center rounded-full border border-violet-400/25 bg-violet-500/10 px-3 py-1 font-mono text-[11px] font-medium uppercase tracking-[0.22em] text-violet-200",
+ className
+ )}
+ >
+ {children}
+ </p>
+ );
+}
diff --git a/components/site-footer.tsx b/components/site-footer.tsx
new file mode 100644
index 0000000..983de05
--- /dev/null
+++ b/components/site-footer.tsx
@@ -0,0 +1,95 @@
+import Link from "next/link";
+import { Logo } from "@/components/logo";
+import { buttonVariants } from "@/components/ui/button";
+import { cn } from "@/lib/utils";
+
+const columns = [
+ {
+ title: "Product",
+ links: [
+ { href: "/platform", label: "Platform" },
+ { href: "/fabric", label: "Fabric" },
+ { href: "/solutions", label: "Solutions" },
+ { href: "/pricing", label: "Pricing" },
+ { href: "/request-access", label: "Request access" },
+ ],
+ },
+ {
+ title: "Company",
+ links: [
+ { href: "/about", label: "About" },
+ { href: "/customers", label: "Customers" },
+ { href: "/careers", label: "Careers" },
+ { href: "/insights", label: "Insights" },
+ ],
+ },
+ {
+ title: "Trust",
+ links: [
+ { href: "/trust", label: "Trust center" },
+ { href: "/privacy", label: "Privacy" },
+ { href: "/terms", label: "Terms" },
+ { href: "/pricing", label: "Sovereign" },
+ ],
+ },
+];
+
+export function SiteFooter() {
+ return (
+ <footer className="relative border-t border-white/10 bg-background/40 backdrop-blur-xl">
+ <div className="mx-auto grid max-w-6xl gap-12 px-5 py-16 sm:px-8 md:grid-cols-5">
+ <div className="md:col-span-2">
+ <Logo />
+ <p className="mt-4 max-w-sm text-sm leading-relaxed text-muted-foreground">
+ The agentic cloud for enterprise outcomes. Space-aware,
+ entanglement-ready, hyperautomation-compliant — and surprisingly
+ serious about Dogecoin.
+ </p>
+ <Link
+ href="/request-access"
+ className={cn(
+ buttonVariants({ variant: "outline" }),
+ "mt-6 h-9 px-3.5"
+ )}
+ >
+ Request access
+ </Link>
+ </div>
+ {columns.map((col) => (
+ <div key={col.title}>
+ <p className="font-mono text-[11px] uppercase tracking-[0.18em] text-muted-foreground">
+ {col.title}
+ </p>
+ <ul className="mt-4 space-y-2.5">
+ {col.links.map((link) => (
+ <li key={link.href + link.label}>
+ <Link
+ href={link.href}
+ className="text-sm text-foreground/85 transition-colors hover:text-primary"
+ >
+ {link.label}
+ </Link>
+ </li>
+ ))}
+ </ul>
+ </div>
+ ))}
+ </div>
+ <div className="border-t border-white/10">
+ <div className="mx-auto flex max-w-6xl flex-col gap-3 px-5 py-6 text-xs text-muted-foreground sm:flex-row sm:items-center sm:justify-between sm:px-8">
+ <p>
+ © {new Date().getFullYear()} The Agentic Cloud, Inc. All rights
+ reserved.
+ </p>
+ <p className="flex flex-wrap gap-x-4 gap-y-1">
+ <span>SOC 2 Type II</span>
+ <span>ISO 27001</span>
+ <span>FedRAMP High</span>
+ <span>SLSA L3</span>
+ <span>GDPR · CCPA · COPPA</span>
+ </p>
+ </div>
+ </div>
+ </footer>
+ );
+}
diff --git a/components/site-header.tsx b/components/site-header.tsx
new file mode 100644
index 0000000..4d6df15
--- /dev/null
+++ b/components/site-header.tsx
@@ -0,0 +1,130 @@
+"use client";
+
+import Link from "next/link";
+import { usePathname } from "next/navigation";
+import { useState } from "react";
+import { Menu } from "lucide-react";
+import { Logo } from "@/components/logo";
+import { Button, buttonVariants } from "@/components/ui/button";
+import {
+ Sheet,
+ SheetContent,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from "@/components/ui/sheet";
+import { nav } from "@/lib/content";
+import { cn } from "@/lib/utils";
+
+export function SiteHeader() {
+ const pathname = usePathname();
+ const [open, setOpen] = useState(false);
+
+ return (
+ <header className="sticky top-0 z-40 border-b border-white/10 bg-background/40 backdrop-blur-2xl">
+ <div className="mx-auto flex h-16 max-w-6xl items-center justify-between gap-4 px-5 sm:px-8">
+ <Link href="/" aria-label="The Agentic Cloud home" className="min-w-0">
+ <Logo className="max-[420px]:[&>span:last-child]:hidden" />
+ </Link>
+ <nav className="hidden items-center gap-6 lg:flex">
+ {nav.map((item) => (
+ <Link
+ key={item.href}
+ href={item.href}
+ className={cn(
+ "text-sm transition-colors hover:text-foreground",
+ pathname === item.href || pathname.startsWith(`${item.href}/`)
+ ? "text-foreground"
+ : "text-muted-foreground"
+ )}
+ >
+ {item.label}
+ </Link>
+ ))}
+ </nav>
+ <div className="hidden items-center gap-2 lg:flex">
+ <Link
+ href="/about"
+ className={cn(
+ buttonVariants({ variant: "ghost" }),
+ "h-8 px-3 text-muted-foreground"
+ )}
+ >
+ About
+ </Link>
+ <Link
+ href="/request-access"
+ className={cn(buttonVariants(), "h-8 px-3.5")}
+ >
+ Request access
+ </Link>
+ </div>
+ <Sheet open={open} onOpenChange={setOpen}>
+ <SheetTrigger
+ nativeButton={false}
+ render={
+ <Button
+ variant="ghost"
+ size="icon"
+ className="lg:hidden"
+ aria-label="Open menu"
+ />
+ }
+ >
+ <Menu className="size-5" />
+ </SheetTrigger>
+ <SheetContent side="right" className="bg-background">
+ <SheetHeader>
+ <SheetTitle className="font-sans text-left text-sm font-medium tracking-tight">
+ The Agentic Cloud
+ </SheetTitle>
+ </SheetHeader>
+ <nav className="flex flex-col gap-1 px-4">
+ {nav.map((item) => (
+ <Link
+ key={item.href}
+ href={item.href}
+ onClick={() => setOpen(false)}
+ className="rounded-lg px-2 py-2.5 text-base text-foreground/90 hover:bg-muted"
+ >
+ {item.label}
+ </Link>
+ ))}
+ <Link
+ href="/about"
+ onClick={() => setOpen(false)}
+ className="rounded-lg px-2 py-2.5 text-base text-foreground/90 hover:bg-muted"
+ >
+ About
+ </Link>
+ <Link
+ href="/careers"
+ onClick={() => setOpen(false)}
+ className="rounded-lg px-2 py-2.5 text-base text-foreground/90 hover:bg-muted"
+ >
+ Careers
+ </Link>
+ <Link
+ href="/trust"
+ onClick={() => setOpen(false)}
+ className="rounded-lg px-2 py-2.5 text-base text-foreground/90 hover:bg-muted"
+ >
+ Trust
+ </Link>
+ <Link
+ href="/request-access"
+ onClick={() => setOpen(false)}
+ className={cn(
+ buttonVariants(),
+ "mt-4 h-10 justify-center px-4"
+ )}
+ >
+ Request access
+ </Link>
+ </nav>
+ </SheetContent>
+ </Sheet>
+ </div>
+ </header>
+ );
+}
diff --git a/components/solutions-tabs.tsx b/components/solutions-tabs.tsx
new file mode 100644
index 0000000..0bc055c
--- /dev/null
+++ b/components/solutions-tabs.tsx
@@ -0,0 +1,53 @@
+"use client";
+
+import { solutions } from "@/lib/content";
+import {
+ Tabs,
+ TabsContent,
+ TabsList,
+ TabsTrigger,
+} from "@/components/ui/tabs";
+
+export function SolutionsTabs() {
+ return (
+ <Tabs defaultValue={solutions[0].id} className="w-full">
+ <TabsList
+ variant="line"
+ className="h-auto w-full flex-wrap justify-start gap-1 rounded-none bg-transparent p-0"
+ >
+ {solutions.map((s) => (
+ <TabsTrigger
+ key={s.id}
+ value={s.id}
+ className="h-9 px-3 text-sm data-active:text-foreground"
+ >
+ {s.label}
+ </TabsTrigger>
+ ))}
+ </TabsList>
+ {solutions.map((s) => (
+ <TabsContent key={s.id} value={s.id} className="mt-10">
+ <p className="font-mono text-[11px] uppercase tracking-[0.2em] text-primary">
+ {s.label}
+ </p>
+ <h2 className="mt-3 max-w-3xl font-heading text-3xl leading-tight text-foreground md:text-4xl">
+ {s.headline}
+ </h2>
+ <p className="mt-5 max-w-3xl text-base leading-relaxed text-muted-foreground">
+ {s.body}
+ </p>
+ <ul className="mt-8 grid gap-3 sm:grid-cols-3">
+ {s.outcomes.map((o) => (
+ <li
+ key={o}
+ className="rounded-xl border border-white/10 bg-white/5 p-4 text-sm leading-relaxed text-foreground/90 backdrop-blur-xl"
+ >
+ {o}
+ </li>
+ ))}
+ </ul>
+ </TabsContent>
+ ))}
+ </Tabs>
+ );
+}
diff --git a/components/ui/accordion.tsx b/components/ui/accordion.tsx
new file mode 100644
index 0000000..6142db9
--- /dev/null
+++ b/components/ui/accordion.tsx
@@ -0,0 +1,74 @@
+"use client"
+
+import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"
+
+import { cn } from "@/lib/utils"
+import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
+
+function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
+ return (
+ <AccordionPrimitive.Root
+ data-slot="accordion"
+ className={cn("flex w-full flex-col", className)}
+ {...props}
+ />
+ )
+}
+
+function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
+ return (
+ <AccordionPrimitive.Item
+ data-slot="accordion-item"
+ className={cn("not-last:border-b", className)}
+ {...props}
+ />
+ )
+}
+
+function AccordionTrigger({
+ className,
+ children,
+ ...props
+}: AccordionPrimitive.Trigger.Props) {
+ return (
+ <AccordionPrimitive.Header className="flex">
+ <AccordionPrimitive.Trigger
+ data-slot="accordion-trigger"
+ className={cn(
+ "group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
+ className
+ )}
+ {...props}
+ >
+ {children}
+ <ChevronDownIcon data-slot="accordion-trigger-icon" className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden" />
+ <ChevronUpIcon data-slot="accordion-trigger-icon" className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline" />
+ </AccordionPrimitive.Trigger>
+ </AccordionPrimitive.Header>
+ )
+}
+
+function AccordionContent({
+ className,
+ children,
+ ...props
+}: AccordionPrimitive.Panel.Props) {
+ return (
+ <AccordionPrimitive.Panel
+ data-slot="accordion-content"
+ className="overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up"
+ {...props}
+ >
+ <div
+ className={cn(
+ "h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4",
+ className
+ )}
+ >
+ {children}
+ </div>
+ </AccordionPrimitive.Panel>
+ )
+}
+
+export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
diff --git a/components/ui/badge.tsx b/components/ui/badge.tsx
new file mode 100644
index 0000000..b20959d
--- /dev/null
+++ b/components/ui/badge.tsx
@@ -0,0 +1,52 @@
+import { mergeProps } from "@base-ui/react/merge-props"
+import { useRender } from "@base-ui/react/use-render"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const badgeVariants = cva(
+ "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
+ secondary:
+ "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
+ destructive:
+ "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
+ outline:
+ "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
+ ghost:
+ "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+function Badge({
+ className,
+ variant = "default",
+ render,
+ ...props
+}: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
+ return useRender({
+ defaultTagName: "span",
+ props: mergeProps<"span">(
+ {
+ className: cn(badgeVariants({ variant }), className),
+ },
+ props
+ ),
+ render,
+ state: {
+ slot: "badge",
+ variant,
+ },
+ })
+}
+
+export { Badge, badgeVariants }
diff --git a/components/ui/button.tsx b/components/ui/button.tsx
new file mode 100644
index 0000000..78b28b7
--- /dev/null
+++ b/components/ui/button.tsx
@@ -0,0 +1,59 @@
+import { Button as ButtonPrimitive } from "@base-ui/react/button"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const buttonVariants = cva(
+ "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ {
+ variants: {
+ variant: {
+ default:
+ "vibe-btn border-transparent text-white hover:brightness-110",
+ outline:
+ "border-white/15 bg-white/5 text-foreground backdrop-blur-md hover:bg-white/10 hover:text-foreground aria-expanded:bg-white/10 aria-expanded:text-foreground dark:border-white/15 dark:bg-white/5 dark:hover:bg-white/10",
+ secondary:
+ "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
+ ghost:
+ "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
+ destructive:
+ "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default:
+ "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
+ sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
+ lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
+ icon: "size-8",
+ "icon-xs":
+ "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
+ "icon-sm":
+ "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
+ "icon-lg": "size-9",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+function Button({
+ className,
+ variant = "default",
+ size = "default",
+ ...props
+}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
+ return (
+ <ButtonPrimitive
+ data-slot="button"
+ className={cn(buttonVariants({ variant, size, className }))}
+ {...props}
+ />
+ )
+}
+
+export { Button, buttonVariants }
diff --git a/components/ui/card.tsx b/components/ui/card.tsx
new file mode 100644
index 0000000..4458dae
--- /dev/null
+++ b/components/ui/card.tsx
@@ -0,0 +1,103 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Card({
+ className,
+ size = "default",
+ ...props
+}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
+ return (
+ <div
+ data-slot="card"
+ data-size={size}
+ className={cn(
+ "group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+ <div
+ data-slot="card-header"
+ className={cn(
+ "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+ <div
+ data-slot="card-title"
+ className={cn(
+ "font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+ <div
+ data-slot="card-description"
+ className={cn("text-sm text-muted-foreground", className)}
+ {...props}
+ />
+ )
+}
+
+function CardAction({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+ <div
+ data-slot="card-action"
+ className={cn(
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function CardContent({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+ <div
+ data-slot="card-content"
+ className={cn("px-(--card-spacing)", className)}
+ {...props}
+ />
+ )
+}
+
+function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+ <div
+ data-slot="card-footer"
+ className={cn(
+ "flex items-center rounded-b-xl border-t bg-muted/50 p-(--card-spacing)",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardAction,
+ CardDescription,
+ CardContent,
+}
diff --git a/components/ui/dialog.tsx b/components/ui/dialog.tsx
new file mode 100644
index 0000000..014f5aa
--- /dev/null
+++ b/components/ui/dialog.tsx
@@ -0,0 +1,160 @@
+"use client"
+
+import * as React from "react"
+import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
+
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import { XIcon } from "lucide-react"
+
+function Dialog({ ...props }: DialogPrimitive.Root.Props) {
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />
+}
+
+function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
+}
+
+function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
+}
+
+function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
+}
+
+function DialogOverlay({
+ className,
+ ...props
+}: DialogPrimitive.Backdrop.Props) {
+ return (
+ <DialogPrimitive.Backdrop
+ data-slot="dialog-overlay"
+ className={cn(
+ "fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function DialogContent({
+ className,
+ children,
+ showCloseButton = true,
+ ...props
+}: DialogPrimitive.Popup.Props & {
+ showCloseButton?: boolean
+}) {
+ return (
+ <DialogPortal>
+ <DialogOverlay />
+ <DialogPrimitive.Popup
+ data-slot="dialog-content"
+ className={cn(
+ "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
+ className
+ )}
+ {...props}
+ >
+ {children}
+ {showCloseButton && (
+ <DialogPrimitive.Close
+ data-slot="dialog-close"
+ render={
+ <Button
+ variant="ghost"
+ className="absolute top-2 right-2"
+ size="icon-sm"
+ />
+ }
+ >
+ <XIcon
+ />
+ <span className="sr-only">Close</span>
+ </DialogPrimitive.Close>
+ )}
+ </DialogPrimitive.Popup>
+ </DialogPortal>
+ )
+}
+
+function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+ <div
+ data-slot="dialog-header"
+ className={cn("flex flex-col gap-2", className)}
+ {...props}
+ />
+ )
+}
+
+function DialogFooter({
+ className,
+ showCloseButton = false,
+ children,
+ ...props
+}: React.ComponentProps<"div"> & {
+ showCloseButton?: boolean
+}) {
+ return (
+ <div
+ data-slot="dialog-footer"
+ className={cn(
+ "-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end",
+ className
+ )}
+ {...props}
+ >
+ {children}
+ {showCloseButton && (
+ <DialogPrimitive.Close render={<Button variant="outline" />}>
+ Close
+ </DialogPrimitive.Close>
+ )}
+ </div>
+ )
+}
+
+function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
+ return (
+ <DialogPrimitive.Title
+ data-slot="dialog-title"
+ className={cn(
+ "font-heading text-base leading-none font-medium",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function DialogDescription({
+ className,
+ ...props
+}: DialogPrimitive.Description.Props) {
+ return (
+ <DialogPrimitive.Description
+ data-slot="dialog-description"
+ className={cn(
+ "text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+export {
+ Dialog,
+ DialogClose,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogOverlay,
+ DialogPortal,
+ DialogTitle,
+ DialogTrigger,
+}
diff --git a/components/ui/input.tsx b/components/ui/input.tsx
new file mode 100644
index 0000000..7d21bab
--- /dev/null
+++ b/components/ui/input.tsx
@@ -0,0 +1,20 @@
+import * as React from "react"
+import { Input as InputPrimitive } from "@base-ui/react/input"
+
+import { cn } from "@/lib/utils"
+
+function Input({ className, type, ...props }: React.ComponentProps<"input">) {
+ return (
+ <InputPrimitive
+ type={type}
+ data-slot="input"
+ className={cn(
+ "h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+export { Input }
diff --git a/components/ui/label.tsx b/components/ui/label.tsx
new file mode 100644
index 0000000..74da65c
--- /dev/null
+++ b/components/ui/label.tsx
@@ -0,0 +1,20 @@
+"use client"
+
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Label({ className, ...props }: React.ComponentProps<"label">) {
+ return (
+ <label
+ data-slot="label"
+ className={cn(
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+export { Label }
diff --git a/components/ui/navigation-menu.tsx b/components/ui/navigation-menu.tsx
new file mode 100644
index 0000000..5958637
--- /dev/null
+++ b/components/ui/navigation-menu.tsx
@@ -0,0 +1,168 @@
+import { NavigationMenu as NavigationMenuPrimitive } from "@base-ui/react/navigation-menu"
+import { cva } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+import { ChevronDownIcon } from "lucide-react"
+
+function NavigationMenu({
+ align = "start",
+ className,
+ children,
+ ...props
+}: NavigationMenuPrimitive.Root.Props &
+ Pick<NavigationMenuPrimitive.Positioner.Props, "align">) {
+ return (
+ <NavigationMenuPrimitive.Root
+ data-slot="navigation-menu"
+ className={cn(
+ "group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
+ className
+ )}
+ {...props}
+ >
+ {children}
+ <NavigationMenuPositioner align={align} />
+ </NavigationMenuPrimitive.Root>
+ )
+}
+
+function NavigationMenuList({
+ className,
+ ...props
+}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.List>) {
+ return (
+ <NavigationMenuPrimitive.List
+ data-slot="navigation-menu-list"
+ className={cn(
+ "group flex flex-1 list-none items-center justify-center gap-0",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function NavigationMenuItem({
+ className,
+ ...props
+}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.Item>) {
+ return (
+ <NavigationMenuPrimitive.Item
+ data-slot="navigation-menu-item"
+ className={cn("relative", className)}
+ {...props}
+ />
+ )
+}
+
+const navigationMenuTriggerStyle = cva(
+ "group/navigation-menu-trigger inline-flex h-9 w-max items-center justify-center rounded-lg px-2.5 py-1.5 text-sm font-medium transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-popup-open:bg-muted/50 data-popup-open:hover:bg-muted data-open:bg-muted/50 data-open:hover:bg-muted data-open:focus:bg-muted"
+)
+
+function NavigationMenuTrigger({
+ className,
+ children,
+ ...props
+}: NavigationMenuPrimitive.Trigger.Props) {
+ return (
+ <NavigationMenuPrimitive.Trigger
+ data-slot="navigation-menu-trigger"
+ className={cn(navigationMenuTriggerStyle(), "group", className)}
+ {...props}
+ >
+ {children}{" "}
+ <ChevronDownIcon className="relative top-px ml-1 size-3 transition duration-300 group-data-popup-open/navigation-menu-trigger:rotate-180 group-data-open/navigation-menu-trigger:rotate-180" aria-hidden="true" />
+ </NavigationMenuPrimitive.Trigger>
+ )
+}
+
+function NavigationMenuContent({
+ className,
+ ...props
+}: NavigationMenuPrimitive.Content.Props) {
+ return (
+ <NavigationMenuPrimitive.Content
+ data-slot="navigation-menu-content"
+ className={cn(
+ "data-ending-style:data-activation-direction=left:translate-x-[50%] data-ending-style:data-activation-direction=right:translate-x-[-50%] data-starting-style:data-activation-direction=left:translate-x-[-50%] data-starting-style:data-activation-direction=right:translate-x-[50%] h-full w-auto p-1 transition-[opacity,transform,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] group-data-[viewport=false]/navigation-menu:rounded-lg group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:ring-1 group-data-[viewport=false]/navigation-menu:ring-foreground/10 group-data-[viewport=false]/navigation-menu:duration-300 data-ending-style:opacity-0 data-starting-style:opacity-0 data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function NavigationMenuPositioner({
+ className,
+ side = "bottom",
+ sideOffset = 8,
+ align = "start",
+ alignOffset = 0,
+ ...props
+}: NavigationMenuPrimitive.Positioner.Props) {
+ return (
+ <NavigationMenuPrimitive.Portal>
+ <NavigationMenuPrimitive.Positioner
+ side={side}
+ sideOffset={sideOffset}
+ align={align}
+ alignOffset={alignOffset}
+ className={cn(
+ "isolate z-50 h-(--positioner-height) w-(--positioner-width) max-w-(--available-width) transition-[top,left,right,bottom] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] data-instant:transition-none data-[side=bottom]:before:top-[-10px] data-[side=bottom]:before:right-0 data-[side=bottom]:before:left-0",
+ className
+ )}
+ {...props}
+ >
+ <NavigationMenuPrimitive.Popup className="data-[ending-style]:easing-[ease] xs:w-(--popup-width) relative h-(--popup-height) w-(--popup-width) origin-(--transform-origin) rounded-lg bg-popover text-popover-foreground shadow ring-1 ring-foreground/10 transition-[opacity,transform,width,height,scale,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] outline-none data-ending-style:scale-90 data-ending-style:opacity-0 data-ending-style:duration-150 data-starting-style:scale-90 data-starting-style:opacity-0">
+ <NavigationMenuPrimitive.Viewport className="relative size-full overflow-hidden" />
+ </NavigationMenuPrimitive.Popup>
+ </NavigationMenuPrimitive.Positioner>
+ </NavigationMenuPrimitive.Portal>
+ )
+}
+
+function NavigationMenuLink({
+ className,
+ ...props
+}: NavigationMenuPrimitive.Link.Props) {
+ return (
+ <NavigationMenuPrimitive.Link
+ data-slot="navigation-menu-link"
+ className={cn(
+ "flex items-center gap-2 rounded-lg p-2 text-sm transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 in-data-[slot=navigation-menu-content]:rounded-md data-active:bg-muted/50 data-active:hover:bg-muted data-active:focus:bg-muted [&_svg:not([class*='size-'])]:size-4",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function NavigationMenuIndicator({
+ className,
+ ...props
+}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.Icon>) {
+ return (
+ <NavigationMenuPrimitive.Icon
+ data-slot="navigation-menu-indicator"
+ className={cn(
+ "top-full z-1 flex h-1.5 items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:animate-in data-[state=visible]:fade-in",
+ className
+ )}
+ {...props}
+ >
+ <div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
+ </NavigationMenuPrimitive.Icon>
+ )
+}
+
+export {
+ NavigationMenu,
+ NavigationMenuContent,
+ NavigationMenuIndicator,
+ NavigationMenuItem,
+ NavigationMenuLink,
+ NavigationMenuList,
+ NavigationMenuTrigger,
+ navigationMenuTriggerStyle,
+ NavigationMenuPositioner,
+}
diff --git a/components/ui/separator.tsx b/components/ui/separator.tsx
new file mode 100644
index 0000000..6e1369e
--- /dev/null
+++ b/components/ui/separator.tsx
@@ -0,0 +1,25 @@
+"use client"
+
+import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"
+
+import { cn } from "@/lib/utils"
+
+function Separator({
+ className,
+ orientation = "horizontal",
+ ...props
+}: SeparatorPrimitive.Props) {
+ return (
+ <SeparatorPrimitive
+ data-slot="separator"
+ orientation={orientation}
+ className={cn(
+ "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+export { Separator }
diff --git a/components/ui/sheet.tsx b/components/ui/sheet.tsx
new file mode 100644
index 0000000..78c0a76
--- /dev/null
+++ b/components/ui/sheet.tsx
@@ -0,0 +1,138 @@
+"use client"
+
+import * as React from "react"
+import { Dialog as SheetPrimitive } from "@base-ui/react/dialog"
+
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import { XIcon } from "lucide-react"
+
+function Sheet({ ...props }: SheetPrimitive.Root.Props) {
+ return <SheetPrimitive.Root data-slot="sheet" {...props} />
+}
+
+function SheetTrigger({ ...props }: SheetPrimitive.Trigger.Props) {
+ return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
+}
+
+function SheetClose({ ...props }: SheetPrimitive.Close.Props) {
+ return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
+}
+
+function SheetPortal({ ...props }: SheetPrimitive.Portal.Props) {
+ return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
+}
+
+function SheetOverlay({ className, ...props }: SheetPrimitive.Backdrop.Props) {
+ return (
+ <SheetPrimitive.Backdrop
+ data-slot="sheet-overlay"
+ className={cn(
+ "fixed inset-0 z-50 bg-black/10 transition-opacity duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function SheetContent({
+ className,
+ children,
+ side = "right",
+ showCloseButton = true,
+ ...props
+}: SheetPrimitive.Popup.Props & {
+ side?: "top" | "right" | "bottom" | "left"
+ showCloseButton?: boolean
+}) {
+ return (
+ <SheetPortal>
+ <SheetOverlay />
+ <SheetPrimitive.Popup
+ data-slot="sheet-content"
+ data-side={side}
+ className={cn(
+ "fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
+ className
+ )}
+ {...props}
+ >
+ {children}
+ {showCloseButton && (
+ <SheetPrimitive.Close
+ data-slot="sheet-close"
+ render={
+ <Button
+ variant="ghost"
+ className="absolute top-3 right-3"
+ size="icon-sm"
+ />
+ }
+ >
+ <XIcon
+ />
+ <span className="sr-only">Close</span>
+ </SheetPrimitive.Close>
+ )}
+ </SheetPrimitive.Popup>
+ </SheetPortal>
+ )
+}
+
+function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+ <div
+ data-slot="sheet-header"
+ className={cn("flex flex-col gap-0.5 p-4", className)}
+ {...props}
+ />
+ )
+}
+
+function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+ <div
+ data-slot="sheet-footer"
+ className={cn("mt-auto flex flex-col gap-2 p-4", className)}
+ {...props}
+ />
+ )
+}
+
+function SheetTitle({ className, ...props }: SheetPrimitive.Title.Props) {
+ return (
+ <SheetPrimitive.Title
+ data-slot="sheet-title"
+ className={cn(
+ "font-heading text-base font-medium text-foreground",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function SheetDescription({
+ className,
+ ...props
+}: SheetPrimitive.Description.Props) {
+ return (
+ <SheetPrimitive.Description
+ data-slot="sheet-description"
+ className={cn("text-sm text-muted-foreground", className)}
+ {...props}
+ />
+ )
+}
+
+export {
+ Sheet,
+ SheetTrigger,
+ SheetClose,
+ SheetContent,
+ SheetHeader,
+ SheetFooter,
+ SheetTitle,
+ SheetDescription,
+}
diff --git a/components/ui/tabs.tsx b/components/ui/tabs.tsx
new file mode 100644
index 0000000..8ee8054
--- /dev/null
+++ b/components/ui/tabs.tsx
@@ -0,0 +1,82 @@
+"use client"
+
+import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+function Tabs({
+ className,
+ orientation = "horizontal",
+ ...props
+}: TabsPrimitive.Root.Props) {
+ return (
+ <TabsPrimitive.Root
+ data-slot="tabs"
+ data-orientation={orientation}
+ className={cn(
+ "group/tabs flex gap-2 data-horizontal:flex-col",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+const tabsListVariants = cva(
+ "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
+ {
+ variants: {
+ variant: {
+ default: "bg-muted",
+ line: "gap-1 bg-transparent",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+function TabsList({
+ className,
+ variant = "default",
+ ...props
+}: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
+ return (
+ <TabsPrimitive.List
+ data-slot="tabs-list"
+ data-variant={variant}
+ className={cn(tabsListVariants({ variant }), className)}
+ {...props}
+ />
+ )
+}
+
+function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
+ return (
+ <TabsPrimitive.Tab
+ data-slot="tabs-trigger"
+ className={cn(
+ "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
+ "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
+ "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
+ return (
+ <TabsPrimitive.Panel
+ data-slot="tabs-content"
+ className={cn("flex-1 text-sm outline-none", className)}
+ {...props}
+ />
+ )
+}
+
+export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
diff --git a/components/ui/textarea.tsx b/components/ui/textarea.tsx
new file mode 100644
index 0000000..04d27f7
--- /dev/null
+++ b/components/ui/textarea.tsx
@@ -0,0 +1,18 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
+ return (
+ <textarea
+ data-slot="textarea"
+ className={cn(
+ "flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+export { Textarea }