Profile Social
Original · freesocial profile with follow
Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.
npx shadcn@latest add https://webinnoventix.com/r/profile-social.json"use client";
import { useCallback, useEffect, useId, useRef, useState } from "react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
type SocialLink = {
id: string;
label: string;
href: string;
text: string;
icon: "globe" | "mail" | "calendar";
};
type Mutual = {
initials: string;
name: string;
tone: string;
};
const BASE_FOLLOWERS = 18402;
const BASE_LIKES = 342;
const LINKS: SocialLink[] = [
{
id: "site",
label: "Open fieldnotes.email in a new tab",
href: "https://example.com",
text: "fieldnotes.email",
icon: "globe",
},
{
id: "mail",
label: "Email Nadia Rahman",
href: "mailto:hello@example.com",
text: "hello@fieldnotes.email",
icon: "mail",
},
];
const MUTUALS: Mutual[] = [
{ initials: "PR", name: "Priya Raman", tone: "from-indigo-500 to-violet-500" },
{ initials: "DO", name: "Dan Okafor", tone: "from-emerald-500 to-sky-500" },
{ initials: "LM", name: "Lena Moreau", tone: "from-rose-500 to-amber-500" },
{ initials: "KT", name: "Kofi Tetteh", tone: "from-sky-500 to-indigo-500" },
];
const TOPICS = ["Decision-making", "Team process", "Writing", "Post-mortems"];
function formatCount(n: number): string {
return n.toLocaleString("en-US");
}
function Icon({ name, className }: { name: SocialLink["icon"]; className: string }) {
if (name === "globe") {
return (
<svg viewBox="0 0 20 20" aria-hidden="true" className={className} fill="none" stroke="currentColor" strokeWidth="1.5">
<circle cx="10" cy="10" r="7.25" />
<path d="M2.9 10h14.2M10 2.75c1.9 2 2.85 4.4 2.85 7.25S11.9 15.25 10 17.25c-1.9-2-2.85-4.4-2.85-7.25S8.1 4.75 10 2.75z" />
</svg>
);
}
if (name === "mail") {
return (
<svg viewBox="0 0 20 20" aria-hidden="true" className={className} fill="none" stroke="currentColor" strokeWidth="1.5">
<rect x="2.75" y="4.75" width="14.5" height="10.5" rx="2" />
<path d="M3.25 6.2l6.75 4.8 6.75-4.8" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
}
return (
<svg viewBox="0 0 20 20" aria-hidden="true" className={className} fill="none" stroke="currentColor" strokeWidth="1.5">
<rect x="2.75" y="4.25" width="14.5" height="13" rx="2" />
<path d="M2.75 8.25h14.5M6.5 2.75v3M13.5 2.75v3" strokeLinecap="round" />
</svg>
);
}
export default function ProfileSocial() {
const reduced = useReducedMotion();
const uid = useId();
const [following, setFollowing] = useState(false);
const [notify, setNotify] = useState(false);
const [liked, setLiked] = useState(false);
const [copied, setCopied] = useState(false);
const [burst, setBurst] = useState(0);
const copyTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
const burstTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
return () => {
if (copyTimer.current) clearTimeout(copyTimer.current);
if (burstTimer.current) clearTimeout(burstTimer.current);
};
}, []);
const followers = following ? BASE_FOLLOWERS + 1 : BASE_FOLLOWERS;
const likes = liked ? BASE_LIKES + 1 : BASE_LIKES;
const toggleFollow = useCallback(() => {
setFollowing((prev) => {
const next = !prev;
if (!next) setNotify(false);
if (next) {
setBurst((b) => b + 1);
if (burstTimer.current) clearTimeout(burstTimer.current);
burstTimer.current = setTimeout(() => setBurst(0), 1100);
}
return next;
});
}, []);
const handleCopy = useCallback(() => {
const url = "fieldnotes.email/@nadiarahman";
const done = () => {
setCopied(true);
if (copyTimer.current) clearTimeout(copyTimer.current);
copyTimer.current = setTimeout(() => setCopied(false), 2000);
};
if (typeof navigator !== "undefined" && navigator.clipboard) {
navigator.clipboard.writeText(url).then(done).catch(done);
} else {
done();
}
}, []);
return (
<section className="relative w-full bg-slate-50 px-4 py-16 sm:px-6 sm:py-24 dark:bg-slate-950">
<style>{`
@keyframes psoc-orbit {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes psoc-halo {
0%, 100% { opacity: 0.55; transform: translate3d(0, 0, 0) scale(1); }
50% { opacity: 0.85; transform: translate3d(2%, -3%, 0) scale(1.08); }
}
@keyframes psoc-live {
0% { transform: scale(1); opacity: 0.6; }
75% { transform: scale(2.4); opacity: 0; }
100% { transform: scale(2.4); opacity: 0; }
}
.psoc-orbit { animation: psoc-orbit 14s linear infinite; }
.psoc-halo { animation: psoc-halo 18s ease-in-out infinite; }
.psoc-live { animation: psoc-live 2.4s ease-out infinite; }
@media (prefers-reduced-motion: reduce) {
.psoc-orbit, .psoc-halo, .psoc-live { animation: none !important; }
}
`}</style>
<div
aria-hidden="true"
className="psoc-halo pointer-events-none absolute left-1/2 top-8 h-72 w-[42rem] max-w-full -translate-x-1/2 rounded-full bg-[radial-gradient(50%_60%_at_30%_40%,#818cf8_0%,transparent_70%),radial-gradient(45%_55%_at_70%_50%,#34d399_0%,transparent_72%)] opacity-60 blur-3xl dark:opacity-30"
/>
<div className="relative mx-auto w-full max-w-2xl">
<article className="overflow-hidden rounded-3xl border border-slate-200 bg-white shadow-[0_1px_2px_rgba(15,23,42,0.04),0_12px_40px_-12px_rgba(15,23,42,0.12)] dark:border-slate-800 dark:bg-slate-900 dark:shadow-[0_12px_40px_-12px_rgba(0,0,0,0.6)]">
<div className="px-5 pt-6 sm:px-8 sm:pt-8">
<div className="flex items-start justify-between gap-4">
<div className="flex min-w-0 items-center gap-4">
<div className="relative shrink-0">
<div className="relative grid h-[4.5rem] w-[4.5rem] place-items-center rounded-full p-[2px] sm:h-20 sm:w-20">
<span
aria-hidden="true"
className="psoc-orbit absolute inset-0 rounded-full bg-[conic-gradient(from_0deg,#6366f1,#a78bfa,#34d399,#38bdf8,#6366f1)]"
/>
<span className="relative grid h-full w-full place-items-center rounded-full bg-white dark:bg-slate-900">
<span className="grid h-[calc(100%-4px)] w-[calc(100%-4px)] place-items-center rounded-full bg-gradient-to-br from-slate-800 to-slate-600 text-lg font-semibold tracking-tight text-white sm:text-xl dark:from-slate-100 dark:to-slate-300 dark:text-slate-900">
NR
</span>
</span>
</div>
<span className="absolute bottom-0.5 right-0.5 flex h-4 w-4 items-center justify-center rounded-full bg-white ring-2 ring-white dark:bg-slate-900 dark:ring-slate-900">
<span aria-hidden="true" className="psoc-live absolute h-2.5 w-2.5 rounded-full bg-emerald-400" />
<span className="relative h-2.5 w-2.5 rounded-full bg-emerald-500" />
<span className="sr-only">Active now</span>
</span>
</div>
<div className="min-w-0">
<div className="flex items-center gap-1.5">
<h2 className="truncate text-lg font-semibold tracking-tight text-slate-900 sm:text-xl dark:text-slate-50">
Nadia Rahman
</h2>
<svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4 shrink-0 text-sky-500" fill="currentColor">
<path
fillRule="evenodd"
d="M10 1.6l2 1.5 2.5-.2.9 2.3 2.2 1.3-.7 2.4.7 2.4-2.2 1.3-.9 2.3-2.5-.2-2 1.5-2-1.5-2.5.2-.9-2.3L2.4 11l.7-2.4-.7-2.4 2.2-1.3.9-2.3 2.5.2 2-1.5zm3.2 6a.85.85 0 00-1.25-1.15l-2.85 2.95-1.1-1.15a.85.85 0 10-1.25 1.2l1.75 1.75a.85.85 0 001.25 0l3.45-3.6z"
clipRule="evenodd"
/>
</svg>
<span className="sr-only">Verified writer</span>
</div>
<p className="mt-0.5 truncate text-sm text-slate-500 dark:text-slate-400">
@nadiarahman · Porto, Portugal
</p>
</div>
</div>
<button
type="button"
onClick={handleCopy}
aria-label="Copy link to this profile"
className="grid h-9 w-9 shrink-0 place-items-center rounded-lg border border-slate-200 bg-white text-slate-500 transition-colors hover:bg-slate-50 hover:text-slate-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-slate-100 dark:focus-visible:ring-offset-slate-900"
>
{copied ? (
<svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4 text-emerald-500" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M4 10.5l4 4 8-9" />
</svg>
) : (
<svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round">
<path d="M8.4 11.6a3 3 0 004.4.2l2.4-2.4a3 3 0 10-4.3-4.3l-1 1" />
<path d="M11.6 8.4a3 3 0 00-4.4-.2l-2.4 2.4a3 3 0 104.3 4.3l1-1" />
</svg>
)}
</button>
</div>
<p className="mt-5 text-sm leading-relaxed text-slate-600 dark:text-slate-300">
I write <span className="font-medium text-slate-900 dark:text-slate-100">Field Notes</span>, a weekly
letter about how software teams actually make decisions — the meeting nobody minuted, the doc everyone
skimmed, the trade-off that only shows up eighteen months later. Eight years of engineering management,
written down honestly.
</p>
<ul className="mt-4 flex flex-wrap gap-1.5">
{TOPICS.map((topic) => (
<li
key={topic}
className="rounded-full border border-slate-200 bg-slate-50 px-2.5 py-1 text-xs font-medium text-slate-600 dark:border-slate-700 dark:bg-slate-800/60 dark:text-slate-300"
>
{topic}
</li>
))}
</ul>
<div className="mt-5 flex flex-wrap items-center gap-x-5 gap-y-2 text-sm">
{LINKS.map((link) => (
<a
key={link.id}
href={link.href}
target="_blank"
rel="noopener"
aria-label={link.label}
className="inline-flex items-center gap-1.5 rounded-md text-slate-500 underline-offset-4 transition-colors hover:text-indigo-600 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:text-slate-400 dark:hover:text-indigo-400 dark:focus-visible:ring-offset-slate-900"
>
<Icon name={link.icon} className="h-4 w-4" />
{link.text}
</a>
))}
<span className="inline-flex items-center gap-1.5 text-slate-500 dark:text-slate-400">
<Icon name="calendar" className="h-4 w-4" />
Joined March 2019
</span>
</div>
</div>
{/* Stats */}
<div className="mt-6 grid grid-cols-3 border-y border-slate-200 dark:border-slate-800">
<div className="border-r border-slate-200 px-4 py-4 text-center dark:border-slate-800">
<p className="text-base font-semibold tabular-nums text-slate-900 dark:text-slate-50">1,284</p>
<p className="mt-0.5 text-xs font-medium uppercase tracking-wide text-slate-500 dark:text-slate-400">
Letters
</p>
</div>
<div className="relative border-r border-slate-200 px-4 py-4 text-center dark:border-slate-800">
<div className="relative flex h-6 items-center justify-center overflow-hidden">
<AnimatePresence initial={false} mode="popLayout">
<motion.span
key={followers}
initial={reduced ? false : { y: 14, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={reduced ? { opacity: 0 } : { y: -14, opacity: 0 }}
transition={reduced ? { duration: 0 } : { duration: 0.22, ease: "easeOut" }}
className="text-base font-semibold tabular-nums text-slate-900 dark:text-slate-50"
>
{formatCount(followers)}
</motion.span>
</AnimatePresence>
<AnimatePresence>
{burst > 0 && !reduced && (
<motion.span
key={burst}
aria-hidden="true"
initial={{ opacity: 0, y: 4, scale: 0.8 }}
animate={{ opacity: 1, y: -18, scale: 1 }}
exit={{ opacity: 0, y: -26 }}
transition={{ duration: 0.9, ease: "easeOut" }}
className="pointer-events-none absolute right-3 top-0 text-xs font-bold text-emerald-500"
>
+1
</motion.span>
)}
</AnimatePresence>
</div>
<p className="mt-0.5 text-xs font-medium uppercase tracking-wide text-slate-500 dark:text-slate-400">
Readers
</p>
</div>
<div className="px-4 py-4 text-center">
<p className="text-base font-semibold tabular-nums text-slate-900 dark:text-slate-50">312</p>
<p className="mt-0.5 text-xs font-medium uppercase tracking-wide text-slate-500 dark:text-slate-400">
Following
</p>
</div>
</div>
{/* Actions */}
<div className="px-5 py-5 sm:px-8">
<div className="flex items-center gap-2">
<motion.button
type="button"
aria-pressed={following}
onClick={toggleFollow}
whileTap={reduced ? undefined : { scale: 0.97 }}
transition={reduced ? { duration: 0 } : { type: "spring", stiffness: 500, damping: 30 }}
className={[
"inline-flex h-11 flex-1 items-center justify-center gap-2 rounded-xl text-sm font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-slate-900",
following
? "bg-slate-100 text-slate-700 ring-1 ring-inset ring-slate-200 hover:bg-slate-200 focus-visible:ring-slate-400 dark:bg-slate-800 dark:text-slate-100 dark:ring-slate-700 dark:hover:bg-slate-700"
: "bg-indigo-600 text-white shadow-sm hover:bg-indigo-500 focus-visible:ring-indigo-500",
].join(" ")}
>
{following ? (
<svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M4 10.5l4 4 8-9" />
</svg>
) : (
<svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
<path d="M10 4.5v11M4.5 10h11" />
</svg>
)}
{following ? "Following" : "Follow"}
</motion.button>
<AnimatePresence initial={false}>
{following && (
<motion.button
type="button"
aria-pressed={notify}
aria-label={notify ? "Turn off new letter alerts" : "Turn on new letter alerts"}
onClick={() => setNotify((v) => !v)}
initial={reduced ? false : { opacity: 0, width: 0, marginLeft: 0 }}
animate={{ opacity: 1, width: 44, marginLeft: 0 }}
exit={reduced ? { opacity: 0 } : { opacity: 0, width: 0, marginLeft: -8 }}
transition={reduced ? { duration: 0 } : { duration: 0.22, ease: "easeOut" }}
className={[
"grid h-11 shrink-0 place-items-center overflow-hidden rounded-xl border transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-slate-900",
notify
? "border-transparent bg-amber-400 text-slate-900 hover:bg-amber-300 focus-visible:ring-amber-500"
: "border-slate-200 bg-white text-slate-500 hover:bg-slate-50 hover:text-slate-800 focus-visible:ring-indigo-500 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-slate-100",
].join(" ")}
>
{notify ? (
<svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="currentColor">
<path d="M10 2a4.5 4.5 0 00-4.5 4.5c0 3.2-.8 4.6-1.4 5.3-.4.4-.1 1.2.5 1.2h10.8c.6 0 .9-.8.5-1.2-.6-.7-1.4-2.1-1.4-5.3A4.5 4.5 0 0010 2zM8.2 15.2a1.9 1.9 0 003.6 0H8.2z" />
</svg>
) : (
<svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
<path d="M5.8 6.9a4.2 4.2 0 018.4 0c0 3.1.8 4.5 1.4 5.2.3.4 0 1-.5 1H4.9c-.5 0-.8-.6-.5-1 .6-.7 1.4-2.1 1.4-5.2z" />
<path d="M8.4 15.4a1.8 1.8 0 003.2 0" />
<path d="M3.5 3.5l13 13" className="text-rose-400" />
</svg>
)}
</motion.button>
)}
</AnimatePresence>
<a
href="mailto:hello@example.com"
className="inline-flex h-11 shrink-0 items-center gap-2 rounded-xl border border-slate-200 bg-white px-4 text-sm font-semibold text-slate-700 transition-colors hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:hover:bg-slate-800 dark:focus-visible:ring-offset-slate-900"
>
<svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
<path d="M17 10a6.4 6.4 0 01-6.9 6.4A7 7 0 013 10.6 7 7 0 0110 3a7 7 0 017 7z" />
<path d="M6.5 13.5l1-3.5" />
<path d="M8 8.5l4.5-1.2-1.2 4.5" />
</svg>
Message
</a>
</div>
<p aria-live="polite" className="sr-only">
{following
? notify
? "Following Nadia Rahman. Alerts on for new letters."
: "Following Nadia Rahman. Alerts off."
: "Not following Nadia Rahman."}
{copied ? " Profile link copied to clipboard." : ""}
</p>
{/* Mutuals */}
<div className="mt-5 flex items-center gap-3">
<ul className="flex shrink-0 -space-x-2" aria-hidden="true">
{MUTUALS.map((m) => (
<li
key={m.initials}
className={`grid h-7 w-7 place-items-center rounded-full bg-gradient-to-br ${m.tone} text-[10px] font-semibold text-white ring-2 ring-white dark:ring-slate-900`}
>
{m.initials}
</li>
))}
</ul>
<p className="text-xs leading-relaxed text-slate-500 dark:text-slate-400">
Followed by{" "}
<span className="font-medium text-slate-700 dark:text-slate-200">Priya Raman</span>,{" "}
<span className="font-medium text-slate-700 dark:text-slate-200">Dan Okafor</span> and 47 others you
follow.
</p>
</div>
</div>
{/* Pinned letter */}
<div className="border-t border-slate-200 bg-slate-50/70 px-5 py-5 sm:px-8 dark:border-slate-800 dark:bg-slate-950/40">
<div className="flex items-center gap-1.5 text-xs font-medium uppercase tracking-wide text-slate-500 dark:text-slate-400">
<svg viewBox="0 0 20 20" aria-hidden="true" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
<path d="M8 2.5h4l-.6 4.2 2.6 2.3H5.9l2.7-2.3L8 2.5z" />
<path d="M10 9v8.5" />
</svg>
Pinned letter
</div>
<h3 className="mt-2 text-sm font-semibold text-slate-900 dark:text-slate-50">
<a
href="https://example.com"
target="_blank"
rel="noopener"
id={`${uid}-pinned`}
className="rounded-md underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:focus-visible:ring-offset-slate-950"
>
Issue #211 — The reorg was decided in a hallway
</a>
</h3>
<p className="mt-1.5 text-sm leading-relaxed text-slate-600 dark:text-slate-300">
Every org chart has an official story and a real one. This week: how to spot which decisions were made
before the meeting, and why writing them down after the fact is not the same as making them in the open.
</p>
<div className="mt-3 flex items-center gap-3">
<button
type="button"
aria-pressed={liked}
aria-label={liked ? "Remove like from Issue 211" : "Like Issue 211"}
onClick={() => setLiked((v) => !v)}
className={[
"inline-flex items-center gap-1.5 rounded-lg px-2 py-1 text-xs font-semibold tabular-nums transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:focus-visible:ring-offset-slate-950",
liked
? "bg-rose-50 text-rose-600 focus-visible:ring-rose-500 dark:bg-rose-500/10 dark:text-rose-400"
: "text-slate-500 hover:bg-slate-100 hover:text-slate-800 focus-visible:ring-indigo-500 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-slate-100",
].join(" ")}
>
<motion.span
animate={reduced ? undefined : { scale: liked ? [1, 1.35, 1] : 1 }}
transition={reduced ? { duration: 0 } : { duration: 0.32, ease: "easeOut" }}
className="inline-grid place-items-center"
>
<svg
viewBox="0 0 20 20"
aria-hidden="true"
className="h-4 w-4"
fill={liked ? "currentColor" : "none"}
stroke="currentColor"
strokeWidth="1.6"
strokeLinejoin="round"
>
<path d="M10 16.5S3.5 12.7 3.5 8.2a3.5 3.5 0 016.5-1.9 3.5 3.5 0 016.5 1.9c0 4.5-6.5 8.3-6.5 8.3z" />
</svg>
</motion.span>
{formatCount(likes)}
</button>
<span className="inline-flex items-center gap-1.5 text-xs font-medium tabular-nums text-slate-500 dark:text-slate-400">
<svg viewBox="0 0 20 20" aria-hidden="true" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
<path d="M16.5 9.8a5.9 5.9 0 01-6.4 5.9L5.5 17l.8-3.2A5.7 5.7 0 014.5 9.8C4.5 6.6 7.2 4 10.5 4s6 2.6 6 5.8z" />
</svg>
58 replies
</span>
<span className="ml-auto text-xs text-slate-400 dark:text-slate-500">4 days ago</span>
</div>
</div>
</article>
</div>
</section>
);
}Dependencies
Licence
Built by Web Innoventix. Free for personal and commercial use, no attribution required.
Built by Web Innoventix
Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.
Get a free quoteSimilar components
Browse all →
Profile Header
Originalprofile header with cover and avatar

Profile Settings
Originalaccount settings panel

Profile User Card
Originalcompact user profile card

Profile Stats
Originalprofile with stats and badges

Profile Edit
Originaledit profile form

Profile Team
Originalteam member profile grid

Profile Tabs
Originalprofile page with tabbed content

Profile Bio
Originalbio card with links

Profile Cover
Originallarge cover profile hero

Spotlight Hero
OriginalA centred hero with a soft radial spotlight, badge and dual call-to-action.

Split Hero
OriginalA two-column hero pairing a headline and CTAs with a product mock and social proof.

Gradient Spotlight Hero
OriginalA minimal centred hero with a soft gradient-mesh backdrop, announcement pill and dual call-to-action buttons.

