Marked as helpful by the asker
Add your production URL to Authentication → URL Configuration → Redirect URLs (with /** at the end). Site URL alone is not enough, Supabase only redirects to URLs on that allow-list, otherwise it falls back and the token is consumed on the wrong page.
Second thing to check: some mail clients pre-fetch links to scan them. That consumes the one-time token before you click. Use a PKCE flow (token_hash in the URL) instead of the implicit one; @supabase/ssr does this by default.