Footer onthult zich op scroll. Native CSS scroll-timeline.
// Mechanisme: footer-css-scroll-driven-minimal
// Pure CSS scroll-driven: thin horizontal rule scaleX 0->1, tagline opacity 0->1.
// animation-timeline: view() + animation-range gekoppeld aan entry/cover.
// JS fallback voor non-supporting browsers (scroll-listener + manuele progress).
(() => {
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const supportsTimeline = CSS.supports('animation-timeline: view()');
const root = document.querySelector('.fcs-mn');
if (!root) return;
const rule = root.querySelector('.fcs-mn-rule');
const tagline = root.querySelector('.fcs-mn-tagline');
const word = root.querySelector('.fcs-mn-word');
if (reduce) {
if (rule) rule.style.transform = 'scaleX(1)';
if (tagline) tagline.style.opacity = '1';
if (word) word.style.opacity = '1';
return;
}
if (supportsTimeline) return;
const sentinel = root.querySelector('.fcs-mn-sentinel');
if (!sentinel) return;
const onScroll = () => {
const r = sentinel.getBoundingClientRect();
const vh = window.innerHeight;
const p = Math.max(0, Math.min(1, 1 - (r.top / vh)));
if (rule) rule.style.transform = 'scaleX(' + p + ')';
if (word) word.style.opacity = String(Math.max(0, Math.min(1, (p - 0.15) / 0.4)));
if (tagline) tagline.style.opacity = String(Math.max(0, Math.min(1, (p - 0.4) / 0.4)));
};
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
})(); <!-- Skeleton: footer-css-scroll-driven-minimal -->
<div class="fcs-mn">
<div class="fcs-mn-spacer"></div>
<footer class="fcs-mn-foot">
<div class="fcs-mn-sentinel"></div>
<span class="fcs-mn-eyebrow">end</span>
<h2 class="fcs-mn-word">thanks.</h2>
<hr class="fcs-mn-rule"/>
<p class="fcs-mn-tagline">A studio for motion.</p>
<div class="fcs-mn-meta"><span>blurr</span><span>2026</span></div>
</footer>
</div> /* Styling: footer-css-scroll-driven-minimal */
:root {
--mn-paper: #F4F1EB;
--mn-ink: #0A0A0A;
--mn-rule: rgba(10,10,10,.22);
}
.fcs-mn { background: var(--mn-paper); color: var(--mn-ink); font-family: 'Inter', system-ui, sans-serif; }
.fcs-mn-rule {
transform-origin: left center; transform: scaleX(0);
animation: mnRule 0.8s ease-out both;
animation-timeline: view();
animation-range: entry 5% cover 65%;
}
.fcs-mn-tagline { opacity: 0; animation: mnFade 0.8s ease-out both; animation-timeline: view(); animation-range: cover 35% cover 75%; }
@keyframes mnRule { to { transform: scaleX(1); } }
@keyframes mnFade { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
.fcs-mn-rule { transform: scaleX(1) !important; animation: none !important; }
.fcs-mn-tagline { opacity: 1 !important; animation: none !important; }
}