agency-web/app/page.tsx

326 lines
12 KiB
TypeScript

import {
SITE,
services,
cases,
} from "./content";
import SiteHeader from "./components/SiteHeader";
import Hero from "./components/Hero";
import VelocityMarquee from "./components/VelocityMarquee";
import Reveal, { RevealItem } from "./components/Reveal";
import Scoreboard from "./components/Scoreboard";
import CaseCard, { type CaseData } from "./components/CaseCard";
import ProcessLoop from "./components/ProcessLoop";
import Testimonials from "./components/Testimonials";
import Faq from "./components/Faq";
import Magnetic from "./components/Magnetic";
import SectionDivider from "./components/SectionDivider";
import FinalCTA from "./components/FinalCTA";
const TAPE = [
"Revenue, not vanity metrics",
"Paid",
"SEO",
"Content",
"Social",
"+52% ROAS",
"+217% demos",
"+128 booked/mo",
"Reported every month",
];
const INDUSTRIES = [
"E-commerce",
"B2B SaaS",
"Clinics",
"Professional services",
"DTC brands",
"Marketplaces",
];
/* Monochrome partner / certification marks, recreated as simple inline SVG
wordmark-badges (no raster, no copied brand art). Illustrative, consistent
with the footer "illustrative samples" disclaimer. ~24px tall, --c-text-dim. */
const TRUST_MARKS: { label: string; svg: React.ReactNode }[] = [
{
label: "Google Partner",
svg: (
<svg viewBox="0 0 150 24" role="img" focusable="false">
<circle cx="11" cy="12" r="9" fill="none" stroke="currentColor" strokeWidth="2.2" />
<path d="M11 12h9" stroke="currentColor" strokeWidth="2.2" />
<path d="M16 12a5 5 0 1 0-1.5 3.6" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" />
<text x="28" y="16" fontFamily="var(--font-sans)" fontSize="13" fontWeight="700" fill="currentColor">
Google Partner
</text>
</svg>
),
},
{
label: "Meta Business Partner",
svg: (
<svg viewBox="0 0 178 24" role="img" focusable="false">
<path
d="M4 16c0-5 2.5-8 5.5-8 2.6 0 4 2 5.5 5 1.5-3 2.9-5 5.5-5 3 0 5.5 3 5.5 8M4 16c0 2 1 3 2.6 3 2.2 0 3.6-2.8 4.9-5M22 16c0 2-1 3-2.6 3-2.2 0-3.6-2.8-4.9-5"
fill="none"
stroke="currentColor"
strokeWidth="2.2"
strokeLinecap="round"
/>
<text x="32" y="16" fontFamily="var(--font-sans)" fontSize="13" fontWeight="700" fill="currentColor">
Meta Business Partner
</text>
</svg>
),
},
{
label: "HubSpot Certified",
svg: (
<svg viewBox="0 0 158 24" role="img" focusable="false">
<circle cx="12" cy="14" r="6" fill="none" stroke="currentColor" strokeWidth="2.2" />
<circle cx="18.5" cy="6.5" r="2.6" fill="none" stroke="currentColor" strokeWidth="2" />
<path d="M12 8V5M15 12l2.2-3.4" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" />
<text x="30" y="16" fontFamily="var(--font-sans)" fontSize="13" fontWeight="700" fill="currentColor">
HubSpot Certified
</text>
</svg>
),
},
{
label: "Shopify Plus Partner",
svg: (
<svg viewBox="0 0 168 24" role="img" focusable="false">
<path
d="M9 4 5 5 3 20l8 1 2-16-4-1Zm0 0 1.6.4M11 6.5c-1.6 0-2.2 1.2-2.2 2.2 0 1.4 2.4 1.3 2.4 2.8 0 .7-.6 1-1.2 1"
fill="none"
stroke="currentColor"
strokeWidth="1.8"
strokeLinejoin="round"
strokeLinecap="round"
/>
<text x="22" y="16" fontFamily="var(--font-sans)" fontSize="13" fontWeight="700" fill="currentColor">
Shopify Plus Partner
</text>
</svg>
),
},
];
/* Small live-feeling figures that flank the manifesto so the section reads full,
not empty. Illustrative samples, consistent with the rest of the prototype. */
const MANIFESTO_STATS = [
{ k: "Avg. reporting cadence", v: "Monthly" },
{ k: "Channels we run", v: "6+" },
{ k: "Built around", v: "Your revenue" },
];
export default function Page() {
return (
<>
<SiteHeader />
<main id="main">
<Hero />
{/* ===== KINETIC TAPE — scroll-velocity marquee ===== */}
<section className="tape" aria-label="What we do, at a glance">
<VelocityMarquee items={TAPE} />
</section>
{/* ===== POSITIONING / MANIFESTO ===== */}
<section id="manifesto" className="manifesto frame" aria-labelledby="man-h">
<div className="wrap manifesto__wrap">
<Reveal as="p" className="kicker">
<span className="kicker__dot" />
The problem with most agencies
</Reveal>
<Reveal as="p" className="manifesto__lead display" delay={80}>
<span id="man-h">
Most budgets buy <span className="strike">activity</span>, not
outcomes. Dashboards fill with impressions while the sales number{" "}
<span className="grad">sits still.</span>
</span>
</Reveal>
<Reveal as="p" className="manifesto__body" delay={180}>
We started Feedback Studios to fix that. Every campaign we run is
built to move revenue, and we report on it the way your CFO would.
No vanity metrics. No mystery. Just the number that pays the bills.
</Reveal>
{/* stat ribbon — fills the section, adds a "live" texture */}
<Reveal as="ul" className="manifesto__stats" stagger={0.07} delay={120}>
{MANIFESTO_STATS.map((s) => (
<RevealItem as="li" className="manifesto__stat" key={s.k}>
<span className="manifesto__stat-v display">{s.v}</span>
<span className="manifesto__stat-k">{s.k}</span>
</RevealItem>
))}
</Reveal>
</div>
</section>
{/* ===== INDUSTRIES / SOCIAL PROOF ===== */}
<section className="proof" aria-label="Who we work with">
<div className="wrap">
<p className="kicker proof__label">
Trusted by teams that care about the sales number
</p>
<Reveal as="ul" className="proof__list" stagger={0.06}>
{INDUSTRIES.map((p) => (
<RevealItem as="li" className="proof__item" key={p}>
<span className="proof__item-dot" aria-hidden="true" />
{p}
</RevealItem>
))}
</Reveal>
{/* second row — monochrome partner / certification marks (inline
SVG, no raster) so the section reads substantiated, not sparse */}
<Reveal as="ul" className="proof__logos" stagger={0.06} delay={120}>
{TRUST_MARKS.map((m) => (
<RevealItem as="li" className="proof__logo" key={m.label}>
<span className="proof__logo-svg" aria-hidden="true">
{m.svg}
</span>
<span className="sr-only">{m.label}</span>
</RevealItem>
))}
</Reveal>
</div>
</section>
<SectionDivider label="What we do" />
{/* ===== SERVICES — interactive ledger ===== */}
<section id="services" className="services frame" aria-labelledby="svc-h">
<div className="wrap">
<header className="sec-head">
<p className="kicker">
<span className="kicker__dot" />
Services / 06
</p>
<Reveal as="h2" variant="clip">
<span id="svc-h" className="display sec-head__title">
How we grow your business
</span>
</Reveal>
</header>
<Reveal as="ol" className="ledger" stagger={0.07}>
{services.map((s, i) => (
<RevealItem as="li" key={s.id}>
<a href={SITE.booking} className="ledger__row" data-cursor="Scope it">
<span className="ledger__no">
{String(i + 1).padStart(2, "0")}
</span>
<h3 className="ledger__name display">{s.name}</h3>
<p className="ledger__desc">{s.desc}</p>
<span className="ledger__arrow" aria-hidden="true"></span>
</a>
</RevealItem>
))}
</Reveal>
</div>
</section>
{/* ===== METRICS scoreboard (animated SVG bars + count-ups) ===== */}
<Scoreboard />
{/* ===== CASE STUDIES — 3D tilt + coded charts ===== */}
<section id="work" className="work frame" aria-labelledby="work-h">
<div className="wrap">
<header className="sec-head">
<p className="kicker">
<span className="kicker__dot" />
Selected work sample
</p>
<Reveal as="h2" variant="clip">
<span id="work-h" className="display sec-head__title">
Proof, not promises
</span>
</Reveal>
</header>
<div className="work__grid">
{cases.map((c, i) => (
<CaseCard key={c.tag} data={c as unknown as CaseData} index={i} />
))}
</div>
<div className="work__cta">
<Magnetic strength={0.3}>
<a href={SITE.booking} className="btn btn--ghost" data-cursor="See more">
View all work <span className="arrow" aria-hidden="true"></span>
</a>
</Magnetic>
</div>
</div>
</section>
{/* ===== PROCESS — pinned scroll + morphing SVG ===== */}
<ProcessLoop />
{/* ===== TESTIMONIALS — interactive auto-advancing carousel ===== */}
<Testimonials />
{/* ===== FAQ ===== */}
<section id="faq" data-invert className="faq-sec frame" aria-labelledby="faq-h">
<div className="wrap faq-sec__wrap">
<header className="sec-head">
<p className="kicker">
<span className="kicker__dot" />
FAQ
</p>
<Reveal as="h2" variant="clip">
<span id="faq-h" className="display sec-head__title">
Questions about working with a digital marketing agency
</span>
</Reveal>
</header>
<Faq />
</div>
</section>
{/* ===== FINAL CTA — dramatic cursor-reactive WebGL + kinetic type ===== */}
<FinalCTA />
</main>
{/* ===== FOOTER ===== */}
<footer data-invert className="colophon frame" aria-label="Footer">
<div className="wrap">
<div className="colophon__top">
<div className="colophon__brand">
<span className="brand__mark" aria-hidden="true">
<span className="brand__dot" />
</span>
<p className="colophon__line">
{SITE.name}. {SITE.tagline}
</p>
</div>
<nav className="colophon__nav" aria-label="Footer">
<ul>
<li><a href="#services">Services</a></li>
<li><a href="#work">Work</a></li>
<li><a href="#process">About</a></li>
<li><a href="#faq">FAQ</a></li>
<li><a href={`mailto:${SITE.email}`}>Contact</a></li>
</ul>
<ul>
<li><a href="https://www.linkedin.com" rel="noopener">LinkedIn</a></li>
<li><a href={SITE.booking}>Book a call</a></li>
<li><a href="#main">Privacy</a></li>
<li><a href="#main">Terms</a></li>
</ul>
</nav>
</div>
<div className="rule" />
<div className="colophon__bottom">
<p>© 2026 {SITE.name}. All rights reserved.</p>
<p className="colophon__note">
Metrics and case studies shown are illustrative samples.
</p>
</div>
</div>
</footer>
</>
);
}