67 lines
2.4 KiB
TypeScript
67 lines
2.4 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* CaseStudies — large film-cell cards. Each is a real <article> with the
|
|
* generated capsule visual, a problem -> result narrative, the method, and the
|
|
* headline metric. Alternating media side creates an editorial rhythm; refined
|
|
* scale-on-hover on the image. Images are explicit-sized + lazy-loaded.
|
|
*/
|
|
|
|
import Reveal from "./Reveal";
|
|
import { cases } from "../content";
|
|
|
|
export default function CaseStudies() {
|
|
return (
|
|
<section id="work" className="cases" aria-label="Case studies">
|
|
<div className="wrap">
|
|
<Reveal>
|
|
<p className="kicker">Case studies</p>
|
|
<h2 className="section__title">Proof, not promises.</h2>
|
|
<p className="section__lead">
|
|
A few of the businesses we've grown. Same approach every time:
|
|
tie the work to the revenue, then prove it.
|
|
</p>
|
|
</Reveal>
|
|
|
|
<div className="cases__list">
|
|
{cases.map((c, i) => (
|
|
<Reveal key={c.tag} y={60}>
|
|
<article className="case hoverable" data-cursor="view work">
|
|
<div className="case__media">
|
|
<span className="case__tag">{c.tag}</span>
|
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
<img
|
|
src={c.img}
|
|
alt={c.alt}
|
|
className="case__img"
|
|
width={900}
|
|
height={760}
|
|
loading={i === 0 ? "eager" : "lazy"}
|
|
decoding="async"
|
|
/>
|
|
</div>
|
|
<div className="case__body">
|
|
<p className="case__problem">{c.problem}</p>
|
|
<h3 className="case__result">
|
|
<em>{c.result}</em>
|
|
</h3>
|
|
<p className="case__how">{c.how}</p>
|
|
<p className="case__metric">
|
|
<span className="case__metric-num">{c.metricNum}</span>
|
|
<span className="case__metric-label">{c.metricLabel}</span>
|
|
</p>
|
|
</div>
|
|
</article>
|
|
</Reveal>
|
|
))}
|
|
</div>
|
|
|
|
<div className="cases__cta">
|
|
<a className="btn btn--ghost hoverable" href="#contact">
|
|
<span>View all work →</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|