R5: marketing landing — light-theme public site at /

A new (marketing) route group with its own LIGHT layout (slate palette +
marketing coral #E95656 + periwinkle cards on near-white), the inverse of
the dark app. The middleware rewrites '/' → /marketing for logged-out
visitors (keyed on the session cookie / Clerk __session); authed users
fall through to the workspace app unchanged.

Built to the measured marketing system with OUR copy and honest claims —
NO SOC 2 / compliance badges: floating white pill nav, the 75px/800/-3px
display hero with a single coral keyword span, dual pill CTAs (coral
primary / white-bordered secondary), trust badges ('free credits',
'no credit card', 'self-hostable & air-gapped'), periwinkle feature
cards, a structural-security section (approval-gated, broker-held creds,
air-gappable — our real differentiators), an interactive FAQ accordion,
CTA band, and footer.

E2E (p7-marketing): renders for logged-out visitors, FAQ accordion works,
asserts NO SOC 2 claim, and an axe pass (coral CTAs sized to clear the
AA large-text threshold). p0-shell updated: logged-out '/' now shows
marketing with a Sign-in link to /login.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-10 20:13:09 -05:00
co-authored by Claude Fable 5
parent 1bfbccf172
commit 200bb56299
8 changed files with 409 additions and 7 deletions
+68
View File
@@ -0,0 +1,68 @@
"use client";
import { ChevronDown } from "lucide-react";
import { useState } from "react";
const FAQS: { q: string; a: string }[] = [
{
q: "What is a claw?",
a: "A claw is an AI coworker — an agent with a job, a chat, and its own sandboxed computer. Your team talks to it like a teammate, and it uses tools to get work done.",
},
{
q: "How do you keep agents safe?",
a: "Every action that reaches outside the sandbox — sending an email, posting to Slack, a transaction — is intercepted and held until a human approves it, with the exact payload shown. Agent code runs in a locked-down container with no network.",
},
{
q: "Can I run it on my own infrastructure?",
a: "Yes. The same container images deploy to Kubernetes or to a single-node Docker Compose appliance you can run fully air-gapped, installed from a signed bundle that verifies offline.",
},
{
q: "Which tools can claws connect to?",
a: "Slack and email today, plus a growing app directory you connect with API keys or OAuth. Credentials are held by a separate secret broker the agent can never read.",
},
{
q: "How is my data protected?",
a: "Credentials are encrypted at rest in an isolated broker process; agent sandboxes have no egress; and in the air-gapped deployment nothing ever leaves your network.",
},
];
/** FAQ accordion (measured): one open at a time, chevron rotates. */
export function Faq() {
const [open, setOpen] = useState<number | null>(0);
return (
<section id="faq" className="mx-auto w-[min(760px,92%)] py-16">
<h2 className="text-center text-[clamp(30px,5vw,48px)] font-extrabold tracking-[-1.5px]">
Questions, <span className="text-marketing-coral">answered</span>.
</h2>
<div className="flex flex-col gap-3 pt-10">
{FAQS.map((item, i) => (
<div
key={item.q}
className="rounded-2xl border border-marketing-border bg-white"
>
<button
type="button"
aria-expanded={open === i}
onClick={() => setOpen(open === i ? null : i)}
className="flex w-full items-center justify-between gap-4 px-6 py-4 text-left text-base font-semibold"
>
{item.q}
<ChevronDown
aria-hidden
size={18}
className={`shrink-0 text-marketing-slate transition-transform duration-normal ease-app ${
open === i ? "rotate-180" : ""
}`}
/>
</button>
{open === i && (
<p className="px-6 pb-5 text-sm leading-relaxed text-marketing-slate">
{item.a}
</p>
)}
</div>
))}
</div>
</section>
);
}
+38
View File
@@ -0,0 +1,38 @@
import Link from "next/link";
/** Floating white pill nav (measured): wordmark left, links center,
* auth pills right. Our brand, our links. */
export function MarketingNav() {
return (
<header className="sticky top-4 z-50 mx-auto flex w-[min(960px,92%)] items-center justify-between rounded-radius-button bg-white px-5 py-2.5 shadow-[0_8px_30px_-12px_rgba(22,29,39,0.18)] ring-1 ring-marketing-border">
<Link href="/" className="font-mono text-lg font-semibold tracking-tight">
clawmates
</Link>
<nav className="hidden gap-6 text-sm font-medium sm:flex">
<a href="#features" className="hover:text-marketing-coral">
Product
</a>
<a href="#security" className="hover:text-marketing-coral">
Security
</a>
<a href="#faq" className="hover:text-marketing-coral">
FAQ
</a>
</nav>
<div className="flex items-center gap-2">
<Link
href="/login"
className="rounded-radius-button px-4 py-2 text-sm font-medium hover:bg-[#f1f3f7]"
>
Sign in
</Link>
<Link
href="/login"
className="rounded-radius-button bg-marketing-slate-dark px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-[#0f172a]"
>
Get started
</Link>
</div>
</header>
);
}
@@ -0,0 +1,181 @@
import Link from "next/link";
import {
KeyRound,
Network,
ServerCog,
ShieldCheck,
Sparkles,
Workflow,
} from "lucide-react";
import type { LucideIcon } from "lucide-react";
/** Hero (measured display scale): 75px/800/-3px, one coral keyword span,
* our copy, dual pill CTA, honest trust badges. */
export function Hero() {
return (
<section className="mx-auto w-[min(960px,92%)] pt-20 pb-16 text-center">
<h1 className="text-[clamp(44px,8vw,75px)] leading-[0.92] font-extrabold tracking-[-3px]">
<span className="text-marketing-coral">AI coworkers</span>
<br />
that actually ship work.
</h1>
<p className="mx-auto max-w-2xl pt-6 text-[clamp(17px,2.4vw,21.9px)] leading-snug font-medium text-marketing-slate">
Clawmates are agents your whole team can chat with and every
action that reaches the outside world waits for a human&apos;s
approval. Run them in our cloud or fully air-gapped on your own
hardware.
</p>
<div className="flex flex-wrap justify-center gap-3 pt-8">
<Link
href="/login"
className="flex h-14 items-center rounded-radius-button bg-marketing-coral px-10 text-xl font-bold text-white transition-colors hover:bg-[#d84a4a]"
>
Get started for free
</Link>
<a
href="mailto:[email protected]"
className="flex h-14 items-center rounded-radius-button border border-marketing-border bg-white px-10 text-base font-semibold text-[#0f172a] transition-colors hover:bg-[#f1f3f7]"
>
Book a demo
</a>
</div>
<div className="flex flex-wrap justify-center gap-x-6 gap-y-2 pt-8 text-sm text-marketing-slate">
<span> Free credits to start</span>
<span> No credit card required</span>
<span> Self-hostable &amp; air-gapped</span>
</div>
</section>
);
}
const FEATURES: { icon: LucideIcon; title: string; body: string }[] = [
{
icon: ShieldCheck,
title: "Human-in-the-loop",
body: "Every outbound message, email, or transaction is intercepted and waits for explicit approval — with the exact payload shown.",
},
{
icon: ServerCog,
title: "Run it anywhere",
body: "The same images deploy to Kubernetes or a single-node, fully offline appliance. Your data never has to leave your network.",
},
{
icon: Network,
title: "Works where you do",
body: "Slack, email, and a growing app directory — connect the tools your claws need, with credentials held in a separate secret broker.",
},
{
icon: Workflow,
title: "Built for teams",
body: "Claws are shared, with per-claw access policies, an org chart, routines, and a usage leaderboard for the whole workspace.",
},
];
export function Features() {
return (
<section id="features" className="mx-auto w-[min(960px,92%)] py-16">
<h2 className="text-center text-[clamp(34px,6vw,64px)] leading-[1.02] font-extrabold tracking-[-2.56px]">
Multiply your team&apos;s <span className="text-marketing-coral">brainpower</span>.
</h2>
<div className="grid grid-cols-1 gap-4 pt-12 sm:grid-cols-2">
{FEATURES.map((f) => (
<div
key={f.title}
className="rounded-3xl bg-marketing-periwinkle p-8"
>
<span className="flex size-11 items-center justify-center rounded-2xl bg-white">
<f.icon aria-hidden size={20} className="text-marketing-coral" />
</span>
<p className="pt-5 text-xl font-bold">{f.title}</p>
<p className="pt-2 text-sm leading-relaxed text-marketing-slate">
{f.body}
</p>
</div>
))}
</div>
</section>
);
}
const SECURITY: { icon: LucideIcon; title: string; body: string }[] = [
{
icon: ShieldCheck,
title: "Approval-gated by design",
body: "Sensitive actions can never fire without a recorded human decision — proven by our own concurrency soak tests.",
},
{
icon: KeyRound,
title: "Credentials in a broker",
body: "Secrets live in a separate process, encrypted at rest. Agents never see a raw key; the broker injects them.",
},
{
icon: ServerCog,
title: "Air-gappable",
body: "Install from a signed, offline-verified bundle. No phone-home, no required internet — your whole stack on your hardware.",
},
];
export function Security() {
return (
<section id="security" className="mx-auto w-[min(960px,92%)] py-16">
<h2 className="text-center text-[clamp(34px,6vw,64px)] leading-[1.02] font-extrabold tracking-[-2.56px]">
Security that&apos;s <span className="text-marketing-coral">structural</span>.
</h2>
<p className="mx-auto max-w-xl pt-4 text-center text-base text-marketing-slate">
Not a checkbox bolted on later the safety layer is the architecture.
</p>
<div className="grid grid-cols-1 gap-4 pt-12 sm:grid-cols-3">
{SECURITY.map((s) => (
<div key={s.title} className="rounded-3xl border border-marketing-border bg-white p-7">
<span className="flex size-11 items-center justify-center rounded-2xl bg-marketing-periwinkle">
<s.icon aria-hidden size={20} className="text-marketing-coral" />
</span>
<p className="pt-5 text-lg font-bold">{s.title}</p>
<p className="pt-2 text-sm leading-relaxed text-marketing-slate">
{s.body}
</p>
</div>
))}
</div>
</section>
);
}
export function CtaBand() {
return (
<section className="mx-auto w-[min(960px,92%)] py-16">
<div className="flex flex-col items-center gap-6 rounded-[32px] bg-marketing-slate-dark px-8 py-16 text-center text-white">
<Sparkles aria-hidden size={28} className="text-marketing-coral" />
<h2 className="text-[clamp(30px,5vw,48px)] font-extrabold tracking-[-1.5px]">
Build your AI team today.
</h2>
<Link
href="/login"
className="flex h-14 items-center rounded-radius-button bg-marketing-coral px-10 text-xl font-bold text-white transition-colors hover:bg-[#d84a4a]"
>
Get started for free
</Link>
</div>
</section>
);
}
export function Footer() {
return (
<footer className="mx-auto w-[min(960px,92%)] border-t border-marketing-border py-10 text-sm text-marketing-slate">
<div className="flex flex-wrap items-center justify-between gap-4">
<span className="font-mono font-semibold text-marketing-ink">
clawmates
</span>
<nav className="flex flex-wrap gap-5">
<Link href="/login">Sign in</Link>
<a href="mailto:[email protected]">Contact</a>
<a href="#faq">FAQ</a>
</nav>
</div>
<p className="pt-6 text-xs">
© 2026 Clawmates · clawmates.work
</p>
</footer>
);
}