# Parallax Pinned Chapters + Snap Carousel Design **Date:** 2026-03-05 **Status:** Approved ## Overview Redesign the landing page scroll experience using a "chapter" model. Sections are grouped into 4 chapters that pin (sticky) in place as the user scrolls. Each subsequent chapter slides up and covers the previous one, creating a layered card-stack effect. The services carousel is rebuilt with CSS scroll-snap for native horizontal snapping. ## Chapter Structure | Chapter | Sections | Purpose | | ------- | -------------------------- | --------------- | | 1 | HeroSection + TrustStrip | "Who we are" | | 2 | ServicesCarousel | "What we offer" | | 3 | WhyUsSection + CTABanner | "Why choose us" | | 4 | SupportDownloads + Contact | "Get in touch" | ## Scroll Behavior ### Pinning Mechanism - Each chapter wrapper uses `position: sticky; top: 0` - Chapters stack with increasing `z-index` (1, 2, 3, 4) - Each chapter has a solid background so it fully covers the chapter behind it - A subtle `box-shadow` on the top edge of each chapter creates the "sliding over" depth illusion - The outer container uses `scroll-snap-type: y proximity` for soft vertical snap (helps chapters land cleanly but does not fight free scrolling) ### Chapter Details **Chapter 1: Hero + TrustStrip** - `min-height: 100dvh` to fill the viewport - Hero fills most of the space, TrustStrip anchored at the bottom - Pins in place while Chapter 2 slides up over it - Existing gradient background + dot pattern preserved **Chapter 2: ServicesCarousel** - Natural content height (not forced to viewport height) - Pins in place while Chapter 3 slides up - Carousel rebuilt with CSS scroll-snap (see Carousel section below) **Chapter 3: WhyUs + CTABanner** - Natural content height - Pins in place while Chapter 4 slides up - WhyUs image gets a subtle parallax speed difference (scrolls slightly slower than text) for added depth **Chapter 4: SupportDownloads + Contact** - Normal scroll, no pinning (last chapter, nothing covers it) - Existing fade-in animations preserved ## Carousel Rebuild (CSS Scroll-Snap) The current carousel uses absolute positioning with JS-driven transforms and offset calculations. This will be replaced with a native CSS scroll-snap approach. ### New approach - Horizontal scroll container with `scroll-snap-type: x mandatory` - Each card is a snap point with `scroll-snap-align: center` - Cards are laid out in a flex row, each taking full width of the visible area - Native touch/swipe works out of the box - Dot indicators sync with scroll position via `IntersectionObserver` or `scrollLeft` calculation - Arrow buttons use `scrollBy()` with `behavior: 'smooth'` - Auto-play uses `scrollBy()` and pauses on user interaction (touch, hover, focus) - Personal/Business tab toggle resets scroll position to 0 ### Benefits over current approach - No absolute positioning or transform math - Touch/swipe is native and performant - Reduced JS complexity - Better accessibility (native scroll semantics) - Respects `prefers-reduced-motion` automatically ## Technical Implementation ### New component: ChapterWrapper A reusable wrapper that applies sticky positioning: ```tsx interface ChapterProps { children: React.ReactNode; zIndex: number; className?: string; } function Chapter({ children, zIndex, className }: ChapterProps) { return (
{children}
); } ``` ### Updated PublicLandingView structure ```tsx
{" "} {/* No sticky - last chapter */}
``` ### Shadow/depth effect Each Chapter (except Chapter 1) gets a top shadow to enhance the "sliding over" illusion: ```css .chapter-overlay { box-shadow: 0 -8px 30px -10px rgba(0, 0, 0, 0.1); } ``` ## Mobile Considerations - Use `100dvh` (dynamic viewport height) instead of `100vh` to avoid iOS address bar issues - Carousel CSS scroll-snap is touch-native and works well on mobile - Sticky positioning works on mobile browsers (iOS Safari, Chrome Android) - If performance is poor on low-end devices, sticky can be disabled via a CSS class ## Accessibility - `prefers-reduced-motion: reduce` disables sticky pinning behavior (falls back to normal scroll) - Carousel maintains keyboard navigation (arrow keys, tab through cards) - ARIA attributes preserved: `role="region"`, `aria-roledescription="carousel"`, slide labels - Scroll-snap does not interfere with screen readers ## Files to Modify | File | Change | | ------------------------------------------------------- | --------------------------------------- | | `features/landing-page/views/PublicLandingView.tsx` | Wrap sections in Chapter components | | `features/landing-page/components/ServicesCarousel.tsx` | Rebuild with CSS scroll-snap | | `features/landing-page/components/HeroSection.tsx` | Adjust to fill chapter space (flex-1) | | `features/landing-page/components/TrustStrip.tsx` | Adjust to anchor at bottom of Chapter 1 | | `features/landing-page/hooks/useInfiniteCarousel.ts` | Replace with scroll-snap hook or remove | | `features/landing-page/components/index.ts` | Export new Chapter component | | New: `features/landing-page/components/Chapter.tsx` | Chapter wrapper component | | New: `features/landing-page/hooks/useSnapCarousel.ts` | Hook for scroll-snap carousel state |