- Replaced font references in globals.css to use DM Sans and JetBrains Mono for improved typography consistency. - Adjusted various components to utilize the new font styles, enhancing visual hierarchy and readability. - Updated layout properties in AppShell and Sidebar for better alignment and spacing. - Enhanced button styles to include a new subtle variant for improved UI flexibility. - Refactored SearchFilterBar to support active filter display, improving user interaction experience. - Made minor adjustments to the DashboardView and landing page components for better visual consistency.
5.8 KiB
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-shadowon the top edge of each chapter creates the "sliding over" depth illusion - The outer container uses
scroll-snap-type: y proximityfor soft vertical snap (helps chapters land cleanly but does not fight free scrolling)
Chapter Details
Chapter 1: Hero + TrustStrip
min-height: 100dvhto 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
IntersectionObserverorscrollLeftcalculation - Arrow buttons use
scrollBy()withbehavior: '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-motionautomatically
Technical Implementation
New component: ChapterWrapper
A reusable wrapper that applies sticky positioning:
interface ChapterProps {
children: React.ReactNode;
zIndex: number;
className?: string;
}
function Chapter({ children, zIndex, className }: ChapterProps) {
return (
<section className={cn("sticky top-0", className)} style={{ zIndex }}>
{children}
</section>
);
}
Updated PublicLandingView structure
<main>
<Chapter zIndex={1} className="min-h-dvh">
<HeroSection />
<TrustStrip />
</Chapter>
<Chapter zIndex={2}>
<ServicesCarousel />
</Chapter>
<Chapter zIndex={3}>
<WhyUsSection />
<CTABanner />
</Chapter>
<div>
{" "}
{/* No sticky - last chapter */}
<SupportDownloadsSection />
<ContactSection />
</div>
</main>
Shadow/depth effect
Each Chapter (except Chapter 1) gets a top shadow to enhance the "sliding over" illusion:
.chapter-overlay {
box-shadow: 0 -8px 30px -10px rgba(0, 0, 0, 0.1);
}
Mobile Considerations
- Use
100dvh(dynamic viewport height) instead of100vhto 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: reducedisables 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 |