diff --git a/src/app/components/editorial-ui.tsx b/src/app/components/editorial-ui.tsx index 722fb98..364879a 100644 --- a/src/app/components/editorial-ui.tsx +++ b/src/app/components/editorial-ui.tsx @@ -18,10 +18,20 @@ export function Reveal({ useEffect(() => { const el = ref.current; if (!el) return; - if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) { - el.classList.add("is-in"); - return; - } + if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return; + + // Only animate what starts below the fold. Anything already on screen stays + // visible — otherwise the hero fades in after the section beneath it. + const rect = el.getBoundingClientRect(); + const onScreen = rect.top < window.innerHeight && rect.bottom > 0; + if (onScreen) return; + + // Hide it without a transition, then reveal when it scrolls into view. + el.style.transition = "none"; + el.classList.add("reveal-armed"); + void el.offsetHeight; + el.style.transition = ""; + const io = new IntersectionObserver( (entries) => { for (const e of entries) { diff --git a/src/app/globals.css b/src/app/globals.css index aa71895..c941271 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -230,15 +230,19 @@ html[data-device="phone"] .desktop-toggle { Motion — scroll reveals only ------------------------------------------------------------------ */ +/* Visible by default: Reveal only hides elements that start below the fold, so + above-the-fold content (the hero) is never hidden while waiting for JS. */ .reveal { - opacity: 0; - transform: translate3d(0, 14px, 0); transition: opacity 0.55s ease-out, transform 0.55s ease-out; transition-delay: var(--delay, 0ms); } -.reveal.is-in { +.reveal.reveal-armed { + opacity: 0; + transform: translate3d(0, 14px, 0); +} +.reveal.reveal-armed.is-in { opacity: 1; transform: none; } @@ -262,8 +266,8 @@ html[data-device="phone"] .desktop-toggle { scroll-behavior: auto; } .reveal { - opacity: 1; - transform: none; + opacity: 1 !important; + transform: none !important; transition: none; } .animate-blink {