Research
Build a thesis from evidence.
Research, build, validate, deploy, compound.
Build a thesis from evidence.
Code the strategy.
Backtest on real data.
Send it live.
Iterate and accrue.
Sticky cards lock over each other as the next one rises. The buried card eases down in scale and opacity so a thin peek of each top edge (the gold hairline) remains visible beneath the card above. Scroll-scrubbed, so there is no replay button; scroll back up and the stack unspools.
A sequential process or loop with 3 to 6 steps, where each step carries equal weight and the order is the story. Good for methodologies, pipelines, and loops that compound on themselves.
Don't use for non-sequential content where order is arbitrary. Don't exceed about 6 cards or the buried stack reads as visual noise and the scroll length becomes a chore.
<!-- Requires GSAP: https://cdnjs.cloudflare.com/ajax/libs/gsap/3.13.0/gsap.min.js -->
<style>
:root{
--bg:#0b0a08;--surface:#14110b;--ivory:#efe8d6;--muted:#9c9078;--faint:#5a5446;
--line:#2a2519;--line-faint:rgba(239,232,214,.08);--gold:#c9a24b;--gold-soft:#e7cd8c;
--font-display:'Instrument Serif',ui-serif,Georgia,'Times New Roman',serif;
--font-title:'Libre Caslon Condensed',ui-serif,Georgia,'Times New Roman',serif;
--font-body:'Inter',system-ui,-apple-system,sans-serif;
--font-mono:'JetBrains Mono',ui-monospace,monospace;
--ease:cubic-bezier(.22,1,.36,1);--dur-fast:200ms;--dur-base:400ms;
}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--ivory);font-family:var(--font-body);min-height:100vh;padding:64px 48px}
@keyframes hf-shimmer{0%{background-position:175% 0}100%{background-position:-75% 0}}
.text-shimmer{background-image:linear-gradient(100deg,var(--muted) 0%,var(--muted) 42%,var(--gold-soft) 48%,#f7eed1 50%,var(--gold-soft) 52%,var(--muted) 58%,var(--muted) 100%);background-size:250% 100%;-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;animation:hf-shimmer 13s ease-in-out infinite}
@media(prefers-reduced-motion:reduce){.text-shimmer{animation:none;-webkit-text-fill-color:var(--muted);color:var(--muted)}}
.intro{max-width:960px;margin-bottom:72px}
.intro h2{font-family:var(--font-title);font-size:clamp(2.25rem,5.5vw,3.75rem);line-height:1.04;color:var(--ivory);font-weight:400;letter-spacing:.01em}
.intro h2 em{font-style:normal;color:var(--gold-soft)}
.intro p{margin-top:20px;max-width:36rem;font-weight:300;line-height:1.7;font-size:1.0625rem}
.stack{max-width:960px;margin:0 auto;display:flex;flex-direction:column}
.card-wrap{position:sticky;top:6.5rem}
.card{position:relative;display:flex;flex-direction:column;justify-content:center;min-height:220px;border:1px solid var(--line);background:var(--surface);border-radius:1.5rem;padding:32px 24px;overflow:hidden;box-shadow:0 -1px 0 0 rgba(201,162,75,.12),0 40px 90px -50px rgba(0,0,0,.85)}
.card::before{content:"";position:absolute;left:0;right:0;top:0;height:1px;background:linear-gradient(90deg,transparent,rgba(201,162,75,.4),transparent)}
.card-inner{display:flex;flex-direction:column;gap:20px}
.numeral{font-family:var(--font-title);font-size:4.5rem;line-height:1;color:var(--gold-soft);font-weight:400}
.card-body{max-width:36rem}
.card-body h3{font-family:var(--font-title);font-size:2rem;color:var(--ivory);font-weight:400;line-height:1.05}
.card-body p{margin-top:12px;font-family:var(--font-body);font-size:1rem;font-weight:300;line-height:1.7;color:var(--muted)}
@media(min-width:768px){
.card{min-height:260px;padding:48px 40px}
.card-inner{flex-direction:row;align-items:center;gap:56px}
.numeral{font-size:7rem}
.card-body h3{font-size:3rem}
.card-body p{font-size:1.0625rem}
}
</style>
<header class="intro">
<h2>Five movements, one <em>relentless</em> loop.</h2>
<p class="text-shimmer">Research, build, validate, deploy, compound.</p>
</header>
<main class="stack" id="stack">
<div class="card-wrap" style="top:calc(6.5rem + 0rem)">
<article class="card">
<div class="card-inner">
<span class="numeral">I</span>
<div class="card-body">
<h3>Research</h3>
<p>Build a thesis from evidence.</p>
</div>
</div>
</article>
</div>
<div class="card-wrap" style="top:calc(6.5rem + 1.5rem)">
<article class="card">
<div class="card-inner">
<span class="numeral">II</span>
<div class="card-body">
<h3>Build</h3>
<p>Code the strategy.</p>
</div>
</div>
</article>
</div>
<div class="card-wrap" style="top:calc(6.5rem + 3rem)">
<article class="card">
<div class="card-inner">
<span class="numeral">III</span>
<div class="card-body">
<h3>Validate</h3>
<p>Backtest on real data.</p>
</div>
</div>
</article>
</div>
<div class="card-wrap" style="top:calc(6.5rem + 4.5rem)">
<article class="card">
<div class="card-inner">
<span class="numeral">IV</span>
<div class="card-body">
<h3>Deploy</h3>
<p>Send it live.</p>
</div>
</div>
</article>
</div>
<div class="card-wrap" style="top:calc(6.5rem + 6rem)">
<article class="card">
<div class="card-inner">
<span class="numeral">V</span>
<div class="card-body">
<h3>Compound</h3>
<p>Iterate and accrue.</p>
</div>
</div>
</article>
</div>
</main>
<script>
gsap.registerPlugin(ScrollTrigger);
const mm = gsap.matchMedia();
mm.add("(prefers-reduced-motion: no-preference)", () => {
const wrappers = gsap.utils.toArray('.card-wrap');
const cards = gsap.utils.toArray('.card');
cards.forEach((card, i) => {
if (i >= cards.length - 1) return;
gsap.to(card, {
scale: 0.92,
opacity: 0.45,
ease: 'none',
transformOrigin: 'center top',
scrollTrigger: {
trigger: wrappers[i + 1],
start: 'top 70%',
end: 'top 22%',
scrub: true,
},
});
});
});
mm.add("(prefers-reduced-motion: reduce)", () => {
// plain vertical list: no sticky, no scale/opacity tween
gsap.set('.card-wrap', { position: 'static', marginBottom: 24 });
});
</script>