GSAP Scroll-triggered Animations with Stylish Typography

<script src="https://unpkg.com/gsap@3/dist/gsap.min.js"></script>
<script src="https://unpkg.com/gsap@3/dist/ScrollTrigger.min.js"></script>

<style>
@import url("https://fonts.googleapis.com/css?family=Signika+Negative:300,400&display=swap");
body {
font-family: "Signika Negative", sans-serif;
font-weight: 300;
font-size: 1rem;
background: black;
}
.section {
padding: 40vh 0 0;
}
.container {
width: 100%;
margin: 0 auto;
max-width: 980px;
}
.list {
padding: 0 0 90vh 0;
}
.list-item {
font-size: 56px;
line-height: 1;
font-weight: 700;
letter-spacing: 0em;
display: inline;
color: white;
opacity: 0.3;
}
</style>

<main>
<section class="section">
<div class="container">
<ul class="list">
<li class="list-item">Up to 2x more Active Noise Cancellation.</li>
<li class="list-item"> Transparency mode to hear the world around you.</li>
<li class="list-item"> All-new Adaptive Audio intelligently tailors noise control to your environment.</li>
<li class="list-item"> Spatial Audio takes immersion to a remarkably personal level.</li>
<li class="list-item"> And a single charge delivers 6 hours of battery life.</li>
</ul>
</div>
</section>
</main>

<script>
const quotes = gsap.utils.toArray(".quote");
const tl = gsap.timeline({
scrollTrigger: {
toggleActions: "play reverse play reverse",
trigger: ".section",
start: "top top",
end: "bottom bottom",
markers: true,
scrub: true
}
});
const items = gsap.utils.toArray(".list-item");
const amount = items.length;
tl.to(items, { stagger: 0.5, opacity: 1 }).to(
items,
{
stagger: 0.75,
opacity: (i) => (i < amount - 1 ? 0.3 : 1)
},
0.5
);
</script>