diff --git a/src/components/MotionController.tsx b/src/components/MotionController.tsx index f95ab3f..3dd6bae 100644 --- a/src/components/MotionController.tsx +++ b/src/components/MotionController.tsx @@ -79,7 +79,8 @@ export const MotionController = () => { }; } - const initialRevealBoundary = window.innerHeight * 0.92; + // Never hide content that was already painted inside the viewport. + const initialRevealBoundary = window.innerHeight; elements.forEach((element) => { const bounds = element.getBoundingClientRect(); if (bounds.top <= initialRevealBoundary && bounds.bottom >= 0) { @@ -105,6 +106,7 @@ export const MotionController = () => { { duration: 600, delay: Math.min(siblingIndex * 50, 250), + fill: 'backwards', easing: 'cubic-bezier(0.16, 1, 0.3, 1)', }, ); diff --git a/src/styles/globals.css b/src/styles/globals.css index 42700b8..7f2a40b 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -210,6 +210,13 @@ button:active:not(:disabled) { border-color: transparent; } +/* Keep pending reveals hidden only after the controller is ready. */ +@media (prefers-reduced-motion: no-preference) { + html[data-motion-ready='true'] :is([data-reveal], [data-footer-reveal]):not([data-visible='true']) { + opacity: 0; + } +} + @media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto;