useEffect fired before the browser had laid out the freshly-rendered
match cards, so getElementById returned null or scrollIntoView ran
before the element was in its final position. Double requestAnimationFrame
waits for React's commit AND the browser's layout pass.
scroll-mt-20 (80 px) adds clearance for the 60 px sticky nav so the
targeted card isn't hidden beneath it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Split all page.tsx files into server wrapper (metadata export) + client.tsx (Apollo/interactive)
- Add robots.ts and sitemap.ts (tournaments, teams, players)
- Add metadataBase, OpenGraph and Twitter card metadata to root layout
- Replace hardcoded worldcup.pivoine.art with NEXT_PUBLIC_SITE_URL env var (sitemap/robots) and relative paths (page metadata, resolved by Next.js against metadataBase)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>