diff --git a/landing/.gitignore b/landing/.gitignore
new file mode 100644
index 0000000..c2658d7
--- /dev/null
+++ b/landing/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/landing/app/globals.css b/landing/app/globals.css
new file mode 100644
index 0000000..e6b390b
--- /dev/null
+++ b/landing/app/globals.css
@@ -0,0 +1,412 @@
+:root {
+ --bg: #f8f9fc;
+ --surface: #ffffff;
+ --border: #e2e8f0;
+ --text: #0f172a;
+ --text-secondary: #475569;
+ --muted: #94a3b8;
+ --accent: #2563eb;
+ --accent-hover: #1d4ed8;
+ --accent-light: #eff6ff;
+ --emerald: #059669;
+ --emerald-light: #ecfdf5;
+ --emerald-bright: #10b981;
+ --violet: #7c3aed;
+ --violet-light: #f5f3ff;
+ --rose: #e11d48;
+ --rose-light: #fff1f2;
+ --amber: #d97706;
+ --amber-light: #fffbeb;
+ --radius: 10px;
+ --radius-lg: 16px;
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
+ --shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.06), 0 2px 4px -2px rgba(0, 0, 0, 0.04);
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.06), 0 4px 6px -4px rgba(0, 0, 0, 0.04);
+ --transition: 0.2s ease;
+}
+
+* { margin: 0; padding: 0; box-sizing: border-box; }
+
+html { scroll-behavior: smooth; }
+
+body {
+ background: var(--bg);
+ color: var(--text);
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+ -webkit-font-smoothing: antialiased;
+}
+
+::selection { background: var(--accent-light); color: var(--accent); }
+
+/* ── Card ── */
+.card {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-sm);
+ transition: box-shadow var(--transition), border-color var(--transition);
+}
+.card:hover {
+ box-shadow: var(--shadow-md);
+ border-color: #cbd5e1;
+}
+
+.card-spotlight {
+ position: relative;
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-lg);
+ overflow: hidden;
+ transition: box-shadow var(--transition), border-color var(--transition);
+}
+.card-spotlight::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: radial-gradient(
+ 600px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
+ rgba(37, 99, 235, 0.04),
+ transparent 40%
+ );
+ opacity: 0;
+ transition: opacity 0.3s;
+ pointer-events: none;
+}
+.card-spotlight:hover::before { opacity: 1; }
+.card-spotlight:hover {
+ box-shadow: var(--shadow-md);
+ border-color: #cbd5e1;
+}
+
+/* ── Button ── */
+.btn-primary {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 12px 28px;
+ background: var(--accent);
+ color: #fff;
+ font-weight: 600;
+ font-size: 15px;
+ border-radius: var(--radius);
+ border: none;
+ cursor: pointer;
+ transition: background 0.2s, box-shadow 0.2s;
+ text-decoration: none;
+}
+.btn-primary:hover {
+ background: var(--accent-hover);
+ box-shadow: var(--shadow-md);
+}
+
+.btn-secondary {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 12px 28px;
+ background: var(--surface);
+ color: var(--text);
+ font-weight: 600;
+ font-size: 15px;
+ border-radius: var(--radius);
+ border: 1px solid var(--border);
+ cursor: pointer;
+ transition: border-color 0.2s, box-shadow 0.2s;
+ text-decoration: none;
+}
+.btn-secondary:hover {
+ border-color: var(--accent);
+ box-shadow: var(--shadow-sm);
+}
+
+.btn-ghost {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 8px 16px;
+ background: transparent;
+ color: var(--text-secondary);
+ font-size: 13px;
+ font-weight: 500;
+ border-radius: 8px;
+ border: 1px solid transparent;
+ cursor: pointer;
+ transition: color 0.2s, border-color 0.2s;
+ text-decoration: none;
+}
+.btn-ghost:hover {
+ color: var(--text);
+ border-color: var(--border);
+}
+
+/* ── Badge ── */
+.badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 14px;
+ border-radius: 100px;
+ background: var(--accent-light);
+ color: var(--accent);
+ font-size: 12px;
+ font-weight: 600;
+ letter-spacing: 0.2px;
+ border: 1px solid rgba(37, 99, 235, 0.12);
+}
+.badge-dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--accent);
+ animation: badge-pulse 2s infinite;
+}
+@keyframes badge-pulse {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.3; }
+}
+
+/* ── Tag / chip ── */
+.tag {
+ display: inline-flex;
+ align-items: center;
+ padding: 3px 10px;
+ border-radius: 100px;
+ font-size: 10px;
+ font-weight: 700;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+ border: 1px solid transparent;
+}
+.tag-emerald { background: var(--emerald-light); color: var(--emerald); border-color: rgba(5, 150, 105, 0.12); }
+.tag-blue { background: var(--accent-light); color: var(--accent); border-color: rgba(37, 99, 235, 0.12); }
+.tag-violet { background: var(--violet-light); color: var(--violet); border-color: rgba(124, 58, 237, 0.12); }
+.tag-amber { background: var(--amber-light); color: var(--amber); border-color: rgba(217, 119, 6, 0.12); }
+.tag-rose { background: var(--rose-light); color: var(--rose); border-color: rgba(225, 29, 72, 0.12); }
+
+/* ── Code block ── */
+.code-block {
+ background: #f1f5f9;
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ overflow: hidden;
+}
+.code-header {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 16px;
+ background: #e2e8f0;
+ font-size: 12px;
+ color: var(--text-secondary);
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
+}
+.code-dot { width: 9px; height: 9px; border-radius: 50%; }
+.code-body {
+ padding: 16px;
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
+ font-size: 13px;
+ line-height: 1.6;
+ overflow-x: auto;
+ color: var(--text-secondary);
+}
+
+/* ── Modern Centered Floating Nav ── */
+.nav-wrapper {
+ position: fixed;
+ top: 20px;
+ left: 0;
+ right: 0;
+ z-index: 100;
+ display: flex;
+ justify-content: center;
+ padding: 0 16px;
+ pointer-events: none;
+}
+.nav {
+ pointer-events: auto;
+ width: 100%;
+ max-width: 900px;
+ background: rgba(255, 255, 255, 0.78);
+ backdrop-filter: blur(20px) saturate(190%);
+ -webkit-backdrop-filter: blur(20px) saturate(190%);
+ border: 1px solid rgba(226, 232, 240, 0.85);
+ border-radius: 100px;
+ padding: 8px 12px 8px 22px;
+ box-shadow: 0 12px 35px -10px rgba(15, 23, 42, 0.08), 0 4px 12px rgba(0, 0, 0, 0.02);
+ transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
+}
+.nav-inner {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+}
+.logo {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-weight: 800;
+ font-size: 17px;
+ letter-spacing: -0.03em;
+ color: var(--text);
+ text-decoration: none;
+}
+.logo-mark {
+ width: 26px;
+ height: 26px;
+ border-radius: 7px;
+ background: linear-gradient(135deg, var(--accent), var(--emerald));
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #fff;
+ font-weight: 900;
+ font-size: 13px;
+ box-shadow: 0 2px 8px rgba(37, 99, 235, 0.25);
+}
+.nav-links {
+ display: flex;
+ gap: 20px;
+ align-items: center;
+}
+.nav-links a {
+ color: var(--text-secondary);
+ text-decoration: none;
+ font-size: 13.5px;
+ font-weight: 600;
+ padding: 6px 14px;
+ border-radius: 100px;
+ transition: all 0.2s ease;
+}
+.nav-links a:hover {
+ color: var(--text);
+ background: rgba(15, 23, 42, 0.04);
+}
+.nav-action {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 8px 18px;
+ background: var(--text);
+ color: #fff;
+ font-size: 13px;
+ font-weight: 600;
+ border-radius: 100px;
+ text-decoration: none;
+ transition: all 0.25s ease;
+ box-shadow: 0 4px 12px rgba(15, 23, 42, 0.15);
+}
+.nav-action:hover {
+ background: var(--accent);
+ transform: translateY(-1px);
+ box-shadow: 0 6px 16px rgba(37, 99, 235, 0.3);
+}
+@media (max-width: 768px) {
+ .nav-links { display: none; }
+ .nav-wrapper { top: 12px; }
+ .nav { padding: 8px 12px 8px 16px; }
+}
+
+/* ── Section ── */
+.section { padding: 100px 24px; max-width: 1200px; margin: 0 auto; }
+.section-label {
+ color: var(--accent);
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 1.5px;
+ text-transform: uppercase;
+ margin-bottom: 12px;
+}
+.section-title {
+ font-size: clamp(28px, 3.5vw, 42px);
+ font-weight: 800;
+ line-height: 1.2;
+ margin-bottom: 16px;
+ letter-spacing: -0.03em;
+}
+.section-sub {
+ color: var(--text-secondary);
+ font-size: 16px;
+ max-width: 620px;
+ line-height: 1.7;
+}
+
+/* ── Stat card ── */
+.stat-card { text-align: center; padding: 24px 16px; }
+.stat-value {
+ font-size: clamp(32px, 4vw, 48px);
+ font-weight: 800;
+ letter-spacing: -0.03em;
+ color: var(--text);
+}
+.stat-label {
+ color: var(--muted);
+ font-size: 12px;
+ margin-top: 4px;
+ text-transform: uppercase;
+ letter-spacing: 0.8px;
+}
+
+/* ── Agent card ── */
+.agent-card {
+ padding: 24px;
+ border-radius: var(--radius-lg);
+ background: var(--surface);
+ border: 1px solid var(--border);
+ box-shadow: var(--shadow-sm);
+ transition: box-shadow var(--transition), border-color var(--transition);
+}
+.agent-card:hover {
+ box-shadow: var(--shadow-md);
+ border-color: #cbd5e1;
+}
+
+/* ── Step number ── */
+.step-num {
+ width: 32px;
+ height: 32px;
+ border-radius: 8px;
+ background: var(--accent-light);
+ color: var(--accent);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: 800;
+ font-size: 13px;
+ flex-shrink: 0;
+}
+
+/* ── Quote table row ── */
+.quote-row {
+ transition: background 0.15s;
+}
+.quote-row:hover {
+ background: #f8fafc;
+}
+
+/* ── Tool chip ── */
+.tool-chip {
+ padding: 5px 12px;
+ border-radius: 6px;
+ background: var(--surface);
+ border: 1px solid var(--border);
+ font-size: 12px;
+ font-family: 'JetBrains Mono', monospace;
+ color: var(--muted);
+ transition: border-color 0.15s, color 0.15s;
+}
+.tool-chip:hover {
+ border-color: var(--accent);
+ color: var(--text-secondary);
+}
+
+/* ── Comparison table row ── */
+.compare-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 14px 20px;
+ border-radius: 8px;
+ font-size: 14px;
+}
diff --git a/landing/app/layout.tsx b/landing/app/layout.tsx
new file mode 100644
index 0000000..0a5bb88
--- /dev/null
+++ b/landing/app/layout.tsx
@@ -0,0 +1,16 @@
+import type { Metadata } from 'next';
+import './globals.css';
+
+export const metadata: Metadata = {
+ title: 'CircuLink — Manufacturing Waste-to-Revenue MCP Platform',
+ description:
+ 'Agentic AI multi-agent MCP platform for Industry 4.0. 6 autonomous agents turn factory waste into verified, matched, transacted revenue.',
+};
+
+export default function RootLayout({ children }: { children: React.ReactNode }) {
+ return (
+
+
{children}
+
+ );
+}
diff --git a/landing/app/not-found.tsx b/landing/app/not-found.tsx
new file mode 100644
index 0000000..657798e
--- /dev/null
+++ b/landing/app/not-found.tsx
@@ -0,0 +1,11 @@
+export default function NotFound() {
+ return (
+
+
Page Not Found
+
The page you are looking for does not exist.
+
+ Return Home
+
+
+ );
+}
diff --git a/landing/app/page.tsx b/landing/app/page.tsx
new file mode 100644
index 0000000..4b77262
--- /dev/null
+++ b/landing/app/page.tsx
@@ -0,0 +1,875 @@
+'use client';
+
+import {
+ Factory,
+ Recycle,
+ Brain,
+ Search,
+ GitMerge,
+ Truck,
+ TrendingUp,
+ ShieldCheck,
+ MapPin,
+ Phone,
+ ArrowRight,
+ Plug,
+ Terminal,
+ Workflow,
+ Zap,
+ Globe,
+ Gauge,
+ ChevronRight,
+ IndianRupee,
+ Quote,
+} from 'lucide-react';
+import dynamic from 'next/dynamic';
+import { SpotlightCard } from '@/components/SpotlightCard';
+import { CountUp } from '@/components/CountUp';
+import { FadeIn } from '@/components/FadeIn';
+import { CodeBlock } from '@/components/CodeBlock';
+
+const Iridescence = dynamic(() => import('@/components/Iridescence'), { ssr: false });
+
+const MCP_URL = 'https://relink-6a64ea0e-aravindco-amrita-university-coimbatore.app.nitrocloud.ai';
+
+export default function Home() {
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+/* ── Nav ── */
+function Nav() {
+ return (
+
+ );
+}
+
+/* ── Hero ── */
+function Hero() {
+ return (
+
+ {/* Iridescence Canvas Background */}
+
+
+
+
+ {/* Radial overlay gradient for seamless text legibility without masking the animation */}
+
+
+
+
+
+
“waste to revenue”
+
+
+
+
+
+ LIVE MCP SERVER — MANUFACTURING & INDUSTRY 4.0
+
+
+
+
+
+ One factory's waste.
+
+ Another's raw material.
+
+
+
+
+
+ Relink is a platform of six autonomous AI agents that sense factory surplus, verify it
+ with vision AI, match buyers across industrial zones, and close the loop — turning
+ manufacturing waste into a revenue stream.
+
+
+
+
+
+
+
+
+
+ {[
+ { value: 4, suffix: 'B+', label: 'Tonnes waste per year' },
+ { value: 15, suffix: '%', label: 'Currently reused' },
+ { value: 500, suffix: 'B+', label: 'Market by 2030', prefix: '$' },
+ { value: 22, suffix: '', label: 'MCP tools live' },
+ ].map((s) => (
+
+
+ {s.prefix}
+
+
+
{s.label}
+
+ ))}
+
+
+
+
+ );
+}
+
+/* ── Problem ── */
+function Problem() {
+ const rows = [
+ { flow: 'Production scheduling', status: 'Optimized', ok: true },
+ { flow: 'Machine health (IoT + predictive maintenance)', status: 'Optimized', ok: true },
+ { flow: 'Quality control (computer vision)', status: 'Optimized', ok: true },
+ { flow: 'Inbound supply chain', status: 'Optimized', ok: true },
+ { flow: 'Waste and byproduct outflow', status: 'Pen, paper and a phone call', ok: false },
+ ];
+
+ return (
+
+
+ The Industry 4.0 Blind Spot
+
+ Every manufacturing flow got digitized.
+
+ Except the one coming out the back door.
+
+
+ Factories run SCADA, MES, and predictive maintenance on every production line — then
+ sell 50 tonnes of monthly scrap to whichever dealer called first, at 30–40% below
+ fair value. That asymmetry costs Indian manufacturing an estimated{' '}
+ ₹25,000 crore every year.
+
+
+
+
+
+ {rows.map((r) => (
+
+ {r.flow}
+
+ {r.status}
+
+
+ ))}
+
+
+
+ );
+}
+
+/* ── Agents ── */
+function Agents() {
+ const agents = [
+ {
+ icon: Factory,
+ name: 'Intake Agent',
+ type: 'Proactive',
+ desc: 'Polls ERP disposal queues, accepts photo uploads, and answers multilingual voice calls from MSME factories. Sellers set their own price.',
+ color: 'var(--emerald)',
+ tag: 'emerald',
+ },
+ {
+ icon: ShieldCheck,
+ name: 'Verification Agent',
+ type: 'Autonomous',
+ desc: 'Gemini Vision grades material health (A/B/C), classifies downstream uses, benchmarks price, and scores seller trust without human intervention.',
+ color: 'var(--accent)',
+ tag: 'blue',
+ },
+ {
+ icon: Search,
+ name: 'Sourcing Agent',
+ type: 'Conversational',
+ desc: 'Natural-language BOM decomposition plus cluster analysis that recommends the best industrial zone to source from based on density, price, and trust.',
+ color: 'var(--violet)',
+ tag: 'violet',
+ },
+ {
+ icon: GitMerge,
+ name: 'Matching Agent',
+ type: 'Autonomous',
+ desc: 'Solves the many-to-many allocation problem — combines sellers to fill one buyer's BOM at minimum cost plus transport.',
+ color: 'var(--amber)',
+ tag: 'amber',
+ },
+ {
+ icon: Truck,
+ name: 'Logistics Agent',
+ type: 'On-demand',
+ desc: 'Google Maps MCP integration for routes, freight estimates, and transporter matching when a buyer requests delivery assistance.',
+ color: 'var(--accent)',
+ tag: 'blue',
+ },
+ {
+ icon: TrendingUp,
+ name: 'Prediction Agent',
+ type: 'Proactive',
+ desc: 'Reads production schedules and forecasts waste before it exists — then pre-notifies matched buyers via WhatsApp. Predictive supply.',
+ color: 'var(--rose)',
+ tag: 'rose',
+ },
+ ];
+
+ return (
+
+
+ Agentic Architecture
+
+ Six autonomous agents.
+
+ One event-driven MCP nervous system.
+
+
+ Each agent is a standalone MCP server. They communicate through Supabase Realtime —
+ when the Intake Agent writes a listing, the Verification Agent wakes up automatically. No
+ polling. No orchestrator bottleneck.
+
+
+
+
+ {agents.map((a, i) => (
+
+
+
+
+
+
{a.name}
+
+ {a.type}
+
+
+
+
+ {a.desc}
+
+
+
+ ))}
+
+
+ );
+}
+
+/* ── MCP Guide ── */
+function McpGuide() {
+ const curlList = `curl ${MCP_URL}/mcp \\
+ -H "Content-Type: application/json" \\
+ -d '{
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "tools/list"
+ }'`;
+
+ const curlCall = `curl ${MCP_URL}/mcp \\
+ -H "Content-Type: application/json" \\
+ -d '{
+ "jsonrpc": "2.0",
+ "id": 2,
+ "method": "tools/call",
+ "params": {
+ "name": "search_materials",
+ "arguments": {
+ "material_type": "aluminum_scrap",
+ "max_price_per_kg": 150,
+ "max_radius_km": 100
+ }
+ }
+ }'`;
+
+ const claudeConfig = `{
+ "mcpServers": {
+ "relink": {
+ "url": "${MCP_URL}/mcp",
+ "transport": "http"
+ }
+ }
+}`;
+
+ const tools = [
+ 'register_seller', 'create_listing_with_price', 'voice_intake_to_listing',
+ 'sync_erp_surplus', 'analyze_material_health', 'classify_material_usage',
+ 'suggest_fair_price', 'calculate_seller_trust_score', 'detect_listing_anomalies',
+ 'search_materials', 'recommend_best_place_to_source', 'get_seller_contact',
+ 'compare_listings', 'find_optimal_matches', 'rank_suppliers_by_multi_objective',
+ 'calculate_route', 'estimate_freight_cost', 'find_nearby_transporters',
+ 'schedule_pickup', 'forecast_waste_generation', 'get_compliance_report',
+ 'calculate_esg_impact',
+ ];
+
+ return (
+
+
+ MCP Integration Guide
+
+ Connect any MCP client in{' '}
+ 60 seconds.
+
+
+ Relink speaks the Model Context Protocol over streamable HTTP. Claude, ChatGPT,
+ NitroStudio, or your own agent framework can discover and call all 22 tools with no SDK
+ lock-in.
+
+
+
+
+
+
+
1
+
Discover the tools
+
+
+
+
+
+
+
+
+
+
+
+
3
+
Wire into your client
+
+
+
+
+
+
+
+
+ All 22 live tools
+
+
+ {tools.map((t) => (
+
+ {t}
+
+ ))}
+
+
+
+
+ );
+}
+
+/* ── Use Cases ── */
+function UseCases() {
+ const cases = [
+ {
+ icon: Factory,
+ title: 'Auto Stamping Plant, Pune',
+ tag: 'SELLER',
+ tagStyle: 'tag-emerald',
+ body: 'Uploads a photo of 500 kg Al-6061 stamping scrap. Gemini Vision grades it B, benchmarks at ₹148/kg. Manager quotes ₹140/kg. Listed in 40 seconds with a GST-verified trust badge.',
+ metric: '₹4,70,000 per year from disposal cost to revenue',
+ },
+ {
+ icon: Search,
+ title: 'Die-Casting Unit, Chakan',
+ tag: 'BUYER',
+ tagStyle: 'tag-blue',
+ body: 'Types “need 500 kg aluminum scrap for die-casting, budget ₹145/kg”. Sourcing Agent recommends the Talegaon zone — 7 sellers, average ₹132/kg, Grade A. Buyer taps “Get Seller Contact” and calls directly.',
+ metric: '₹20,000 saved on a single 2-tonne order',
+ },
+ {
+ icon: Phone,
+ title: 'Fabrication MSME, Coimbatore',
+ tag: 'VOICE',
+ tagStyle: 'tag-violet',
+ body: 'No ERP, no computer. Calls in, speaks in Tamil: “200 kg mild steel offcuts, want ₹28/kg.” The voice agent transcribes, structures, and lists it — the digital divide closed with a phone call.',
+ metric: '63% of Indian manufacturing output is MSME',
+ },
+ {
+ icon: TrendingUp,
+ title: 'Prediction Engine, Every Factory',
+ tag: 'PROACTIVE',
+ tagStyle: 'tag-amber',
+ body: 'The production schedule shows a 10,000-panel batch run Thursday. The Prediction Agent knows that means roughly 500 kg scrap by Friday — and pre-notifies three matched buyers on WhatsApp before the waste exists.',
+ metric: 'Deals done before waste is generated',
+ },
+ ];
+
+ return (
+
+
+ Real Scenarios
+
+ Built for the factory floor,{' '}
+ not the slide deck.
+
+
+
+
+ {cases.map((c, i) => (
+
+
+
+
+
+ {c.title}
+
+
+
+
+ {c.metric}
+
+
+
+
+ ))}
+
+
+ );
+}
+
+/* ── Pricing / Quotes ── */
+function PricingQuotes() {
+ const quotes = [
+ { material: 'Aluminum Scrap (6061)', grade: 'B', seller: 140, benchmark: '135-155', virgin: 230, trend: '+4%', up: true },
+ { material: 'HDPE Regrind', grade: 'A', seller: 32, benchmark: '28-35', virgin: 85, trend: '+2%', up: true },
+ { material: 'Steel Offcut (MS)', grade: 'B', seller: 28, benchmark: '26-34', virgin: 68, trend: '-1%', up: false },
+ { material: 'Copper Wire Scrap', grade: 'B', seller: 620, benchmark: '580-680', virgin: 850, trend: '+6%', up: true },
+ ];
+
+ return (
+
+
+ Live Benchmark Quotes
+
+ Sellers set the price.{' '}
+ AI keeps everyone honest.
+
+
+ Every listing shows the seller's own quoted price next to the independent AI
+ benchmark — protecting uninformed sellers from underpricing and giving buyers a fair
+ reference point.
+
+
+
+
+
+
+ Material
+ Grade
+ Seller
+ AI Benchmark
+ Virgin
+ Trend
+
+ {quotes.map((q) => (
+
+ {q.material}
+
+
+ {q.grade}
+
+
+
+ {q.seller}
+
+
+ {q.benchmark}
+
+
+ {q.virgin}
+
+
+ {q.trend}
+
+
+ ))}
+
+
+
+ );
+}
+
+/* ── Footer ── */
+function Footer() {
+ return (
+
+
+
+
+ The waste stream is the last
+
+ unoptimized flow in manufacturing.
+
+
+ Plug into the MCP server. Let the six agents close the loop.
+
+
+
+
+
+
+ Relink
+
+
+
+ 6 Agents
+
+
+ MCP
+
+
+ Supabase
+
+
+ Gemini
+
+
+ Industry 4.0
+
+
+
Manufacturing & Industry 4.0
+
+
+
+ );
+}
diff --git a/landing/components/CodeBlock.tsx b/landing/components/CodeBlock.tsx
new file mode 100644
index 0000000..e08e866
--- /dev/null
+++ b/landing/components/CodeBlock.tsx
@@ -0,0 +1,53 @@
+'use client';
+
+import { useState } from 'react';
+import { Check, Copy } from 'lucide-react';
+
+export function CodeBlock({
+ code,
+ language,
+ filename,
+}: {
+ code: string;
+ language: string;
+ filename: string;
+}) {
+ const [copied, setCopied] = useState(false);
+
+ const copy = async () => {
+ await navigator.clipboard.writeText(code);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ };
+
+ return (
+
+
+
+
+
+ {filename}
+
+ {copied ? : }
+ {copied ? 'Copied' : 'Copy'}
+
+
+
+ {code}
+
+
+ );
+}
diff --git a/landing/components/CountUp.tsx b/landing/components/CountUp.tsx
new file mode 100644
index 0000000..0b3b8a0
--- /dev/null
+++ b/landing/components/CountUp.tsx
@@ -0,0 +1,57 @@
+'use client';
+
+import { useEffect, useRef, useState } from 'react';
+
+export function CountUp({
+ end,
+ duration = 2000,
+ suffix = '',
+ prefix = '',
+ decimals = 0,
+}: {
+ end: number;
+ duration?: number;
+ suffix?: string;
+ prefix?: string;
+ decimals?: number;
+}) {
+ const [count, setCount] = useState(0);
+ const [started, setStarted] = useState(false);
+ const ref = useRef(null);
+
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting && !started) setStarted(true);
+ },
+ { threshold: 0.3 }
+ );
+ if (ref.current) observer.observe(ref.current);
+ return () => observer.disconnect();
+ }, [started]);
+
+ useEffect(() => {
+ if (!started) return;
+ let startTime: number;
+ let frame: number;
+
+ const animate = (time: number) => {
+ if (!startTime) startTime = time;
+ const progress = Math.min((time - startTime) / duration, 1);
+ const eased = 1 - Math.pow(1 - progress, 3);
+ setCount(eased * end);
+ if (progress < 1) frame = requestAnimationFrame(animate);
+ };
+
+ frame = requestAnimationFrame(animate);
+ return () => cancelAnimationFrame(frame);
+ }, [started, end, duration]);
+
+ return (
+
+ {prefix}
+ {count.toFixed(decimals)}
+ {suffix}
+
+ );
+}
diff --git a/landing/components/FadeIn.tsx b/landing/components/FadeIn.tsx
new file mode 100644
index 0000000..703215e
--- /dev/null
+++ b/landing/components/FadeIn.tsx
@@ -0,0 +1,35 @@
+'use client';
+
+import { motion } from 'framer-motion';
+import type { ReactNode } from 'react';
+
+export function FadeIn({
+ children,
+ delay = 0,
+ direction = 'up',
+ className = '',
+}: {
+ children: ReactNode;
+ delay?: number;
+ direction?: 'up' | 'down' | 'left' | 'right';
+ className?: string;
+}) {
+ const offsets = {
+ up: { y: 40 },
+ down: { y: -40 },
+ left: { x: 40 },
+ right: { x: -40 },
+ };
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/landing/components/Iridescence.tsx b/landing/components/Iridescence.tsx
new file mode 100644
index 0000000..fa0edda
--- /dev/null
+++ b/landing/components/Iridescence.tsx
@@ -0,0 +1,165 @@
+'use client';
+
+import { Renderer, Program, Mesh, Color, Triangle } from 'ogl';
+import { useEffect, useRef, ComponentPropsWithoutRef } from 'react';
+
+interface IridescenceProps extends Omit, 'color'> {
+ color?: [number, number, number] | number[];
+ speed?: number;
+ amplitude?: number;
+ mouseReact?: boolean;
+}
+
+const vertexShader = `
+attribute vec2 uv;
+attribute vec2 position;
+
+varying vec2 vUv;
+
+void main() {
+ vUv = uv;
+ gl_Position = vec4(position, 0, 1);
+}
+`;
+
+const fragmentShader = `
+precision highp float;
+
+uniform float uTime;
+uniform vec3 uColor;
+uniform vec3 uResolution;
+uniform vec2 uMouse;
+uniform float uAmplitude;
+uniform float uSpeed;
+
+varying vec2 vUv;
+
+void main() {
+ float mr = min(uResolution.x, uResolution.y);
+ vec2 uv = (vUv.xy * 2.0 - 1.0) * uResolution.xy / mr;
+
+ uv += (uMouse - vec2(0.5)) * uAmplitude;
+
+ float d = -uTime * 0.5 * uSpeed;
+ float a = 0.0;
+ for (float i = 0.0; i < 8.0; ++i) {
+ a += cos(i - d - a * uv.x);
+ d += sin(uv.y * i + a);
+ }
+ d += uTime * 0.5 * uSpeed;
+ vec3 col = vec3(cos(uv * vec2(d, a)) * 0.6 + 0.4, cos(a + d) * 0.5 + 0.5);
+ col = cos(col * cos(vec3(d, a, 2.5)) * 0.5 + 0.5) * uColor;
+ gl_FragColor = vec4(col, 1.0);
+}
+`;
+
+export default function Iridescence({
+ color = [1, 1, 1],
+ speed = 1.0,
+ amplitude = 0.1,
+ mouseReact = true,
+ className = '',
+ style,
+ ...rest
+}: IridescenceProps) {
+ const ctnDom = useRef(null);
+ const mousePos = useRef({ x: 0.5, y: 0.5 });
+
+ useEffect(() => {
+ if (!ctnDom.current) return;
+ const ctn = ctnDom.current;
+ const renderer = new Renderer({ alpha: true, antialias: true });
+ const gl = renderer.gl;
+
+ let program: Program;
+
+ function resize() {
+ if (!ctn) return;
+ const width = ctn.offsetWidth || ctn.clientWidth || window.innerWidth;
+ const height = ctn.offsetHeight || ctn.clientHeight || window.innerHeight;
+ renderer.setSize(width, height);
+ if (program) {
+ program.uniforms.uResolution.value = new Color(
+ gl.canvas.width,
+ gl.canvas.height,
+ gl.canvas.width / (gl.canvas.height || 1)
+ );
+ }
+ }
+ window.addEventListener('resize', resize, false);
+
+ const resizeObserver = new ResizeObserver(() => resize());
+ resizeObserver.observe(ctn);
+
+ resize();
+
+ const geometry = new Triangle(gl);
+ program = new Program(gl, {
+ vertex: vertexShader,
+ fragment: fragmentShader,
+ uniforms: {
+ uTime: { value: 0 },
+ uColor: { value: new Color(...color) },
+ uResolution: {
+ value: new Color(gl.canvas.width, gl.canvas.height, gl.canvas.width / (gl.canvas.height || 1))
+ },
+ uMouse: { value: new Float32Array([mousePos.current.x, mousePos.current.y]) },
+ uAmplitude: { value: amplitude },
+ uSpeed: { value: speed }
+ }
+ });
+
+ const mesh = new Mesh(gl, { geometry, program });
+ let animateId: number;
+
+ function update(t: number) {
+ animateId = requestAnimationFrame(update);
+ program.uniforms.uTime.value = t * 0.001;
+ renderer.render({ scene: mesh });
+ }
+ animateId = requestAnimationFrame(update);
+
+ gl.canvas.style.display = 'block';
+ gl.canvas.style.width = '100%';
+ gl.canvas.style.height = '100%';
+ gl.canvas.style.position = 'absolute';
+ gl.canvas.style.inset = '0';
+ ctn.appendChild(gl.canvas);
+
+ function handleMouseMove(e: MouseEvent) {
+ const rect = ctn.getBoundingClientRect();
+ const x = (e.clientX - rect.left) / rect.width;
+ const y = 1.0 - (e.clientY - rect.top) / rect.height;
+ mousePos.current = { x, y };
+ program.uniforms.uMouse.value[0] = x;
+ program.uniforms.uMouse.value[1] = y;
+ }
+
+ const targetEl = mouseReact ? window : null;
+ if (targetEl) {
+ targetEl.addEventListener('mousemove', handleMouseMove);
+ }
+
+ return () => {
+ cancelAnimationFrame(animateId);
+ window.removeEventListener('resize', resize);
+ resizeObserver.disconnect();
+ if (targetEl) {
+ targetEl.removeEventListener('mousemove', handleMouseMove);
+ }
+ if (ctn.contains(gl.canvas)) {
+ ctn.removeChild(gl.canvas);
+ }
+ gl.getExtension('WEBGL_lose_context')?.loseContext();
+ };
+ }, [color, speed, amplitude, mouseReact]);
+
+ return (
+
+ );
+}
diff --git a/landing/components/SpotlightCard.tsx b/landing/components/SpotlightCard.tsx
new file mode 100644
index 0000000..bf3145c
--- /dev/null
+++ b/landing/components/SpotlightCard.tsx
@@ -0,0 +1,28 @@
+'use client';
+
+import { useRef, useState, type ReactNode, type MouseEvent } from 'react';
+
+export function SpotlightCard({ children, className = '' }: { children: ReactNode; className?: string }) {
+ const ref = useRef(null);
+ const [position, setPosition] = useState({ x: 50, y: 50 });
+
+ const handleMouseMove = (e: MouseEvent) => {
+ if (!ref.current) return;
+ const rect = ref.current.getBoundingClientRect();
+ setPosition({
+ x: ((e.clientX - rect.left) / rect.width) * 100,
+ y: ((e.clientY - rect.top) / rect.height) * 100,
+ });
+ };
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/landing/next-env.d.ts b/landing/next-env.d.ts
new file mode 100644
index 0000000..830fb59
--- /dev/null
+++ b/landing/next-env.d.ts
@@ -0,0 +1,6 @@
+///
+///
+///
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/landing/next.config.js b/landing/next.config.js
new file mode 100644
index 0000000..ff815fd
--- /dev/null
+++ b/landing/next.config.js
@@ -0,0 +1,12 @@
+import { fileURLToPath } from 'url';
+import { dirname } from 'path';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ images: { unoptimized: true },
+};
+
+export default nextConfig;
diff --git a/landing/package-lock.json b/landing/package-lock.json
new file mode 100644
index 0000000..7944614
--- /dev/null
+++ b/landing/package-lock.json
@@ -0,0 +1,1023 @@
+{
+ "name": "circulink-landing",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "circulink-landing",
+ "version": "1.0.0",
+ "dependencies": {
+ "framer-motion": "^11.0.0",
+ "lucide-react": "^0.460.0",
+ "next": "^15.0.0",
+ "ogl": "^1.0.11",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
+ },
+ "devDependencies": {
+ "@types/node": "^22.0.0",
+ "@types/react": "^19.0.0",
+ "@types/react-dom": "^19.0.0",
+ "typescript": "^5.7.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz",
+ "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@img/colour": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
+ "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
+ "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
+ "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
+ "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
+ "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
+ "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
+ "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-ppc64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
+ "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-riscv64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
+ "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
+ "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
+ "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
+ "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
+ "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
+ "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
+ "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-ppc64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
+ "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-ppc64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-riscv64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
+ "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-riscv64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
+ "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
+ "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
+ "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
+ "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
+ "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.7.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
+ "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
+ "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
+ "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@next/env": {
+ "version": "15.5.22",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.22.tgz",
+ "integrity": "sha512-O5BlKb3KtsHkvO0gjjV66PuJnAgCtIEIzwkt50HRAHsQkU1t77eksIXSZV84/WMtZJjWrnDUPKHVRi0D62nSAA==",
+ "license": "MIT"
+ },
+ "node_modules/@next/swc-darwin-arm64": {
+ "version": "15.5.22",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.22.tgz",
+ "integrity": "sha512-/VISwtffSg8+fVvBbXdglsvruCsdbBC4dG25iU6xascKVqfQKsj/OtjGnOEkIS7pX5GB9e9/r5QprpicsGL3gw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-darwin-x64": {
+ "version": "15.5.22",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.22.tgz",
+ "integrity": "sha512-NiA9ve8hbiuhG/Q17a2mZDRVxMTtg3rTOgjLnDaLlE+AEPAQlkkuKrfePEbeOrgYmX0U2KGX4EVEn09hXU5GlQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-gnu": {
+ "version": "15.5.22",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.22.tgz",
+ "integrity": "sha512-vAPa9vltW+UW/KWtjXeSUFgV3wb1x9d/BeyC6WFI6eBpL0D2f70oGwtOp6193mNW3qusrpgBzMQferPf+Zh8Dw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-musl": {
+ "version": "15.5.22",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.22.tgz",
+ "integrity": "sha512-iknK80pWlNDnkdSr13bd8mMuG3Z2oTxODwsZHvuMY7caMk77+rBLdHVWsy8v2EVa3ZojJ/+wJX5fnq8va6Gv8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-gnu": {
+ "version": "15.5.22",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.22.tgz",
+ "integrity": "sha512-penuEdkwU2OOAiS+n4LE8T/VIoCfAI01QcLZTJ2xc3+l4Q22L/DzURocmI2LU1b+8BMQoLAP1Sze3uYAZT05Bg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-musl": {
+ "version": "15.5.22",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.22.tgz",
+ "integrity": "sha512-ZM0BKJm3FZ+guG6WT6PcyOLtp6paZ5tngcJC/uUKvLW4Y0TQnnVi1+UGdo8Q6Yxp5gaS82pmC1rD/oFlhkWB3g==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-arm64-msvc": {
+ "version": "15.5.22",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.22.tgz",
+ "integrity": "sha512-rY/YaumrZaS0//94BnHLF5VSRp0GFUO4GvXNuoCBb0cGSci96yO+p1JaNL2aq9YZAYv9cuZRziV02x5IQH/wjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-x64-msvc": {
+ "version": "15.5.22",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.22.tgz",
+ "integrity": "sha512-s5IA4cyrbR2XK/5NWcu5dp8CfPBiKME+UhvNperia7uQybEgg5+LIhGMiY37WQE4rcI4owsDcU4IVUjLoTuDkA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.5.15",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
+ "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.8.0"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "22.20.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz",
+ "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.17",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
+ "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.3",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
+ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001806",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz",
+ "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/client-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
+ "license": "MIT"
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/framer-motion": {
+ "version": "11.18.2",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz",
+ "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^11.18.1",
+ "motion-utils": "^11.18.1",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/lucide-react": {
+ "version": "0.460.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.460.0.tgz",
+ "integrity": "sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/motion-dom": {
+ "version": "11.18.1",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz",
+ "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-utils": "^11.18.1"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "11.18.1",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz",
+ "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==",
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.16",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
+ "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/next": {
+ "version": "15.5.22",
+ "resolved": "https://registry.npmjs.org/next/-/next-15.5.22.tgz",
+ "integrity": "sha512-mrtal1sRxO4YrlDS98sDuIvGZivKbFix8w7oAL9ZynfOgc3cADQOQgvwtMooc18Qr8bKzvQAcHwHZ0mbJ7zcfQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@next/env": "15.5.22",
+ "@swc/helpers": "0.5.15",
+ "caniuse-lite": "^1.0.30001579",
+ "postcss": "8.4.31",
+ "styled-jsx": "5.1.6"
+ },
+ "bin": {
+ "next": "dist/bin/next"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
+ },
+ "optionalDependencies": {
+ "@next/swc-darwin-arm64": "15.5.22",
+ "@next/swc-darwin-x64": "15.5.22",
+ "@next/swc-linux-arm64-gnu": "15.5.22",
+ "@next/swc-linux-arm64-musl": "15.5.22",
+ "@next/swc-linux-x64-gnu": "15.5.22",
+ "@next/swc-linux-x64-musl": "15.5.22",
+ "@next/swc-win32-arm64-msvc": "15.5.22",
+ "@next/swc-win32-x64-msvc": "15.5.22",
+ "sharp": "^0.34.3"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.1.0",
+ "@playwright/test": "^1.51.1",
+ "babel-plugin-react-compiler": "*",
+ "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+ "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+ "sass": "^1.3.0"
+ },
+ "peerDependenciesMeta": {
+ "@opentelemetry/api": {
+ "optional": true
+ },
+ "@playwright/test": {
+ "optional": true
+ },
+ "babel-plugin-react-compiler": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ogl": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ogl/-/ogl-1.0.11.tgz",
+ "integrity": "sha512-kUpC154AFfxi16pmZUK4jk3J+8zxwTWGPo03EoYA8QPbzikHoaC82n6pNTbd+oEaJonaE8aPWBlX7ad9zrqLsA==",
+ "license": "Unlicense"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "node_modules/postcss": {
+ "version": "8.4.31",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+ "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.2.8",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
+ "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.8",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz",
+ "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.8"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "optional": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/sharp": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
+ "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "@img/colour": "^1.0.0",
+ "detect-libc": "^2.1.2",
+ "semver": "^7.7.3"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.34.5",
+ "@img/sharp-darwin-x64": "0.34.5",
+ "@img/sharp-libvips-darwin-arm64": "1.2.4",
+ "@img/sharp-libvips-darwin-x64": "1.2.4",
+ "@img/sharp-libvips-linux-arm": "1.2.4",
+ "@img/sharp-libvips-linux-arm64": "1.2.4",
+ "@img/sharp-libvips-linux-ppc64": "1.2.4",
+ "@img/sharp-libvips-linux-riscv64": "1.2.4",
+ "@img/sharp-libvips-linux-s390x": "1.2.4",
+ "@img/sharp-libvips-linux-x64": "1.2.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
+ "@img/sharp-linux-arm": "0.34.5",
+ "@img/sharp-linux-arm64": "0.34.5",
+ "@img/sharp-linux-ppc64": "0.34.5",
+ "@img/sharp-linux-riscv64": "0.34.5",
+ "@img/sharp-linux-s390x": "0.34.5",
+ "@img/sharp-linux-x64": "0.34.5",
+ "@img/sharp-linuxmusl-arm64": "0.34.5",
+ "@img/sharp-linuxmusl-x64": "0.34.5",
+ "@img/sharp-wasm32": "0.34.5",
+ "@img/sharp-win32-arm64": "0.34.5",
+ "@img/sharp-win32-ia32": "0.34.5",
+ "@img/sharp-win32-x64": "0.34.5"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/styled-jsx": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
+ "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
+ "license": "MIT",
+ "dependencies": {
+ "client-only": "0.0.1"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ },
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ }
+ }
+}
diff --git a/landing/package.json b/landing/package.json
new file mode 100644
index 0000000..6caa133
--- /dev/null
+++ b/landing/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "circulink-landing",
+ "version": "1.0.0",
+ "type": "module",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start"
+ },
+ "dependencies": {
+ "framer-motion": "^11.0.0",
+ "lucide-react": "^0.460.0",
+ "next": "^15.0.0",
+ "ogl": "^1.0.11",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
+ },
+ "devDependencies": {
+ "@types/node": "^22.0.0",
+ "@types/react": "^19.0.0",
+ "@types/react-dom": "^19.0.0",
+ "typescript": "^5.7.0"
+ }
+}
diff --git a/landing/tsconfig.json b/landing/tsconfig.json
new file mode 100644
index 0000000..f5fc2f7
--- /dev/null
+++ b/landing/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [{ "name": "next" }],
+ "paths": { "@/*": ["./*"] }
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "exclude": ["node_modules"]
+}