From 6cead72ee1dee07c46e4443354e3976501c0ff5c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 02:19:15 +0000 Subject: [PATCH] feat(ui): refine mobile active state and fix desktop regression - Restrict `VideoCard` mobile active state detection to mobile devices (<1024px) using `window.matchMedia` - Tighten `IntersectionObserver` sweet spot to 10% (rootMargin: -45%) to prevent multiple cards being active - Encapsulate mobile active CSS rules within media query to prevent desktop style regression - Ensure proper marquee scrolling behavior on mobile by separating static and animated states - Prevent layout blowouts by enforcing `min-width: 0` on flex containers --- css/tailwind.source.css | 21 +++++++++++++++++---- js/ui/components/VideoCard.js | 14 +++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/css/tailwind.source.css b/css/tailwind.source.css index 1c2391f3..dd8a8feb 100644 --- a/css/tailwind.source.css +++ b/css/tailwind.source.css @@ -1130,8 +1130,7 @@ } .card:hover, - .card:focus-within, - .card[data-mobile-active="true"] { + .card:focus-within { --video-card-lift-translate-y: var(--motion-video-card-hover-translate); --video-card-backdrop-opacity: 0.425; --video-card-backdrop-translate-y: var( @@ -1163,8 +1162,7 @@ } .video-card__title:hover, - .video-card__title:focus-visible, - .card[data-mobile-active="true"] .video-card__title { + .video-card__title:focus-visible { color: var(--color-accent); } @@ -5914,6 +5912,21 @@ /* Mobile Active State */ @media (max-width: calc(theme("screens.lg") - var(--breakpoint-edge-offset))) { + .card[data-mobile-active="true"] { + --video-card-lift-translate-y: var(--motion-video-card-hover-translate); + --video-card-backdrop-opacity: 0.425; + --video-card-backdrop-translate-y: var( + --motion-video-card-backdrop-translate + ); + --video-card-backdrop-scale: 1.12; + --video-card-backdrop-blur: var(--blur-video-card-backdrop-strong); + @apply shadow-lg; + } + + .card[data-mobile-active="true"] .video-card__title { + color: var(--color-accent); + } + .card[data-mobile-active="true"] .marquee-host.can-marquee .marquee-static { opacity: 0; } diff --git a/js/ui/components/VideoCard.js b/js/ui/components/VideoCard.js index 7ca6f585..94f2ec11 100644 --- a/js/ui/components/VideoCard.js +++ b/js/ui/components/VideoCard.js @@ -3043,7 +3043,19 @@ export class VideoCard { if (!VideoCard.viewportObserver) { VideoCard.viewportObserver = new IntersectionObserver( (entries) => { + // Prevent active state on desktop to avoid conflicting with hover + const isDesktop = + typeof window !== "undefined" && + window.matchMedia("(min-width: 1024px)").matches; + for (const entry of entries) { + if (isDesktop) { + if (entry.target.hasAttribute("data-mobile-active")) { + entry.target.removeAttribute("data-mobile-active"); + } + continue; + } + if (entry.isIntersecting) { entry.target.setAttribute("data-mobile-active", "true"); } else { @@ -3051,7 +3063,7 @@ export class VideoCard { } } }, - { rootMargin: "-25% 0px -25% 0px", threshold: 0 } + { rootMargin: "-45% 0px -45% 0px", threshold: 0 } ); } VideoCard.viewportObserver.observe(element);