Files
OpenFrame/components/LandingPage.tsx
T
yusufipk 6c6df3cf1d feat: hosted-first landing + accurate fair source licensing copy
- Replace unsubstantiated hero claim with client sign-off messaging
- Rename Open Source (Self-hosted) to Fair Source (Self-hosted) with FSL
  explanation (source visible, self-hostable, Apache 2.0 after two years)
- Put Hosted Cloud first in pricing with Recommended badge and trial note
- Move self-hosting hero link to GitHub, out of primary CTA path
- Add FAQ entries for FSL licensing and 7-day free trial
- Align license language across landing, README, terms, SEO, comparisons
- Fix contact email to [email protected] everywhere (mailto links,
  notification sender fallbacks) and SEO fallback domain
2026-07-12 18:32:38 +07:00

957 lines
43 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import Image from 'next/image';
import Link from 'next/link';
import { MarketingCompareLinks } from '@/components/marketing/marketing-compare-links';
import { useEffect, useRef } from 'react';
import { gsap } from 'gsap';
import {
Video,
MoveRight,
Play,
Mic,
PenTool,
Keyboard,
BellRing,
FolderOpen,
FileDown,
History,
Smartphone,
Link as LinkIcon,
CheckSquare,
MessageSquare,
Github,
ArrowRight,
XCircle,
ArrowDown,
CheckCircle,
Upload,
Share2,
Check,
} from 'lucide-react';
interface LandingPageProps {
isLoggedIn: boolean;
}
const controlButtonClass =
'group relative isolate inline-flex h-8 items-center justify-center overflow-hidden border border-border bg-background px-2.5 text-[11px] font-medium text-foreground transition-colors duration-300 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:h-9 sm:px-4 sm:text-xs';
const coreWorkflowFeatures = [
{
title: 'Version Compare',
description: 'Compare any two versions side-by-side on a single timeline.',
icon: History,
},
{
title: 'Asset Management',
description: 'Keep images and supplementary videos grouped perfectly per cut.',
icon: FolderOpen,
},
{
title: 'Version History',
description: 'Infinite versioning. Toggle between V1 and V10 without losing where you are.',
icon: History,
},
{
title: 'Approval Workflow',
description:
'Assign specific team members or clients to review and sign off on a cut. Get an exact \"Approved\" status.',
icon: CheckCircle,
},
];
const workflowAcceleratorFeatures = [
{
title: 'Keyboard Shortcuts',
description: 'J, K, L, Space, and M controls for professional editing workflows.',
icon: Keyboard,
},
{
title: 'PDF/CSV Exports',
description: 'Turn video comments into a professional feedback report in one click.',
icon: FileDown,
},
{
title: 'Real-time Webhooks',
description:
'Get instant Telegram alerts the second a comment is dropped. More integrations coming soon.',
icon: BellRing,
},
{
title: 'Mobile-Optimized Review',
description: 'Touch-optimized player for clients reviewing cuts on the move.',
icon: Smartphone,
},
];
export function LandingPage({ isLoggedIn }: LandingPageProps) {
const rootRef = useRef<HTMLDivElement | null>(null);
const navbarRef = useRef<HTMLElement | null>(null);
const hostedCtaHref = isLoggedIn ? '/dashboard' : '/register';
useEffect(() => {
const cleanupHandlers: Array<() => void> = [];
const ctx = gsap.context(() => {
// General Reveal Animations
gsap.from('[data-hero-copy]', {
y: 40,
opacity: 0,
duration: 1,
stagger: 0.15,
ease: 'power4.out',
});
// Voice Notes Waveform Animation
const waveformBars = gsap.utils.toArray<HTMLElement>('.voice-bar');
waveformBars.forEach((bar, index) => {
gsap.set(bar, { transformOrigin: 'center bottom' });
gsap.to(bar, {
scaleY: gsap.utils.random(0.3, 1.5),
duration: gsap.utils.random(0.4, 0.8),
repeat: -1,
yoyo: true,
delay: index * 0.05,
ease: 'power2.inOut',
});
});
// Navbar Scroll Effect
const nav = navbarRef.current;
if (nav) {
const updateNavbar = () => {
const hasScrolled = window.scrollY > 20;
gsap.to(nav, {
backgroundColor: hasScrolled
? 'color-mix(in oklab, var(--background) 85%, transparent)'
: 'transparent',
backdropFilter: hasScrolled ? 'blur(16px)' : 'blur(0px)',
borderBottomColor: hasScrolled ? 'var(--border)' : 'transparent',
duration: 0.3,
overwrite: 'auto',
});
};
updateNavbar();
window.addEventListener('scroll', updateNavbar, { passive: true });
cleanupHandlers.push(() => window.removeEventListener('scroll', updateNavbar));
}
}, rootRef);
return () => {
cleanupHandlers.forEach((cleanup) => cleanup());
ctx.revert();
};
}, []);
return (
<div
ref={rootRef}
className="min-h-screen overflow-x-hidden bg-background text-foreground font-sans selection:bg-primary/20"
>
{/* Header */}
<header
ref={navbarRef}
className="fixed inset-x-0 top-0 z-50 border-b border-transparent bg-transparent transition-colors duration-300"
>
<div className="mx-auto flex h-14 w-full max-w-[1200px] items-center justify-between px-4 sm:h-16 sm:px-6 lg:px-10">
<Link
href="/"
className="group relative isolate inline-flex items-center gap-2 overflow-hidden border border-border bg-background px-3 py-2"
>
<span className="pointer-events-none absolute inset-0 -translate-x-[101%] bg-primary/10 transition-transform duration-300 group-hover:translate-x-0" />
<Video className="relative z-10 h-4 w-4 text-primary" />
<span className="relative z-10 text-xs font-semibold tracking-[0.12em]">OPENFRAME</span>
</Link>
<nav className="hidden items-center gap-6 text-[11px] font-medium uppercase tracking-[0.14em] md:flex">
<Link
className="text-muted-foreground transition-colors hover:text-foreground"
href="#features"
>
Features
</Link>
<Link
className="text-muted-foreground transition-colors hover:text-foreground"
href="#pricing"
>
Pricing
</Link>
<a
className="text-muted-foreground transition-colors hover:text-foreground"
href="https://github.com/yusufipk/OpenFrame"
target="_blank"
rel="noreferrer"
>
GitHub
</a>
<a
className="text-muted-foreground transition-colors hover:text-foreground"
href="mailto:[email protected]"
>
Contact
</a>
</nav>
<div className="flex items-center gap-2">
{isLoggedIn ? (
<Link href="/dashboard" className={controlButtonClass}>
<span className="pointer-events-none absolute inset-0 -translate-x-[101%] bg-primary/10 transition-transform duration-300 group-hover:translate-x-0" />
<span className="relative z-10 inline-flex items-center gap-2">
Dashboard
<MoveRight className="h-3.5 w-3.5" />
</span>
</Link>
) : (
<>
<Link
href="/login"
className="text-xs font-medium text-muted-foreground hover:text-foreground hidden sm:block mr-4"
>
Log in
</Link>
<Link href="/register" className={controlButtonClass}>
<span className="pointer-events-none absolute inset-0 -translate-x-[101%] bg-primary/10 transition-transform duration-300 group-hover:translate-x-0" />
<span className="relative z-10">Get Started Free</span>
</Link>
</>
)}
</div>
</div>
</header>
<main className="relative">
{/* 1) HERO */}
<section className="relative flex min-h-[95vh] flex-col items-center justify-center px-4 pb-20 pt-32 text-center sm:px-6 lg:px-8">
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top,_var(--tw-gradient-stops))] from-primary/5 via-background to-background" />
<div className="relative z-10 mx-auto max-w-[1000px] space-y-8">
<div
data-hero-copy
className="inline-flex items-center gap-2 border border-border/50 bg-secondary/30 px-3 py-1.5 text-xs text-muted-foreground backdrop-blur-md"
>
<span className="relative flex h-2 w-2">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75"></span>
<span className="relative inline-flex h-2 w-2 rounded-full bg-primary"></span>
</span>
<span className="font-mono tracking-wide uppercase">Fair Source Video Review</span>
</div>
<h1
data-hero-copy
className="text-4xl font-semibold leading-[0.95] tracking-[-0.03em] sm:text-5xl md:text-6xl lg:text-7xl"
>
Get Client Sign-off From One Link. <br className="hidden md:block" />
<span className="text-muted-foreground">Stop Chasing Timecodes.</span>
</h1>
<p
data-hero-copy
className="mx-auto max-w-2xl text-base text-muted-foreground md:text-xl"
>
Hosted video review for editors, agencies, and small studios. Comments, voice notes,
and annotations land on one timeline clients review in the browser, no account
needed.
</p>
<div
data-hero-copy
className="mx-auto flex max-w-md flex-col items-center justify-center gap-3"
>
<Link
href={hostedCtaHref}
className="group relative isolate inline-flex h-12 min-w-max items-center justify-center overflow-hidden border border-primary bg-primary px-10 text-sm font-medium whitespace-nowrap text-primary-foreground transition-transform duration-300 hover:scale-[1.02]"
>
Start free trial
<MoveRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
</Link>
<p className="text-xs text-muted-foreground">
7-day free trial · Flat $10/mo no per-seat fees · No client accounts
</p>
<a
href="https://github.com/yusufipk/OpenFrame"
target="_blank"
rel="noreferrer"
className="text-xs font-medium text-muted-foreground/70 transition-colors hover:text-foreground"
>
Prefer self-hosting? View on GitHub{' '}
<ArrowRight className="ml-1 inline h-3 w-3" />
</a>
</div>
</div>
<div data-hero-copy className="relative mx-auto mt-20 w-full max-w-[1200px]">
<div className="relative aspect-[16/9] w-full overflow-hidden border border-border bg-card shadow-2xl rounded-lg">
<Image
src="/landing/deep-dive-dashboard-2.webp"
alt="Product Interface Preview"
fill
className="object-cover"
priority
/>
<div className="absolute inset-0 bg-gradient-to-t from-background/90 via-transparent to-transparent pointer-events-none" />
{/* Toolbar floating UI */}
<div className="absolute bottom-6 left-1/2 z-20 flex -translate-x-1/2 items-center gap-2 border border-border/80 bg-background/90 p-2 backdrop-blur-md shadow-xl">
<button className="flex h-8 w-8 items-center justify-center bg-primary text-primary-foreground hover:bg-primary/90">
<PenTool className="h-4 w-4" />
</button>
<div className="h-6 w-px bg-border" />
<button className="flex h-8 w-8 items-center justify-center text-muted-foreground hover:bg-secondary hover:text-foreground">
<MessageSquare className="h-4 w-4" />
</button>
<button className="flex h-8 w-8 items-center justify-center text-muted-foreground hover:bg-secondary hover:text-foreground">
<Mic className="h-4 w-4" />
</button>
</div>
</div>
</div>
</section>
{/* 2) PROBLEM BLOCK */}
<section className="border-y border-border bg-card/10 px-4 py-16 sm:px-6 lg:px-8">
<div className="mx-auto w-full max-w-[1200px]">
<div className="mx-auto max-w-4xl">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Feedback chaos looks like this:
</h2>
<ul className="mt-8 space-y-4 text-base text-muted-foreground md:text-lg">
<li className="flex items-start gap-3">
<XCircle className="mt-1 h-5 w-5 shrink-0 text-red-500/80" />
<span>Comments spread across WhatsApp, email, and random screenshots.</span>
</li>
<li className="flex items-start gap-3">
<XCircle className="mt-1 h-5 w-5 shrink-0 text-red-500/80" />
<span>&quot;Around 1:12&quot; turns into 10 minutes of guessing.</span>
</li>
<li className="flex items-start gap-3">
<XCircle className="mt-1 h-5 w-5 shrink-0 text-red-500/80" />
<span>Nobody knows which version is actually the latest.</span>
</li>
<li className="flex items-start gap-3">
<XCircle className="mt-1 h-5 w-5 shrink-0 text-red-500/80" />
<span>One unclear note becomes a full extra revision round.</span>
</li>
</ul>
<div className="mt-10 border-l-2 border-primary/50 pl-4">
<p className="text-base text-foreground md:text-lg">
OpenFrame replaces all of that with one link, one timeline, one source of truth.
</p>
</div>
</div>
</div>
</section>
{/* 3) HOW IT WORKS */}
<section className="border-b border-border bg-background px-4 py-20 sm:px-6 lg:px-8">
<div className="mx-auto w-full max-w-[1200px]">
<div className="mb-16 text-center">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
From upload to approval in one flow.
</h2>
</div>
<div className="grid gap-4 md:grid-cols-4 relative">
{[
{ label: 'Upload a cut', icon: Upload },
{ label: 'Share a review link', icon: Share2 },
{ label: 'Get timestamped feedback', icon: MessageSquare },
{ label: 'Mark approved and move on', icon: Check },
].map((step, idx, arr) => (
<div key={step.label} className="group relative flex flex-col items-center">
<div className="flex flex-col items-center justify-center w-full min-h-[100px] md:aspect-[4/3] border border-border bg-card/20 px-4 py-6 md:p-6 text-center relative z-10 transition-all duration-300 group-hover:border-primary/40 group-hover:bg-card/40">
<div className="mb-4 flex h-8 w-8 md:h-10 md:w-10 items-center justify-center bg-secondary/50 text-primary border border-border/50 transition-colors group-hover:bg-primary/10">
<step.icon className="h-4 w-4 md:h-5 md:w-5" />
</div>
<p className="text-sm font-medium text-foreground md:text-base leading-tight">
{step.label}
</p>
<div className="absolute top-3 right-3 font-mono text-[10px] text-muted-foreground/30">
0{idx + 1}
</div>
</div>
{idx < arr.length - 1 && (
<div className="hidden md:flex absolute top-1/2 -right-4 -translate-y-1/2 z-20 items-center justify-center text-muted-foreground/20">
<MoveRight className="h-5 w-5" />
</div>
)}
{idx < arr.length - 1 && (
<div className="md:hidden flex py-4 text-muted-foreground/20">
<ArrowDown className="h-5 w-5" />
</div>
)}
</div>
))}
</div>
</div>
</section>
{/* 4) FEATURES */}
<section id="features" className="scroll-mt-20 border-t border-border bg-card/10">
{/* Feature 1 */}
<div className="border-b border-border">
<div className="mx-auto flex w-full max-w-[1200px] flex-col-reverse items-center justify-between gap-12 px-4 py-20 sm:px-6 lg:flex-row lg:px-8 lg:py-32">
<div data-reveal className="w-full lg:w-1/2 relative">
<div className="relative aspect-[16/10] w-full border border-border/50 bg-background overflow-hidden">
<Image
src="/landing/compare-v2.webp"
alt="Comparison Mode"
fill
className="object-cover object-left-top"
sizes="(min-width: 1024px) 50vw, 100vw"
/>
<div className="absolute inset-0 bg-background/5" />
</div>
</div>
<div data-reveal className="w-full lg:w-1/2 space-y-6">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Compare versions side-by-side. End &quot;which cut is this?&quot;
</h2>
<p className="text-base text-muted-foreground md:text-lg">
See what actually changed between versions then approve with confidence.
</p>
<p className="text-xs uppercase tracking-[0.14em] text-primary">
Cuts revision cycles.
</p>
</div>
</div>
</div>
{/* Feature 2 */}
<div className="border-b border-border bg-background">
<div className="mx-auto flex w-full max-w-[1200px] flex-col items-center justify-between gap-12 px-4 py-20 sm:px-6 lg:flex-row lg:px-8 lg:py-32">
<div data-reveal className="w-full lg:w-1/2 space-y-6">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Explain it better with Voice.
</h2>
<p className="text-base text-muted-foreground md:text-lg">
No more &quot;What did you mean by this?&quot; emails. Every note lands at the
exact moment in the video.
</p>
<p className="text-xs uppercase tracking-[0.14em] text-primary">
Faster feedback. Fewer misunderstandings.
</p>
</div>
<div data-reveal className="w-full lg:w-1/2">
<div className="border border-border bg-card p-6">
<div className="border border-border/50 bg-background p-6">
<div className="flex items-start justify-between">
<div className="flex items-center gap-3">
<div className="flex h-8 w-8 items-center justify-center bg-secondary font-mono text-xs">
Y
</div>
<div className="space-y-1">
<p className="font-mono text-[11px] font-medium leading-none">
Yusuf İpek
</p>
<p className="font-mono text-[10px] text-muted-foreground">00:03:45</p>
</div>
</div>
<span className="inline-block h-2 w-2 animate-pulse rounded-full bg-red-500" />
</div>
<div className="mt-6 flex h-16 items-center gap-1 overflow-hidden">
<button className="mr-2 flex h-8 w-8 flex-none items-center justify-center bg-primary text-primary-foreground hover:bg-primary/90">
<Play className="h-3 w-3" />
</button>
{Array.from({ length: 40 }).map((_, i) => (
<span
key={i}
className="voice-bar w-full flex-1 bg-primary/60"
style={{
height: `${[30, 80, 50, 90, 40, 70, 60, 45, 85, 55, 65, 35, 95, 75, 25, 40, 80, 50, 90, 30][i % 20]}%`,
}}
/>
))}
</div>
</div>
</div>
</div>
</div>
</div>
{/* Feature 3 */}
<div className="border-b border-border">
<div className="mx-auto flex w-full max-w-[1200px] flex-col-reverse items-center justify-between gap-12 px-4 py-20 sm:px-6 lg:flex-row lg:px-8 lg:py-32">
<div
data-reveal
className="w-full lg:w-1/2 relative aspect-video bg-card border border-border p-4"
>
<div className="relative h-full w-full border border-border/50 overflow-hidden bg-background">
<Image
src="https://images.unsplash.com/photo-1542204165-65bf26472b9b?auto=format&fit=crop&w=800&q=80"
alt="Annotate"
fill
className="object-cover opacity-70"
/>
<svg
className="absolute inset-0 h-full w-full pointer-events-none"
viewBox="0 0 800 450"
fill="none"
>
<circle
cx="500"
cy="225"
r="80"
stroke="#06b6d4"
strokeWidth="4"
className="opacity-90 drop-shadow-[0_0_8px_rgba(6,182,212,0.8)]"
/>
<path
d="M500 145 Q550 80 620 120"
stroke="#06b6d4"
strokeWidth="4"
className="opacity-90"
strokeLinecap="round"
/>
</svg>
{/* Circle Editor UI mock */}
<div className="absolute top-4 left-4 border border-border/50 bg-background/90 backdrop-blur-md p-2 flex flex-col gap-2">
<div className="flex gap-2">
<div className="h-6 w-6 rounded-full bg-red-500 cursor-pointer border-2 border-transparent"></div>
<div className="h-6 w-6 rounded-full bg-yellow-500 cursor-pointer border-2 border-transparent"></div>
<div className="h-6 w-6 rounded-full bg-green-500 cursor-pointer border-2 border-transparent"></div>
<div className="h-6 w-6 rounded-full bg-[#06b6d4] cursor-pointer border-2 border-white"></div>
</div>
<div className="h-px w-full bg-border/50" />
<div className="flex gap-2">
<button className="flex h-8 w-8 items-center justify-center text-muted-foreground bg-primary/10 text-primary hover:bg-secondary">
<PenTool className="h-4 w-4" />
</button>
<button className="flex h-8 w-8 items-center justify-center text-muted-foreground hover:bg-secondary">
<MoveRight className="h-4 w-4" />
</button>
</div>
</div>
</div>
</div>
<div data-reveal className="w-full lg:w-1/2 space-y-6">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Point. Draw. Done.
</h2>
<p className="text-base text-muted-foreground md:text-lg">
Precise feedback that leaves zero room for error. Circle, sketch, and point
directly on the video frame.
</p>
<p className="text-xs uppercase tracking-[0.14em] text-primary">
Stops &quot;I thought you meant...&quot;
</p>
</div>
</div>
</div>
</section>
{/* 5) EVERYTHING YOUR TEAM EXPECTS */}
<section className="border-b border-border px-4 py-20 sm:px-6 lg:px-8 lg:py-32 bg-background">
<div className="mx-auto w-full max-w-[1200px]">
<div data-reveal className="mb-12 flex flex-col items-center text-center">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Everything a real production workflow needs.
</h2>
<p className="mt-4 max-w-2xl text-base text-muted-foreground">
The core tools teams expect without the complexity that slows clients down.
</p>
</div>
<div className="space-y-10">
<div>
<p
data-reveal
className="mb-4 text-xs uppercase tracking-[0.14em] text-muted-foreground"
>
Core workflow
</p>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{coreWorkflowFeatures.map((feat) => (
<div
key={feat.title}
data-reveal
className="group border border-border bg-card p-6 transition-colors hover:border-primary/50 hover:bg-card/80"
>
<feat.icon className="mb-4 h-6 w-6 text-primary" />
<h3 className="mb-2 text-lg font-medium">{feat.title}</h3>
<p className="text-sm text-muted-foreground">{feat.description}</p>
</div>
))}
</div>
</div>
<div>
<p
data-reveal
className="mb-4 text-xs uppercase tracking-[0.14em] text-muted-foreground"
>
Workflow Accelerators
</p>
<div className="grid gap-4 sm:grid-cols-2">
{workflowAcceleratorFeatures.map((feat) => (
<div
key={feat.title}
data-reveal
className="group border border-border bg-card p-6 transition-colors hover:border-primary/50 hover:bg-card/80"
>
<feat.icon className="mb-4 h-6 w-6 text-primary" />
<h3 className="mb-2 text-lg font-medium">{feat.title}</h3>
<p className="text-sm text-muted-foreground">{feat.description}</p>
</div>
))}
</div>
</div>
</div>
</div>
</section>
{/* 6) BUILT FOR CLIENTS */}
<section className="border-b border-border bg-card/20 px-4 py-20 sm:px-6 lg:px-8 lg:py-32">
<div className="mx-auto flex w-full max-w-[1200px] flex-col lg:flex-row gap-12 lg:items-center">
<div data-reveal className="lg:w-1/2 space-y-6">
<h2 className="text-4xl font-semibold tracking-[-0.02em] md:text-5xl">
Clients don&apos;t need an account. They just review.
</h2>
<p className="text-lg text-muted-foreground">
If clients can&apos;t adopt the tool, approvals don&apos;t happen. OpenFrame keeps
it frictionless.
</p>
</div>
<div data-reveal className="lg:w-1/2 space-y-4">
<div className="flex items-start gap-4 border border-border bg-background p-6 transition-transform hover:-translate-y-1">
<LinkIcon className="mt-1 h-6 w-6 shrink-0 text-primary" />
<div>
<h3 className="text-lg font-semibold">One link. Review in the browser.</h3>
</div>
</div>
<div className="flex items-start gap-4 border border-border bg-background p-6 transition-transform hover:-translate-y-1">
<Smartphone className="mt-1 h-6 w-6 shrink-0 text-primary" />
<div>
<h3 className="text-lg font-semibold">Works great on mobile.</h3>
</div>
</div>
<div className="flex items-start gap-4 border border-border bg-background p-6 transition-transform hover:-translate-y-1">
<MessageSquare className="mt-1 h-6 w-6 shrink-0 text-primary" />
<div>
<h3 className="text-lg font-semibold">
Timestamped notes that are impossible to miss.
</h3>
</div>
</div>
</div>
</div>
</section>
{/* 7) PRICING */}
<section
id="pricing"
className="border-b border-border bg-[#0a0a0a] px-4 py-20 sm:px-6 lg:px-8 lg:py-32"
>
<div className="mx-auto w-full max-w-[1200px]">
<div data-reveal className="mb-16">
<h2
className="text-3xl font-semibold md:text-5xl text-foreground"
style={{ fontFamily: 'monospace', letterSpacing: '-0.02em' }}
>
Let us run it for you - or deploy it yourself.
</h2>
</div>
<div className="grid gap-6 md:grid-cols-3">
{/* Card 1: Hosted Cloud (recommended) */}
<div
data-reveal
className="relative flex flex-col border border-[#06b6d4]/40 bg-[#141414] p-8"
>
<span className="absolute -top-3 left-8 bg-[#06b6d4] px-2 py-0.5 font-mono text-[10px] font-semibold uppercase tracking-widest text-black">
Recommended
</span>
<div className="mb-6">
<p className="font-mono text-[10px] uppercase font-semibold text-muted-foreground tracking-widest mb-4">
Zero setup. Flat pricing, no per-seat fees.
</p>
<h3 className="text-xl font-semibold text-foreground">Hosted Cloud</h3>
</div>
<div className="mb-2 flex items-baseline gap-2">
<span className="text-3xl font-semibold text-[#06b6d4]">$10</span>
<span className="text-[#06b6d4]">/ month</span>
</div>
<p className="mb-6 text-sm text-muted-foreground">
Starts with a 7-day free trial. Cancel anytime.
</p>
<ul className="mb-8 flex-1 space-y-4 text-sm text-foreground/80">
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Unlimited collaborators</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Timestamped comments + voice notes</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Annotations + version compare</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Share links with permissions</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Exports (PDF/CSV)</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Unlimited YouTube Video Imports</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Download original uploaded video</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Includes: 200 GB Storage</span>
</li>
</ul>
<p className="mb-8 text-sm text-muted-foreground">
Need more storage? Add 100 GB for $5/mo.
</p>
<Link
href={hostedCtaHref}
className="mt-auto group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden bg-[#06b6d4] font-medium text-black transition-colors hover:bg-[#06b6d4]/90 text-sm"
>
Start free trial
</Link>
</div>
{/* Card 2: Fair Source (Self-hosted) */}
<div
data-reveal
className="relative flex flex-col border border-border/40 bg-[#141414] p-8"
>
<div className="mb-6">
<h3 className="text-xl font-semibold text-foreground">
Fair Source (Self-hosted)
</h3>
</div>
<div className="mb-8 flex items-baseline gap-2">
<span className="text-3xl font-semibold text-[#06b6d4]">Free</span>
</div>
<p className="mb-8 text-sm text-muted-foreground">
For teams who want full control and can run their own infrastructure. Licensed
under the{' '}
<a
href="https://fsl.software/"
target="_blank"
rel="noreferrer"
className="underline underline-offset-2 hover:text-foreground"
>
Functional Source License
</a>
.
</p>
<ul className="mb-8 flex-1 space-y-4 text-sm text-foreground/80">
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 h-4 w-4 shrink-0 text-[#06b6d4]" />
Full source code read it, audit it
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 h-4 w-4 shrink-0 text-[#06b6d4]" />
Self-host on your own infrastructure
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 h-4 w-4 shrink-0 text-[#06b6d4]" />
Every release becomes Apache 2.0 open source after two years
</li>
</ul>
<a
href="https://github.com/yusufipk/OpenFrame"
target="_blank"
rel="noreferrer"
className="mt-auto group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden border border-border/50 bg-[#0a0a0a] font-medium text-foreground transition-colors hover:bg-white/5 text-sm"
>
<Github className="mr-2 h-4 w-4" /> View on GitHub
</a>
</div>
{/* Card 3: Studio & Agency */}
<div
data-reveal
className="relative flex flex-col border border-border/40 bg-[#141414] p-8"
>
<div className="mb-6">
<h3 className="text-xl font-semibold text-foreground">
Need more than the standard limits?
</h3>
</div>
<div className="mb-6 flex items-baseline gap-2">
<span className="text-3xl font-semibold text-[#06b6d4]">Let&apos;s talk</span>
</div>
<p className="mb-8 text-sm text-foreground/80 leading-relaxed">
Custom capacity and setup help for high-volume production teams. Tell us your
storage, usage, and workflow - we&apos;ll recommend the right approach.
</p>
<a
href="mailto:[email protected]"
className="group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden bg-[#0a0a0a] font-medium text-foreground transition-colors hover:bg-white/5 border border-border/50 text-sm"
>
Contact us
</a>
</div>
</div>
</div>
</section>
{/* 8) SECURITY & PRIVACY */}
<section className="border-b border-border bg-background px-4 py-20 sm:px-6 lg:px-8 lg:py-24">
<div className="mx-auto w-full max-w-[1200px]">
<div data-reveal className="mx-auto max-w-4xl">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Security & privacy, by design.
</h2>
<ul className="mt-8 space-y-4 text-base text-muted-foreground md:text-lg">
<li>- Permissioned share links (control who can view/comment)</li>
<li>- Private-by-default projects</li>
<li>- Delete videos and projects anytime</li>
<li>- Self-host option for full data control</li>
</ul>
</div>
</div>
</section>
{/* 9) FAQ */}
<section className="border-b border-border bg-card/10 px-4 py-20 sm:px-6 lg:px-8 lg:py-24">
<div className="mx-auto w-full max-w-[1200px]">
<div data-reveal className="mx-auto max-w-4xl">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">FAQ</h2>
<div className="mt-10 space-y-4">
{[
{
q: 'Do clients need an account?',
a: 'No. They can review in the browser with a share link.',
},
{
q: 'What happens if I exceed my storage?',
a: "You can add 100 GB for $5/mo. If you need much more, contact us at [email protected] and we'll help you choose the best setup.",
},
{
q: 'How is YouTube unlimited?',
a: 'There is no storage limit on YouTube imports. You can import an unlimited amount of unlisted YouTube videos and use all of our review features exactly the same.',
},
{
q: 'Can I self-host?',
a: 'Yes. The full source code is public and ships with a Docker setup for self-hosting. Hosted Cloud is for teams who want zero setup.',
},
{
q: 'Is OpenFrame open source?',
a: 'OpenFrame is Fair Source, licensed under the Functional Source License (FSL). You can read and audit the full source code and self-host it, and every release automatically becomes Apache 2.0 open source two years after publication.',
},
{
q: 'Is there a free trial?',
a: 'Yes. Hosted Cloud starts with a 7-day free trial. After that it is a flat $10/mo — no per-seat or per-client fees.',
},
{
q: 'How is this different from sending a Google Drive link?',
a: 'Drive doesnt give timestamped discussion, voice notes, annotations, or version compare, which is where approval time is actually saved.',
},
{
q: 'Is it mobile-friendly?',
a: 'Yes. Clients can review and comment from mobile.',
},
{
q: 'Can I export feedback?',
a: 'Yes. Export to PDF/CSV for archiving or client handoff.',
},
{
q: 'Who can access my videos?',
a: 'Only people you invite or share a link with (based on permissions you set).',
},
{
q: 'Can I cancel anytime?',
a: 'Yes. Cancel anytime from your billing settings.',
},
].map((item) => (
<div key={item.q} className="border border-border bg-background p-6">
<h3 className="text-lg font-semibold">{item.q}</h3>
<p className="mt-2 text-sm text-muted-foreground md:text-base">{item.a}</p>
</div>
))}
</div>
</div>
</div>
</section>
{/* 10) FINAL CTA STRIP */}
<section className="border-b border-border bg-background px-4 py-16 sm:px-6 lg:px-8">
<div
data-reveal
className="mx-auto flex w-full max-w-[1200px] flex-col items-center justify-between gap-4 text-center md:flex-row md:text-left"
>
<div>
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-4xl">
Stop chasing feedback. Start getting approvals.
</h2>
<p className="mt-2 text-sm text-muted-foreground">
Your first review link takes minutes.
</p>
</div>
<Link
href={hostedCtaHref}
className="group relative isolate inline-flex h-12 min-w-max items-center justify-center overflow-hidden border border-primary bg-primary px-10 text-sm font-medium whitespace-nowrap text-primary-foreground transition-transform duration-300 hover:scale-[1.02] md:min-w-[240px]"
>
Start free trial
</Link>
</div>
</section>
</main>
<footer className="border-t border-border bg-background px-4 py-8 sm:px-6 lg:px-8">
<div className="mx-auto grid max-w-[1200px] gap-8 sm:grid-cols-2 lg:grid-cols-3">
<div className="flex items-start gap-2">
<Video className="mt-0.5 h-4 w-4 shrink-0 text-primary" />
<span className="font-mono text-xs text-muted-foreground">
© 2026 IPEK TECH LLC. All rights reserved.
</span>
</div>
<MarketingCompareLinks />
<div className="flex flex-col gap-2">
<span className="font-mono text-[10px] uppercase tracking-wider text-muted-foreground">
Legal
</span>
<div className="flex flex-col gap-1.5">
<a
href="mailto:[email protected]"
className="text-xs text-muted-foreground hover:text-foreground"
>
info@open-frame.net
</a>
<a
href="https://github.com/yusufipk/OpenFrame"
className="text-xs text-muted-foreground hover:text-foreground"
>
GitHub
</a>
<Link href="/terms" className="text-xs text-muted-foreground hover:text-foreground">
Terms
</Link>
<Link href="/privacy" className="text-xs text-muted-foreground hover:text-foreground">
Privacy
</Link>
<Link href="/refund" className="text-xs text-muted-foreground hover:text-foreground">
Refund Policy
</Link>
</div>
</div>
</div>
</footer>
</div>
);
}