Motion's initial="hidden" rendered opacity:0 in server HTML, making content
invisible until JS hydrated — causing a multi-second blank gap after skeleton
disappearance. Replaced with CSS @keyframes stagger animation that plays
immediately from SSR. Also made color extraction fire-and-forget, merged
duplicate stats queries, and removed redundant dashboard loading.tsx.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace fully client-side dashboard and title detail pages with server
component orchestrators that fetch data directly via service functions,
eliminating extra network round-trips through API routes. Each section
streams independently through its own Suspense boundary.
- Extract getUserStats(), getTitleWithChildren(), getRecommendationsForTitle()
into service layer; update getNewAvailableFeed() to include tmdbId/voteAverage
- Split dashboard into server sections (stats, continue watching, library,
recommendations) with client children for animations
- Split title page into server hero + client interaction provider with shared
context for optimistic mutations across actions and seasons
- Add generateMetadata with OG tags, server-side TMDB ID resolution via
redirect(), loading.tsx and not-found.tsx for both pages
- Add per-section skeleton components, fix ContinueWatchingSkeleton dimensions
- Remove 6 unused API routes (feed/*, titles/[id] GET, titles/[id]/recommendations)
- Remove components/stats-summary.tsx, add lib/types/title.ts for shared types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>