diff --git a/src/app/globals.css b/src/app/globals.css index ad33682..8106acc 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -637,8 +637,13 @@ code { /* Card media fades in over the always-present duck fallback layer. */ .media-layer { opacity: 0; transition: opacity 240ms ease; } .media-layer.media-ready { opacity: 1; } +/* ...and the duck fades out with it: the Pollen clips are alpha-transparent + WebMs, so a lingering duck would show through the transparent regions. */ +.media-fallback-card { transition: opacity 240ms ease; } +.media-fallback-card.media-fallback-hidden { opacity: 0; } @media (prefers-reduced-motion: reduce) { - .media-layer { transition: none; } + .media-layer, + .media-fallback-card { transition: none; } } .behavior-media-cue { diff --git a/src/components/MediaPreview.tsx b/src/components/MediaPreview.tsx index ccab490..a836d08 100644 --- a/src/components/MediaPreview.tsx +++ b/src/components/MediaPreview.tsx @@ -138,8 +138,12 @@ export function MediaPreview({ media, title, variant }: MediaPreviewProps) { // case that the hydration race makes untrustworthy via events alone.) useEffect(() => setVideoReady(false), [videoUrl, showVideo]); + // Cards crossfade: when the media layer reveals, the duck fallback fades + // out — necessary because the Pollen clips are alpha-transparent WebMs, + // so an opaque-feeling video would still show the duck through it. + const mediaRevealed = showVideo ? videoReady : imageLoaded; const layerClass = variant === "card" - ? ` media-layer${(showVideo ? videoReady : imageLoaded) ? " media-ready" : ""}` + ? ` media-layer${mediaRevealed ? " media-ready" : ""}` : ""; let mediaNode: ReactNode = null; @@ -199,7 +203,11 @@ export function MediaPreview({ media, title, variant }: MediaPreviewProps) { if (variant === "card") { return ( <> -