# Stacking Sticky Cards (Bounce)

> Sticky cards that stack with a bounce as you scroll — narrative sections with physical, layered energy.

**Definition:** Stacking Sticky Cards (Bounce) is a scroll UI animation from collections.html. It is built with HTML, CSS, JavaScript, and GSAP, ships with a live preview, and is free to copy into personal and commercial projects.

## Facts
- Category: Scroll
- Stack: HTML, CSS, JavaScript, and GSAP
- Added: 2026-08-01
- Canonical page: https://html.bosconvertpro.com/collection/stacking-sticky-cards-bounce
- Full-page preview: https://html.bosconvertpro.com/collection/stacking-sticky-cards-bounce/full
- Live demo: https://html.bosconvertpro.com/demos/stacking-sticky-cards-bounce/index.html
- Markdown mirror: https://html.bosconvertpro.com/collection/stacking-sticky-cards-bounce/index.md
- License: https://html.bosconvertpro.com/terms

## How to use
1. Open https://html.bosconvertpro.com/collection/stacking-sticky-cards-bounce/full to preview the animation in full screen.
2. Copy index.html, styles.css, and script.js from the code tabs on https://html.bosconvertpro.com/collection/stacking-sticky-cards-bounce.
3. Paste the files into your project and adjust timing, easing, and content as needed.

## FAQ
### What is Stacking Sticky Cards (Bounce)?

Stacking Sticky Cards (Bounce) is a scroll UI animation from collections.html. Sticky cards that stack with a bounce as you scroll — narrative sections with physical, layered energy.

### What is Stacking Sticky Cards (Bounce) built with?

Stacking Sticky Cards (Bounce) is built with HTML, CSS, JavaScript, and GSAP. The source for every file is shown on the animation page and can be copied straight into your project.

### How do I use Stacking Sticky Cards (Bounce) in my project?

Open the animation page (https://html.bosconvertpro.com/collection/stacking-sticky-cards-bounce), preview it live, then copy index.html, styles.css, and script.js from the code tabs. Paste the files into your project and adjust timing, easing, and content as needed. A standalone demo runs at https://html.bosconvertpro.com/demos/stacking-sticky-cards-bounce/index.html.

### Is Stacking Sticky Cards (Bounce) free to use?

Yes. The Stacking Sticky Cards (Bounce) demo code may be used in personal and commercial projects. You may not resell or redistribute the collection itself as a competing template pack. Full terms: https://html.bosconvertpro.com/terms.

## Source — index.html
````html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Stacking Sticky Cards (Bounce)</title>
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap"
      rel="stylesheet"
    />
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/lenis@1.2.3/dist/lenis.css"
    />
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <div class="ambient" aria-hidden="true">
      <span class="ambient__orb ambient__orb--a"></span>
      <span class="ambient__orb ambient__orb--b"></span>
      <span class="ambient__grain"></span>
    </div>

    <section class="intro">
      <div class="container intro__inner">
        <span class="badge">Interactive scroll</span>
        <h1 class="intro__title">
          Crafted services,<br />
          <em>stacked with intent</em>
        </h1>
        <p class="intro__text">
          Each card locks into place with a refined bounce — scroll to explore
          how our process unfolds.
        </p>
        <div class="scroll-cue" aria-hidden="true">
          <span class="scroll-cue__line"></span>
          <span class="scroll-cue__label">Scroll</span>
        </div>
      </div>
    </section>

    <!-- Fan layout: cards settle with x / y / rotate offsets -->
    <section
      class="cards-stack"
      data-stacking-cards-init
      data-stacking-cards-desktop="true"
      data-stacking-cards-tablet="true"
      data-stacking-cards-mobile="true"
      data-stacking-cards-desktop-x="-13.75em, 0em, 13em"
      data-stacking-cards-desktop-y="2.125em, 0em, 4.5em"
      data-stacking-cards-desktop-rotate="-5, 2, 6"
      data-stacking-cards-tablet-x="-4em, 0em, 4em"
      data-stacking-cards-tablet-y="1.5em, 0em, 3em"
      data-stacking-cards-tablet-rotate="-4, 1, 5"
      data-stacking-cards-mobile-x="0em, 0em, 0em"
      data-stacking-cards-mobile-y="0.75em, 0em, 1.5em"
      data-stacking-cards-mobile-rotate="-3, 1, 4"
    >
      <div class="container">
        <header class="section-header">
          <span class="section-header__index">01</span>
          <div class="section-header__copy">
            <p class="section-header__eyebrow">Capability stack</p>
            <h2 class="section-header__title">How we work</h2>
          </div>
        </header>

        <div class="cards-stack__collection">
          <div class="cards-stack__list" data-stacking-card-stack>
            <div class="cards-stack__item" data-stacking-card>
              <article class="cards-stack-card" data-stacking-card-target>
                <div class="cards-stack-card__glow" aria-hidden="true"></div>
                <div class="cards-stack-card__start">
                  <span class="cards-stack-card__phase">Phase</span>
                  <span class="cards-stack-card__number">01</span>
                </div>
                <div class="cards-stack-card__end">
                  <h3 class="cards-stack-card__h">Product Discovery</h3>
                  <p class="cards-stack-card__lead">
                    Clarity before craft — define the problem worth solving.
                  </p>
                  <ul class="cards-stack-card__services">
                    <li>User Interviews</li>
                    <li>Journey Mapping</li>
                    <li>Problem Framing</li>
                    <li>Opportunity Sizing</li>
                    <li>Prioritized Roadmap</li>
                  </ul>
                </div>
              </article>
            </div>

            <div class="cards-stack__item" data-stacking-card>
              <article
                class="cards-stack-card is--sage"
                data-stacking-card-target
              >
                <div class="cards-stack-card__glow" aria-hidden="true"></div>
                <div class="cards-stack-card__start">
                  <span class="cards-stack-card__phase">Phase</span>
                  <span class="cards-stack-card__number">02</span>
                </div>
                <div class="cards-stack-card__end">
                  <h3 class="cards-stack-card__h">Creative Systems</h3>
                  <p class="cards-stack-card__lead">
                    A visual language that scales with every product touchpoint.
                  </p>
                  <ul class="cards-stack-card__services">
                    <li>Visual Language</li>
                    <li>Component Libraries</li>
                    <li>Motion Principles</li>
                    <li>Content Patterns</li>
                  </ul>
                </div>
              </article>
            </div>

            <div class="cards-stack__item" data-stacking-card>
              <article
                class="cards-stack-card is--ink"
                data-stacking-card-target
              >
                <div class="cards-stack-card__glow" aria-hidden="true"></div>
                <div class="cards-stack-card__start">
                  <span class="cards-stack-card__phase">Phase</span>
                  <span class="cards-stack-card__number">03</span>
                </div>
                <div class="cards-stack-card__end">
                  <h3 class="cards-stack-card__h">Launch &amp; Iterate</h3>
                  <p class="cards-stack-card__lead">
                    Ship with confidence, then refine from real signal.
                  </p>
                  <ul class="cards-stack-card__services">
                    <li>A/B Experiments</li>
                    <li>Performance Tuning</li>
                    <li>Feedback Loops</li>
                    <li>Growth Playbooks</li>
                  </ul>
                </div>
              </article>
            </div>
          </div>
        </div>
      </div>
    </section>

    <!-- Wide stacked cards -->
    <section
      class="cards-stack cards-stack--wide"
      data-stacking-cards-init
      data-stacking-cards-desktop="true"
      data-stacking-cards-tablet="true"
      data-stacking-cards-mobile="true"
    >
      <div class="container">
        <header class="section-header">
          <span class="section-header__index">02</span>
          <div class="section-header__copy">
            <p class="section-header__eyebrow">Studio disciplines</p>
            <h2 class="section-header__title">What we deliver</h2>
          </div>
        </header>

        <div class="cards-stack__collection">
          <div class="cards-stack__list" data-stacking-card-stack>
            <div class="cards-stack__item is--wide" data-stacking-card>
              <article
                class="cards-stack-card is--wide"
                data-stacking-card-target
              >
                <div class="cards-stack-card__glow" aria-hidden="true"></div>
                <div class="cards-stack-card__wide-layout">
                  <div class="cards-stack-card__start">
                    <span class="cards-stack-card__phase">Studio</span>
                    <span class="cards-stack-card__number">01</span>
                  </div>
                  <div class="cards-stack-card__end">
                    <h3 class="cards-stack-card__h is--l">Research Studio</h3>
                    <p class="cards-stack-card__lead">
                      Evidence-led insights that de-risk product decisions.
                    </p>
                    <ul class="cards-stack-card__services is--inline">
                      <li>Ethnographic Studies</li>
                      <li>Competitive Audits</li>
                      <li>Insight Synthesis</li>
                      <li>Persona Workshops</li>
                      <li>Opportunity Maps</li>
                    </ul>
                  </div>
                </div>
              </article>
            </div>

            <div class="cards-stack__item is--wide" data-stacking-card>
              <article
                class="cards-stack-card is--wide is--sage"
                data-stacking-card-target
              >
                <div class="cards-stack-card__glow" aria-hidden="true"></div>
                <div class="cards-stack-card__wide-layout">
                  <div class="cards-stack-card__start">
                    <span class="cards-stack-card__phase">Studio</span>
                    <span class="cards-stack-card__number">02</span>
                  </div>
                  <div class="cards-stack-card__end">
                    <h3 class="cards-stack-card__h is--l">Interface Craft</h3>
                    <p class="cards-stack-card__lead">
                      Interfaces that feel inevitable — calm, precise, human.
                    </p>
                    <ul class="cards-stack-card__services is--inline">
                      <li>Interaction Design</li>
                      <li>Design Tokens</li>
                      <li>Responsive Layouts</li>
                      <li>Accessibility QA</li>
                    </ul>
                  </div>
                </div>
              </article>
            </div>

            <div class="cards-stack__item is--wide" data-stacking-card>
              <article
                class="cards-stack-card is--wide is--ink"
                data-stacking-card-target
              >
                <div class="cards-stack-card__glow" aria-hidden="true"></div>
                <div class="cards-stack-card__wide-layout">
                  <div class="cards-stack-card__start">
                    <span class="cards-stack-card__phase">Studio</span>
                    <span class="cards-stack-card__number">03</span>
                  </div>
                  <div class="cards-stack-card__end">
                    <h3 class="cards-stack-card__h is--l">Engineering Partner</h3>
                    <p class="cards-stack-card__lead">
                      Production-grade builds that honor the design intent.
                    </p>
                    <ul class="cards-stack-card__services is--inline">
                      <li>Frontend Architecture</li>
                      <li>API Integration</li>
                      <li>Performance Budgets</li>
                      <li>Ship &amp; Support</li>
                    </ul>
                  </div>
                </div>
              </article>
            </div>
          </div>
        </div>
      </div>
    </section>

    <section class="outro">
      <div class="container outro__inner">
        <span class="badge badge--soft">End of sequence</span>
        <h2 class="outro__title">And back up</h2>
        <p class="outro__text">
          Scroll reverse to watch the stack unwind with the same polish.
        </p>
      </div>
    </section>

    <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/ScrollTrigger.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/lenis@1.2.3/dist/lenis.min.js"></script>
    <script src="script.js"></script>
  </body>
</html>
````

## Source — styles.css
````css
/* ============================================
   Stacking Sticky Cards (Bounce) — Premium UI
   ============================================ */

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

:root {
  --bg: #efe9e1;
  --bg-deep: #e4dcd2;
  --text: #141210;
  --text-muted: rgb(20 18 16 / 58%);
  --card-light: #faf8f5;
  --card-sage: #a8a38a;
  --card-ink: #151311;
  --accent: #8b7355;
  --line: rgb(20 18 16 / 10%);
  --radius: 1.75rem;
  --radius-sm: 999px;
  --sticky-top: 4.5rem;
  --container: 88rem;
  --pad-x: clamp(1.25rem, 4vw, 2.5rem);
  --shadow-card:
    0 1px 0 rgb(255 255 255 / 45%) inset,
    0 2px 4px rgb(20 18 16 / 4%),
    0 18px 48px rgb(20 18 16 / 10%),
    0 48px 80px rgb(20 18 16 / 6%);
  --shadow-card-ink:
    0 1px 0 rgb(255 255 255 / 8%) inset,
    0 2px 4px rgb(0 0 0 / 12%),
    0 24px 56px rgb(0 0 0 / 28%),
    0 48px 90px rgb(0 0 0 / 18%);
  --font-sans: "Plus Jakarta Sans", system-ui, -apple-system, sans-serif;
  --font-serif: "Instrument Serif", Georgia, serif;
}

html {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

html.lenis,
html.lenis body {
  height: auto;
}

.lenis.lenis-smooth {
  scroll-behavior: auto !important;
}

.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}

.lenis.lenis-stopped {
  overflow: hidden;
}

body {
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
  overflow-x: hidden;
  min-height: 100vh;
  position: relative;
}

/* ---------- Ambient background ---------- */

.ambient {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
}

.ambient__orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  opacity: 0.55;
}

.ambient__orb--a {
  width: min(52vw, 36rem);
  height: min(52vw, 36rem);
  top: -8%;
  left: -6%;
  background: radial-gradient(circle, #f5e6d3 0%, transparent 70%);
}

.ambient__orb--b {
  width: min(48vw, 32rem);
  height: min(48vw, 32rem);
  bottom: 10%;
  right: -8%;
  background: radial-gradient(circle, #d5cfc0 0%, transparent 70%);
  opacity: 0.4;
}

.ambient__grain {
  position: absolute;
  inset: 0;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px;
  mix-blend-mode: multiply;
}

/* ---------- Layout ---------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--pad-x);
  position: relative;
  z-index: 1;
}

/* ---------- Badge ---------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.9rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: rgb(255 255 255 / 55%);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  box-shadow: 0 1px 0 rgb(255 255 255 / 70%) inset;
}

.badge--soft {
  background: rgb(20 18 16 / 4%);
}

.badge::before {
  content: "";
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px rgb(139 115 85 / 18%);
}

/* ---------- Intro / Outro ---------- */

.intro,
.outro {
  min-height: 78vh;
  display: grid;
  place-items: center;
  text-align: center;
  padding-block: clamp(5rem, 12vh, 9rem) clamp(3rem, 8vh, 5rem);
  position: relative;
  z-index: 1;
}

.intro__inner,
.outro__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
  max-width: 42rem;
}

.intro__title,
.outro__title {
  font-family: var(--font-serif);
  font-size: clamp(2.75rem, 7vw, 5rem);
  font-weight: 400;
  letter-spacing: -0.03em;
  line-height: 1.05;
  color: var(--text);
}

.intro__title em,
.outro__title em {
  font-style: italic;
  color: rgb(20 18 16 / 72%);
}

.intro__text,
.outro__text {
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  font-weight: 400;
  color: var(--text-muted);
  max-width: 30rem;
  line-height: 1.65;
}

.scroll-cue {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  margin-top: 2rem;
  color: var(--text-muted);
}

.scroll-cue__line {
  width: 1px;
  height: 3.25rem;
  background: linear-gradient(
    to bottom,
    rgb(20 18 16 / 0%),
    rgb(20 18 16 / 35%),
    rgb(20 18 16 / 0%)
  );
  position: relative;
  overflow: hidden;
}

.scroll-cue__line::after {
  content: "";
  position: absolute;
  left: 0;
  width: 100%;
  height: 30%;
  background: var(--text);
  opacity: 0.55;
  animation: cue-travel 1.8s ease-in-out infinite;
}

.scroll-cue__label {
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

@keyframes cue-travel {
  0% {
    top: -30%;
  }
  100% {
    top: 100%;
  }
}

.outro {
  min-height: 62vh;
  padding-block: 4rem 10rem;
}

/* ---------- Section headers ---------- */

.section-header {
  display: flex;
  align-items: flex-end;
  gap: 1.25rem;
  margin-bottom: clamp(2.5rem, 6vh, 4rem);
  max-width: 40rem;
}

.section-header__index {
  font-family: var(--font-serif);
  font-size: clamp(2.5rem, 5vw, 3.5rem);
  line-height: 0.9;
  color: rgb(20 18 16 / 18%);
  letter-spacing: -0.03em;
}

.section-header__eyebrow {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 0.35rem;
}

.section-header__title {
  font-size: clamp(1.35rem, 2.4vw, 1.75rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.15;
}

/* ---------- Cards stack ---------- */

.cards-stack {
  padding-block: 12dvh 18dvh;
  position: relative;
  z-index: 1;
}

.cards-stack--wide {
  padding-top: 6dvh;
}

.cards-stack__list {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  gap: 5em;
}

.cards-stack__item {
  position: sticky;
  top: var(--sticky-top);
  flex: none;
  width: 100%;
  max-width: 24em;
  will-change: transform;
}

.cards-stack__item.is--wide {
  max-width: 58em;
}

/* ---------- Card face ---------- */

.cards-stack-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  width: 100%;
  aspect-ratio: 2 / 3;
  padding: clamp(1.75rem, 3vw, 2.4rem);
  border-radius: var(--radius);
  background:
    linear-gradient(165deg, rgb(255 255 255 / 72%) 0%, transparent 42%),
    var(--card-light);
  color: var(--text);
  border: 1px solid rgb(255 255 255 / 55%);
  transform-origin: center center;
  backface-visibility: hidden;
  box-shadow: var(--shadow-card);
  overflow: hidden;
  isolation: isolate;
}

.cards-stack-card__glow {
  position: absolute;
  inset: auto -20% 35% auto;
  width: 70%;
  height: 45%;
  background: radial-gradient(
    circle,
    rgb(255 255 255 / 55%) 0%,
    transparent 70%
  );
  pointer-events: none;
  z-index: 0;
}

.cards-stack-card > *:not(.cards-stack-card__glow) {
  position: relative;
  z-index: 1;
}

.cards-stack-card.is--sage {
  background:
    linear-gradient(165deg, rgb(255 255 255 / 22%) 0%, transparent 45%),
    linear-gradient(180deg, #b5b09a 0%, var(--card-sage) 100%);
  border-color: rgb(255 255 255 / 22%);
  color: #141210;
}

.cards-stack-card.is--ink {
  background:
    linear-gradient(155deg, rgb(255 255 255 / 8%) 0%, transparent 40%),
    linear-gradient(180deg, #1d1a18 0%, var(--card-ink) 100%);
  border-color: rgb(255 255 255 / 8%);
  color: #f6f2ec;
  box-shadow: var(--shadow-card-ink);
}

.cards-stack-card.is--ink .cards-stack-card__phase,
.cards-stack-card.is--ink .cards-stack-card__lead,
.cards-stack-card.is--ink .cards-stack-card__services {
  color: rgb(246 242 236 / 72%);
}

.cards-stack-card.is--ink .cards-stack-card__services li {
  border-color: rgb(246 242 236 / 12%);
}

.cards-stack-card.is--ink .cards-stack-card__glow {
  background: radial-gradient(
    circle,
    rgb(255 255 255 / 10%) 0%,
    transparent 70%
  );
  inset: auto auto 30% -15%;
}

.cards-stack-card.is--wide {
  aspect-ratio: 5 / 3;
  padding: clamp(2rem, 3.5vw, 2.75rem);
}

.cards-stack-card__wide-layout {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 100%;
  gap: 1.5rem;
}

.cards-stack-card__start {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.cards-stack-card__phase {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgb(20 18 16 / 48%);
}

.cards-stack-card__number {
  display: block;
  font-family: var(--font-serif);
  font-size: clamp(4.5rem, 10vw, 6.5rem);
  font-weight: 400;
  line-height: 0.9;
  letter-spacing: -0.04em;
  opacity: 0.92;
}

.cards-stack-card__end {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.cards-stack-card__h {
  margin: 0;
  font-size: clamp(1.85rem, 3.8vw, 2.65rem);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.035em;
}

.cards-stack-card__h.is--l {
  font-size: clamp(2rem, 4.2vw, 3.25rem);
}

.cards-stack-card__lead {
  font-size: 0.95rem;
  font-weight: 400;
  line-height: 1.5;
  color: rgb(20 18 16 / 58%);
  max-width: 22rem;
}

.cards-stack-card__services {
  list-style: none;
  display: flex;
  flex-direction: column;
  margin-top: 0.5rem;
  min-height: 0;
}

.cards-stack-card__services li {
  font-size: 0.95rem;
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: -0.01em;
  padding: 0.55rem 0;
  border-top: 1px solid rgb(20 18 16 / 10%);
  color: rgb(20 18 16 / 78%);
}

.cards-stack-card__services li:last-child {
  border-bottom: 1px solid rgb(20 18 16 / 10%);
}

.cards-stack-card__services.is--inline {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.cards-stack-card__services.is--inline li {
  border: 1px solid rgb(20 18 16 / 12%);
  border-radius: var(--radius-sm);
  padding: 0.4rem 0.8rem;
  font-size: 0.8rem;
  font-weight: 500;
  background: rgb(255 255 255 / 28%);
  backdrop-filter: blur(6px);
}

.cards-stack-card.is--ink .cards-stack-card__services.is--inline li {
  border-color: rgb(246 242 236 / 14%);
  background: rgb(255 255 255 / 6%);
  color: rgb(246 242 236 / 88%);
}

.cards-stack-card.is--sage .cards-stack-card__services.is--inline li {
  border-color: rgb(20 18 16 / 12%);
  background: rgb(255 255 255 / 22%);
}

/* ---------- Responsive ---------- */

@media screen and (max-width: 991px) {
  .cards-stack-card.is--wide {
    aspect-ratio: 5 / 4;
  }

  .cards-stack-card__h.is--l {
    font-size: clamp(1.85rem, 5vw, 2.5rem);
  }
}

@media screen and (max-width: 767px) {
  :root {
    --sticky-top: 3.25rem;
  }

  .cards-stack__list {
    gap: 3.5em;
  }

  .cards-stack__item.is--wide {
    max-width: 24em;
  }

  .cards-stack-card {
    font-size: 0.92em;
  }

  .cards-stack-card.is--wide {
    aspect-ratio: 2 / 3;
  }

  .cards-stack-card__services.is--inline {
    flex-direction: column;
    gap: 0;
  }

  .cards-stack-card__services.is--inline li {
    border-radius: 0;
    border-left: 0;
    border-right: 0;
    border-top: 1px solid rgb(20 18 16 / 10%);
    border-bottom: none;
    padding: 0.55rem 0;
    background: transparent;
    backdrop-filter: none;
  }

  .cards-stack-card__services.is--inline li:last-child {
    border-bottom: 1px solid rgb(20 18 16 / 10%);
  }

  .cards-stack-card.is--ink .cards-stack-card__services.is--inline li {
    border-color: rgb(246 242 236 / 12%);
    background: transparent;
  }

  .intro,
  .outro {
    min-height: 58vh;
    padding-block: 4.5rem 2.5rem;
  }

  .section-header {
    align-items: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-cue__line::after {
    animation: none;
  }

  .cards-stack-card {
    transition: none;
  }
}
````

## Source — script.js
````javascript
/**
 * Stacking Sticky Cards (Bounce)
 * Sticky cards scrub into x / y / rotate offsets, then pulse with an
 * elastic bounce when each card locks at its sticky top.
 * Smooth scrolling via Lenis, synced with ScrollTrigger.
 */

(() => {
  "use strict";

  if (typeof gsap === "undefined" || typeof ScrollTrigger === "undefined") {
    console.warn("GSAP + ScrollTrigger required.");
    return;
  }

  gsap.registerPlugin(ScrollTrigger);

  let lenis = null;

  const ATTR = {
    init: "[data-stacking-cards-init]",
    card: "[data-stacking-card]",
    target: "[data-stacking-card-target]",
  };

  /* ---------- Smooth scroll (Lenis) ---------- */

  function initSmoothScroll() {
    if (typeof Lenis === "undefined") return;
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;

    lenis = new Lenis({
      duration: 1.25,
      easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
      smoothWheel: true,
      touchMultiplier: 1.2,
    });

    // Keep ScrollTrigger in sync with the smoothed scroll position
    lenis.on("scroll", ScrollTrigger.update);

    gsap.ticker.add((time) => {
      lenis.raf(time * 1000);
    });
    gsap.ticker.lagSmoothing(0);
  }

  /* ---------- Viewport helpers ---------- */

  function getViewportTier() {
    const w = window.innerWidth;
    if (w <= 479) return "mobile-portrait";
    if (w <= 767) return "mobile-landscape";
    if (w <= 991) return "tablet";
    return "desktop";
  }

  function isTierEnabled(section, tier) {
    if (tier === "desktop") return section.dataset.stackingCardsDesktop === "true";
    if (tier === "tablet") return section.dataset.stackingCardsTablet === "true";
    return section.dataset.stackingCardsMobile === "true";
  }

  function attrForTier(base, tier) {
    if (tier === "desktop") return `data-stacking-cards-desktop-${base}`;
    if (tier === "tablet") return `data-stacking-cards-tablet-${base}`;
    return `data-stacking-cards-mobile-${base}`;
  }

  function parseRotateValues(section, attr) {
    const fallback = [0, 4, -4];
    const raw = section.getAttribute(attr) || "";
    const values = raw.split(",").map((v) => parseFloat(v.trim()));
    return values.length >= 1 && values.every((v) => !Number.isNaN(v))
      ? values
      : fallback;
  }

  function parseAxisValues(section, attr) {
    const raw = section.getAttribute(attr);
    if (!raw) return ["0em", "0em", "0em"];
    const values = raw
      .split(",")
      .map((v) => v.trim())
      .filter(Boolean);
    return values.length ? values : ["0em", "0em", "0em"];
  }

  function debounceOnWidthChange(fn, ms = 250) {
    let last = innerWidth;
    let timer;
    return function debounced(...args) {
      clearTimeout(timer);
      timer = setTimeout(() => {
        if (innerWidth !== last) {
          last = innerWidth;
          fn.apply(this, args);
        }
      }, ms);
    };
  }

  /* ---------- Bounce pulse ---------- */

  function pulseElement(targetEl) {
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;

    const width = targetEl.offsetWidth || 1;
    const height = targetEl.offsetHeight || 1;
    const fontSize = parseFloat(getComputedStyle(targetEl).fontSize) || 16;
    const stretchPx = 1.5 * fontSize;
    const targetScaleX = (width + stretchPx) / width;
    const targetScaleY = (height - stretchPx * 0.33) / height;

    gsap
      .timeline({ overwrite: "auto" })
      .to(targetEl, {
        scaleX: targetScaleX,
        scaleY: targetScaleY,
        duration: 0.1,
        ease: "power1.out",
      })
      .to(targetEl, {
        scaleX: 1,
        scaleY: 1,
        duration: 1,
        ease: "elastic.out(1, 0.3)",
      });
  }

  /* ---------- Core init ---------- */

  function killStackingTriggers(sections) {
    ScrollTrigger.getAll().forEach((trigger) => {
      const id = trigger.vars?.id;
      if (typeof id === "string" && id.startsWith("stacking")) {
        trigger.kill();
        return;
      }
      sections.forEach((section) => {
        if (trigger.trigger && section.contains(trigger.trigger)) {
          trigger.kill();
        }
      });
    });

    sections.forEach((section) => {
      section.querySelectorAll(ATTR.target).forEach((el) => {
        gsap.killTweensOf(el);
        gsap.set(el, { clearProps: "all" });
      });
    });
  }

  function initStackingStickyCardsBounce() {
    const sections = [...document.querySelectorAll(ATTR.init)];
    if (!sections.length) return;

    const tier = getViewportTier();
    window.viewportTier = tier;

    killStackingTriggers(sections);

    sections.forEach((section) => {
      if (!isTierEnabled(section, tier)) return;

      const cards = [...section.querySelectorAll(ATTR.card)];
      if (!cards.length) return;

      const stickyTop =
        parseFloat(getComputedStyle(cards[0]).top) || 0;

      const rotateValues = parseRotateValues(
        section,
        attrForTier("rotate", tier)
      );
      const xValues = parseAxisValues(section, attrForTier("x", tier));
      const yValues = parseAxisValues(section, attrForTier("y", tier));

      cards.forEach((card, index) => {
        const targetEl = card.querySelector(ATTR.target);
        if (!targetEl) return;

        const rotate = rotateValues[index % rotateValues.length];
        const x = xValues[index % xValues.length];
        const y = yValues[index % yValues.length];

        gsap.set(targetEl, {
          rotate: 0,
          x: 0,
          y: 0,
          scale: 1,
          scaleX: 1,
          scaleY: 1,
          zIndex: cards.length - index,
          force3D: true,
        });

        // Scrub tilt / offset as the card approaches sticky top
        gsap.to(targetEl, {
          rotate,
          x,
          y,
          ease: "power1.in",
          overwrite: "auto",
          scrollTrigger: {
            id: `stacking-rotate-${index}`,
            trigger: card,
            start: "top 75%",
            end: `top-=${stickyTop} top`,
            scrub: true,
          },
        });

        // Bounce when the card locks sticky
        ScrollTrigger.create({
          id: `stacking-bounce-${index}`,
          trigger: card,
          start: `top-=${stickyTop} top`,
          onEnter: () => pulseElement(targetEl),
        });
      });
    });

    ScrollTrigger.refresh();
  }

  /* ---------- Boot ---------- */

  function boot() {
    initSmoothScroll();
    initStackingStickyCardsBounce();

    if (!window._hasStackingResizeListener) {
      let lastTier = getViewportTier();

      window.addEventListener(
        "resize",
        debounceOnWidthChange(() => {
          const next = getViewportTier();
          if (lastTier !== next) {
            initStackingStickyCardsBounce();
            lastTier = next;
            window.viewportTier = next;
          }
          if (lenis) lenis.resize();
        }, 250)
      );

      window._hasStackingResizeListener = true;
    }
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", boot);
  } else {
    boot();
  }
})();
````
