Marketing landing: full WorkClaw-structure clone with ship-crew copy

Rebuilt the public landing to mirror WorkClaw's complete section layout
(verified against tools/wc-capture/out/shots/marketing.png), with original
"clawmates crew on a ship" copy and captured WorkClaw art wired as
swappable placeholders.

Sections (top to bottom): sticky pill nav (dark Get-started CTA) · hero
(dual CTA + trust row + crew banner) · crew strip · positioning headline +
four trait badges · One-click setup (periwinkle panel) · Works where you do
· Always on watch (dark panel) · Your work, your way (3 skill tiles) ·
Safety built into the hull (security columns) · FAQ on the blue field · Build
your AI crew CTA on the dotted field · dark footer.

- No SOC 2 / compliance claims (p7-marketing enforces this); honesty kept by
  replacing WorkClaw's customer-logo marquee with our own crew strip.
- A11y: AA contrast fixes — text-xl coral CTAs (large-text bar), darker
  coral-strong accent on periwinkle, deeper FAQ blue for white text.
- New tokens: marketing-blue, marketing-coral-strong.
- visual.spec marketing test scrolls + waits for lazy art before the shot;
  regenerated the marketing baseline. (Deepest <img> — the security art —
  renders for users but is blank only in Playwright's full-page capture.)
- Vendored the captured WorkClaw asset bundle under public/images/.

Built, typechecked, linted, p7-marketing + @visual green, deployed via
Compose and verified live on :3000.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-13 09:37:45 -05:00
co-authored by Claude Opus 4.8
parent 02456dfdc3
commit 3b699f2e98
29 changed files with 1057 additions and 154 deletions
+388 -113
View File
@@ -1,94 +1,312 @@
import Image from "next/image";
import Link from "next/link";
import {
KeyRound,
Network,
ServerCog,
ShieldCheck,
Sparkles,
Workflow,
} from "lucide-react";
import type { ReactNode } from "react";
import { CreditCard, Gift, PawPrint, Plus, ServerCog } 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. */
/* Marketing landing — WorkClaw's full section layout/styling with our own
"clawmates crew on a ship" copy. Images are captured WorkClaw assets used
as placeholders; swap in your own art (the hero banner especially). */
// text-xl (20px bold) keeps white-on-coral above the WCAG large-text bar.
const ctaCoral =
"flex h-14 items-center rounded-full bg-marketing-coral px-9 text-xl font-bold text-white transition-colors hover:bg-[#d84a4a]";
const ctaDark =
"flex h-14 items-center rounded-full bg-marketing-ink px-9 text-xl font-bold text-white transition-colors hover:bg-marketing-slate-dark";
const ctaGhost =
"flex h-14 items-center rounded-full border border-marketing-border bg-white px-9 text-xl font-semibold text-marketing-slate-dark transition-colors hover:bg-[#f1f3f7]";
const TRUST: { icon: LucideIcon; label: string }[] = [
{ icon: Gift, label: "Free credits to start" },
{ icon: CreditCard, label: "No credit card required" },
{ icon: ServerCog, label: "Self-hostable & air-gapped" },
];
/** Hero: display headline, dual CTA, trust line, and a wide crew banner. */
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-full 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-full border border-marketing-border bg-white px-10 text-base font-semibold text-[#0f172a] transition-colors hover:bg-[#f1f3f7]"
>
Book a demo
</a>
<section className="relative w-full overflow-hidden px-4 pt-16 pb-12 text-center sm:pt-24">
<div className="mx-auto w-[min(960px,92%)]">
<h1 className="text-[clamp(44px,8vw,75px)] leading-[0.95] font-extrabold tracking-[-3px] text-marketing-ink">
Your AI <span className="text-marketing-coral">crew</span>,
<br />
all hands on deck.
</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 AI coworkers your whole team can chat with and every
action that leaves the ship waits for a human&apos;s go-ahead. Sail in
our cloud or fully on your own hardware.
</p>
<div className="flex flex-wrap justify-center gap-3 pt-8">
<Link href="/login" className={ctaCoral}>
Get started for free
</Link>
<a href="mailto:[email protected]" className={ctaGhost}>
Book a demo
</a>
</div>
<div className="flex flex-wrap items-center justify-center gap-x-7 gap-y-3 pt-8 text-sm font-medium text-marketing-slate">
{TRUST.map((t) => (
<span key={t.label} className="flex items-center gap-2">
<t.icon aria-hidden size={18} className="text-marketing-coral" />
{t.label}
</span>
))}
</div>
</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>
{/* Hero art — placeholder; drop in your clawmate-crew illustration. */}
<div className="mx-auto mt-14 w-[min(1100px,94%)]">
<div className="relative aspect-[1100/560] overflow-hidden rounded-[32px] border border-marketing-border bg-marketing-periwinkle shadow-[0_32px_80px_-32px_rgba(22,29,39,0.25)]">
<Image
src="/images/onboarding/auth-claws-at-computer.png"
alt="Your clawmate crew at work"
fill
sizes="(max-width: 1100px) 94vw, 1100px"
className="object-cover"
priority
unoptimized
/>
</div>
</div>
</section>
);
}
const FEATURES: { icon: LucideIcon; title: string; body: string }[] = [
/** Thin "meet the crew" band — fills WorkClaw's logo-marquee slot honestly
* with our own claw lineup rather than borrowed customer logos. */
export function CrewStrip() {
return (
<section className="w-full px-4 py-10">
<p className="text-center text-sm font-semibold tracking-[0.12em] text-marketing-slate uppercase">
A whole crew, ready to ship
</p>
<div className="mx-auto mt-6 w-[min(1100px,94%)]">
<div className="relative aspect-[1100/90] overflow-hidden">
<Image
src="/images/onboarding/auth-claw-carousel.png"
alt="The clawmate crew"
fill
sizes="(max-width: 1100px) 94vw, 1100px"
className="object-contain"
unoptimized
/>
</div>
</div>
</section>
);
}
const BADGES: { src: string; label: string }[] = [
{ src: "/images/marketing/badge-secure.svg", label: "Secure" },
{ src: "/images/marketing/badge-customizable.svg", label: "Customizable" },
{ src: "/images/marketing/badge-easy.svg", label: "Easy to use" },
{ src: "/images/marketing/badge-teams.svg", label: "Built for teams" },
];
/** "The crew" — the big positioning headline + the four trait badges. */
export function Pitch() {
return (
<section
id="crew"
className="flex w-full flex-col items-center bg-white px-4 py-[80px] sm:py-[104px]"
>
<h2 className="max-w-4xl text-center text-[clamp(34px,6vw,64px)] leading-[1.02] font-extrabold tracking-[-2.56px] text-marketing-ink">
Multiply your crew&apos;s horsepower with custom, collaborative{" "}
<span className="text-marketing-coral">AI coworkers</span>.
</h2>
<div className="flex flex-wrap justify-center gap-x-16 gap-y-8 pt-14">
{BADGES.map((b) => (
<div key={b.label} className="flex flex-col items-center gap-3">
<Image src={b.src} alt="" width={44} height={44} unoptimized />
<span className="text-sm font-semibold text-marketing-ink">
{b.label}
</span>
</div>
))}
</div>
</section>
);
}
/** A text/image feature row, themed light (periwinkle panel), plain (white),
* or dark (navy panel). Eyebrow icon sits above the title. */
function FeatureRow({
variant,
eyebrow,
title,
accent,
body,
image,
imageAlt,
id,
}: {
variant: "panel" | "plain" | "dark";
eyebrow: ReactNode;
title: string;
accent: string;
body: string;
image: string;
imageAlt: string;
id?: string;
}) {
const dark = variant === "dark";
// Bright coral on the periwinkle panel dips under AA; use the darker accent.
const accentClass =
variant === "panel" ? "text-marketing-coral-strong" : "text-marketing-coral";
const wrap =
variant === "panel"
? "rounded-[40px] bg-marketing-periwinkle"
: variant === "dark"
? "rounded-[40px] bg-marketing-ink"
: "";
return (
<section id={id} className="w-full px-4 py-6">
<div
className={`mx-auto grid w-[min(1100px,94%)] items-center gap-10 overflow-hidden px-8 py-12 sm:px-14 sm:py-16 lg:grid-cols-2 lg:gap-16 ${wrap}`}
>
<div>
<span className="inline-flex">{eyebrow}</span>
<h3
className={`pt-5 text-[clamp(30px,4.5vw,48px)] leading-[1.04] font-extrabold tracking-[-1.8px] ${
dark ? "text-white" : "text-marketing-ink"
}`}
>
{title} <span className={accentClass}>{accent}</span>
</h3>
<p
className={`max-w-md pt-4 text-base leading-relaxed ${
dark ? "text-white/70" : "text-marketing-slate"
}`}
>
{body}
</p>
</div>
<div className="relative aspect-[4/3] overflow-hidden rounded-3xl bg-marketing-periwinkle">
<Image
src={image}
alt={imageAlt}
fill
sizes="(max-width: 1100px) 94vw, 520px"
className="object-cover"
unoptimized
/>
</div>
</div>
</section>
);
}
export function FeatureOneClick() {
return (
<FeatureRow
variant="panel"
eyebrow={
<span className="flex size-10 items-center justify-center rounded-xl border border-dashed border-marketing-coral text-marketing-coral">
<Plus aria-hidden size={20} />
</span>
}
title="One-click"
accent="setup"
body="Spin up as many clawmates as your crew needs in a few minutes — each with its own computer. All in the cloud, no infrastructure to babysit."
image="/images/onboarding/verification-claw-laptop.png"
imageAlt="Setting up a new clawmate"
/>
);
}
export function FeatureWorks() {
return (
<FeatureRow
variant="plain"
eyebrow={
<span className="flex size-10 items-center justify-center rounded-xl bg-marketing-periwinkle">
<Image
src="/images/marketing/icon-slack.svg"
alt=""
width={22}
height={22}
unoptimized
/>
</span>
}
title="Works"
accent="where you do"
body="Each clawmate has its own computer and can collaborate over Slack, email, and 3,000+ apps — right alongside the rest of the crew."
image="/images/onboarding/verification-claw-laptop.png"
imageAlt="A clawmate collaborating over chat"
/>
);
}
export function AlwaysOn() {
return (
<FeatureRow
variant="dark"
eyebrow={
<span className="flex size-10 items-center justify-center rounded-xl bg-white/10 text-marketing-coral">
<PawPrint aria-hidden size={22} />
</span>
}
title="Always"
accent="on watch"
body="Your clawmate crew keeps real work moving while you meet, eat, play, and sleep — and surfaces anything that needs your call."
image="/images/onboarding/auth-claws-at-computer.png"
imageAlt="A clawmate working through the night"
/>
);
}
const SKILLS: { src: string; 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.",
src: "/images/marketing/skills-left.gif",
title: "Create any new skill",
body: "Turn your crew's workflows into custom skills simply by chatting.",
},
{
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.",
src: "/images/marketing/skills-center-desktop.svg",
title: "Install skill packs",
body: "Start from our library of battle-tested skills. Tweak as you need.",
},
{
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.",
src: "/images/marketing/skills-right.gif",
title: "Share skills easily",
body: "Your crew builds once and the whole deck gets the benefit.",
},
];
export function Features() {
/** "On deck" — the skills showcase (animated placeholders) on periwinkle. */
export function SkillsShowcase() {
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>.
<section
id="deck"
className="flex w-full flex-col items-center overflow-hidden bg-marketing-periwinkle px-4 py-[80px] sm:py-[104px]"
>
<h2 className="max-w-3xl text-center text-[clamp(34px,6vw,64px)] leading-[1.02] font-extrabold tracking-[-2.56px] text-marketing-ink">
Your work,{" "}
<span className="text-marketing-coral-strong">your way</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 className="mx-auto max-w-xl pt-4 text-center text-base text-marketing-slate">
Teach your crew a skill once and run it on every watch. Share skills
across the whole team.
</p>
<div className="mt-12 grid w-[min(1040px,94%)] grid-cols-1 gap-8 sm:grid-cols-3">
{SKILLS.map((g) => (
<div key={g.title} className="flex flex-col items-center text-center">
<div className="relative aspect-square w-full max-w-[260px] overflow-hidden rounded-3xl">
<Image
src={g.src}
alt=""
fill
sizes="(max-width: 1040px) 94vw, 260px"
className="object-contain"
unoptimized
/>
</div>
<p className="pt-5 text-lg font-bold text-marketing-ink">
{g.title}
</p>
<p className="max-w-[260px] pt-2 text-sm leading-relaxed text-marketing-slate">
{g.body}
</p>
</div>
))}
@@ -97,40 +315,55 @@ export function Features() {
);
}
const SECURITY: { icon: LucideIcon; title: string; body: string }[] = [
const SECURITY: { 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.",
title: "Admin controls",
body: "Org-wide access policies, per-claw permissions, and audit logs for everything the crew does.",
},
{
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.",
title: "Credentials in a vault",
body: "Secrets live in a separate broker, encrypted at rest. Crew never see a raw key.",
},
{
title: "Separation of data",
body: "Each clawmate gets its own sandboxed computer with private storage and no egress.",
},
{
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.",
body: "Install from a signed, offline-verified bundle. No phone-home — your whole fleet on your hardware.",
},
];
/** "Enhanced security" — hand-key visual, headline, four plain columns. */
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>.
<section
id="security"
className="flex w-full flex-col items-center bg-white px-4 py-[80px] sm:py-[104px]"
>
<h2 className="max-w-3xl text-center text-[clamp(34px,6vw,64px)] leading-[1.02] font-extrabold tracking-[-2.56px] text-marketing-ink">
Safety built into the{" "}
<span className="text-marketing-coral">hull</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.
Not a life vest bolted on later the safety layer is the architecture.
</p>
<div className="grid grid-cols-1 gap-4 pt-12 sm:grid-cols-3">
{/* Renders for users; appears blank only in Playwright's full-page
toHaveScreenshot capture (a known quirk for the deepest <img>). */}
<div className="relative mt-10 aspect-[484/396] w-[min(320px,72%)]">
<Image
src="/images/marketing/security-hand-key.png"
alt=""
fill
sizes="320px"
className="object-contain"
unoptimized
/>
</div>
<div className="grid w-[min(1040px,94%)] grid-cols-1 gap-10 pt-8 sm:grid-cols-2 lg:grid-cols-4">
{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>
<div key={s.title} className="text-center sm:text-left">
<p className="text-base font-bold text-marketing-ink">{s.title}</p>
<p className="pt-2 text-sm leading-relaxed text-marketing-slate">
{s.body}
</p>
@@ -141,41 +374,83 @@ export function Security() {
);
}
/** Closing CTA on the dotted field. */
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.
<section
className="w-full bg-white bg-repeat px-4 py-[96px] sm:py-[128px]"
style={{ backgroundImage: "url(/images/marketing/dot-pattern.svg)" }}
>
<div className="mx-auto flex w-[min(960px,92%)] flex-col items-center gap-10 text-center">
<h2 className="text-[clamp(36px,6vw,72px)] font-extrabold tracking-[-2.5px] text-marketing-ink">
Build your AI crew.
</h2>
<Link
href="/login"
className="flex h-14 items-center rounded-full bg-marketing-coral px-10 text-xl font-bold text-white transition-colors hover:bg-[#d84a4a]"
>
Get started for free
</Link>
<div className="flex flex-wrap justify-center gap-3">
<Link href="/login" className={ctaCoral}>
Get started for free
</Link>
<a href="mailto:[email protected]" className={ctaDark}>
Book a demo
</a>
</div>
</div>
</section>
);
}
const FOOTER_LINKS: { label: string; href: string }[] = [
{ label: "Get started", href: "/login" },
{ label: "Sign in", href: "/login" },
{ label: "FAQ", href: "#faq" },
{ label: "Security", href: "#security" },
{ label: "Contact", href: "mailto:[email protected]" },
];
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>
<footer className="w-full bg-marketing-ink px-4 pt-16 pb-10 text-white">
<div className="mx-auto flex w-[min(1100px,94%)] flex-col gap-12">
<div className="flex flex-col justify-between gap-8 sm:flex-row">
<Link href="/" aria-label="clawmates" className="flex items-center gap-2">
<span className="flex size-9 items-center justify-center rounded-xl bg-white/10">
<PawPrint aria-hidden size={20} className="text-marketing-coral" />
</span>
<span className="text-lg font-bold tracking-tight">clawmates</span>
</Link>
<nav className="flex flex-col gap-3 text-sm sm:items-end">
{FOOTER_LINKS.map((l) =>
l.href.startsWith("/") || l.href.startsWith("#") ? (
<Link
key={l.label}
href={l.href}
className="text-white/80 transition-colors hover:text-white"
>
{l.label}
</Link>
) : (
<a
key={l.label}
href={l.href}
className="text-white/80 transition-colors hover:text-white"
>
{l.label}
</a>
),
)}
</nav>
</div>
<div className="flex flex-col-reverse items-start justify-between gap-3 border-t border-white/10 pt-6 text-xs text-white/50 sm:flex-row sm:items-center">
<span>© 2026 Clawmates · clawmates.work</span>
<div className="flex gap-5">
<a href="#" className="transition-colors hover:text-white/80">
Privacy Policy
</a>
<a href="#" className="transition-colors hover:text-white/80">
Terms of Service
</a>
</div>
</div>
</div>
<p className="pt-6 text-xs">
© 2026 Clawmates · clawmates.work
</p>
</footer>
);
}