diff --git a/patches/react-native-screens/details.md b/patches/react-native-screens/details.md
new file mode 100644
index 000000000000..e07de39d8108
--- /dev/null
+++ b/patches/react-native-screens/details.md
@@ -0,0 +1,8 @@
+# `react-native-screens` patches
+
+### [react-native-screens+4.15.4+001+delay-freeze-until-paint.patch](react-native-screens+4.15.4+001+delay-freeze-until-paint.patch)
+
+- Reason: Adds `requestAnimationFrame` to `DelayedFreeze` so the screen freeze is deferred until after the current frame is painted. Without this, screens can be frozen while transitional UI states are still visible, causing a visual flicker.
+- Upstream PR/issue: N/A
+- E/App issue: https://github.com/Expensify/App/issues/33725
+- PR introducing patch: https://github.com/Expensify/App/pull/82764
diff --git a/patches/react-native-screens/react-native-screens+4.15.4+001+delay-freeze-until-paint.patch b/patches/react-native-screens/react-native-screens+4.15.4+001+delay-freeze-until-paint.patch
new file mode 100644
index 000000000000..34b81d29b89f
--- /dev/null
+++ b/patches/react-native-screens/react-native-screens+4.15.4+001+delay-freeze-until-paint.patch
@@ -0,0 +1,23 @@
+diff --git a/node_modules/react-native-screens/src/components/helpers/DelayedFreeze.tsx b/node_modules/react-native-screens/src/components/helpers/DelayedFreeze.tsx
+index 443da63..72517fd 100644
+--- a/node_modules/react-native-screens/src/components/helpers/DelayedFreeze.tsx
++++ b/node_modules/react-native-screens/src/components/helpers/DelayedFreeze.tsx
+@@ -12,12 +12,17 @@ function DelayedFreeze({ freeze, children }: FreezeWrapperProps) {
+   // flag used for determining whether freeze should be enabled
+   const [freezeState, setFreezeState] = React.useState(false);
+ 
++  // We use requestAnimationFrame to ensure the current frame is fully painted
++  // before scheduling the freeze. This prevents freezing the screen while
++  // transitional UI states (e.g. opacity from useSingleExecution) are still visible.
+   React.useEffect(() => {
++    let rafID: number;
+     const id = setTimeout(() => {
+-      setFreezeState(freeze);
++      rafID = requestAnimationFrame(() => setFreezeState(freeze));
+     }, 0);
+     return () => {
+       clearTimeout(id);
++      cancelAnimationFrame(rafID);
+     };
+   }, [freeze]);
+ 
diff --git a/patches/react-navigation/@react-navigation+native-stack+7.3.14+003+freeze-screen-below-focused.patch b/patches/react-navigation/@react-navigation+native-stack+7.3.14+003+freeze-screen-below-focused.patch
new file mode 100644
index 000000000000..726fe73f8ecc
--- /dev/null
+++ b/patches/react-navigation/@react-navigation+native-stack+7.3.14+003+freeze-screen-below-focused.patch
@@ -0,0 +1,36 @@
+diff --git a/node_modules/@react-navigation/native-stack/lib/module/views/NativeStackView.native.js b/node_modules/@react-navigation/native-stack/lib/module/views/NativeStackView.native.js
+index 35dfc05..1758a24 100644
+--- a/node_modules/@react-navigation/native-stack/lib/module/views/NativeStackView.native.js
++++ b/node_modules/@react-navigation/native-stack/lib/module/views/NativeStackView.native.js
+@@ -376,9 +376,9 @@ export function NativeStackView({
+         const isModal = modalRouteKeys.includes(route.key);
+         const isPreloaded = preloadedDescriptors[route.key] !== undefined && descriptors[route.key] === undefined;
+ 
+-        // On Fabric, when screen is frozen, animated and reanimated values are not updated
+-        // due to component being unmounted. To avoid this, we don't freeze the previous screen there
+-        const shouldFreeze = isFabric() ? !isPreloaded && !isFocused && !isBelowFocused : !isPreloaded && !isFocused;
++        // Freezing the screen below the focused one is safe on Fabric because
++        // DelayedFreeze defers it to the next macrotask, and transition animations run on the UI thread.
++        const shouldFreeze = !isPreloaded && !isFocused;
+         return /*#__PURE__*/_jsx(SceneView, {
+           index: index,
+           focused: isFocused,
+diff --git a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
+index ca15b1d..3191475 100644
+--- a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
++++ b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx
+@@ -542,11 +542,9 @@ export function NativeStackView({
+             preloadedDescriptors[route.key] !== undefined &&
+             descriptors[route.key] === undefined;
+ 
+-          // On Fabric, when screen is frozen, animated and reanimated values are not updated
+-          // due to component being unmounted. To avoid this, we don't freeze the previous screen there
+-          const shouldFreeze = isFabric()
+-            ? !isPreloaded && !isFocused && !isBelowFocused
+-            : !isPreloaded && !isFocused;
++          // Freezing the screen below the focused one is safe on Fabric because
++          // DelayedFreeze defers it to the next macrotask, and transition animations run on the UI thread.
++          const shouldFreeze = !isPreloaded && !isFocused;
+ 
+           return (
+             <SceneView
diff --git a/patches/react-navigation/details.md b/patches/react-navigation/details.md
index 353fac20ab40..5d7ef976c7b8 100644
--- a/patches/react-navigation/details.md
+++ b/patches/react-navigation/details.md
@@ -39,6 +39,14 @@
 - PR Introducing Patch: [#37891](https://github.com/Expensify/App/pull/37891)
 - PR Updating Patch: [#64155](https://github.com/Expensify/App/pull/64155) 
 
+### [@react-navigation+native-stack+7.3.14+003+freeze-screen-below-focused.patch](@react-navigation+native-stack+7.3.14+003+freeze-screen-below-focused.patch)
+
+- Reason: Removes the `isBelowFocused` exception on Fabric that prevented freezing the screen directly below the focused one. This is now safe because `DelayedFreeze` in `react-native-screens` defers freezing to the next macrotask, and native-stack transition animations run on the UI thread independently of the React tree.
+- Upstream PR/issue: N/A
+- E/App issue: N/A
+- PR Introducing Patch: https://github.com/Expensify/App/pull/82764
+- PR Updating Patch: N/A
+
 ### [@react-navigation+native+7.1.10+001+initial.patch](@react-navigation+native+7.1.10+001+initial.patch)
 
 - Reason: Allows us to use some more advanced navigation actions without messing up the browser history
@@ -75,4 +83,4 @@
 - Upstream PR/issue: N/A
 - E/App issue: [#65709](https://github.com/Expensify/App/issues/65211)
 - PR Introducing Patch: [#65836](https://github.com/Expensify/App/pull/66890)
-- PR Updating Patch: N/A
\ No newline at end of file
+- PR Updating Patch: N/A
diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx
index 4483297f6a1b..96607dc9b1d5 100644
--- a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx
+++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx
@@ -41,6 +41,7 @@ const SplitNavigatorComponent = createPlatformStackNavigatorComponent('SplitNavi
     defaultScreenOptions: defaultPlatformStackScreenOptions,
     useCustomState: useCustomSplitNavigatorState,
     NavigationContentWrapper: SidebarSpacerWrapper,
+    freezeNonTopScreens: true,
 });
 
 function createSplitNavigator<
diff --git a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/ScreenFreezeWrapper.tsx b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/ScreenFreezeWrapper.tsx
new file mode 100644
index 000000000000..ca6e1e2ba641
--- /dev/null
+++ b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/ScreenFreezeWrapper.tsx
@@ -0,0 +1,35 @@
+import React, {useLayoutEffect, useState} from 'react';
+import {Freeze} from 'react-freeze';
+import TooltipSense from '@components/Tooltip/TooltipSense';
+
+type ScreenFreezeWrapperProps = {
+    /** Whether the screen is not currently visible to the user */
+    isScreenBlurred: boolean;
+
+    /** The screen content to freeze when blurred */
+    children: React.ReactNode;
+};
+
+function ScreenFreezeWrapper({isScreenBlurred, children}: ScreenFreezeWrapperProps) {
+    const [frozen, setFrozen] = useState(false);
+
+    // Decouple the Suspense render task so it won't be interrupted by React's concurrent mode
+    // and stuck in an infinite loop
+    useLayoutEffect(() => {
+        if (!TooltipSense.isActive() || !isScreenBlurred) {
+            // eslint-disable-next-line react-hooks/set-state-in-effect
+            setFrozen(isScreenBlurred);
+        }
+
+        // When a tooltip is active, defer freezing by one frame so it can dismiss first.
+        // Otherwise the frozen tree can't hide the tooltip portal rendered on <body>.
+        const id = requestAnimationFrame(() => setFrozen(isScreenBlurred));
+        return () => {
+            cancelAnimationFrame(id);
+        };
+    }, [isScreenBlurred]);
+
+    return <Freeze freeze={frozen}>{children}</Freeze>;
+}
+
+export default ScreenFreezeWrapper;
diff --git a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx
index 730e269d507a..495ca5c25d39 100644
--- a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx
+++ b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx
@@ -13,6 +13,7 @@ import type {
     PlatformStackNavigatorProps,
     PlatformStackRouterOptions,
 } from '@libs/Navigation/PlatformStackNavigation/types';
+import ScreenFreezeWrapper from './ScreenFreezeWrapper';
 
 function createPlatformStackNavigatorComponent<RouterOptions extends PlatformStackRouterOptions = PlatformStackRouterOptions>(
     displayName: string,
@@ -24,6 +25,7 @@ function createPlatformStackNavigatorComponent<RouterOptions extends PlatformSta
     const ExtraContent = options?.ExtraContent;
     const NavigationContentWrapper = options?.NavigationContentWrapper;
     const useCustomEffects = options?.useCustomEffects ?? (() => undefined);
+    const freezeNonTopScreens = options?.freezeNonTopScreens;
 
     function PlatformNavigator({
         id,
@@ -100,6 +102,25 @@ function createPlatformStackNavigatorComponent<RouterOptions extends PlatformSta
             };
         }, [persistentScreens, state]);
 
+        // Wrap each screen's render function with ScreenFreezeWrapper to freeze non-top screens.
+        // This prevents off-screen components from re-rendering.
+        // Persistent screens (e.g. sidebar) are excluded from freezing so they stay interactive.
+        let wrappedDescriptors = descriptors;
+        if (freezeNonTopScreens) {
+            const topRouteKey = state.routes[state.index]?.key;
+            const result: typeof descriptors = {};
+            for (const [key, descriptor] of Object.entries(descriptors)) {
+                const isOnTop = key === topRouteKey;
+                const isPersistent = persistentScreens?.includes(descriptor.route.name);
+                const isScreenBlurred = !isOnTop && !isPersistent;
+                result[key] = {
+                    ...descriptor,
+                    render: () => <ScreenFreezeWrapper isScreenBlurred={isScreenBlurred}>{descriptor.render()}</ScreenFreezeWrapper>,
+                };
+            }
+            wrappedDescriptors = result;
+        }
+
         const Content = useMemo(
             () => (
                 <NavigationContent>
@@ -108,7 +129,7 @@ function createPlatformStackNavigatorComponent<RouterOptions extends PlatformSta
                         {...props}
                         direction="ltr"
                         state={mappedState}
-                        descriptors={descriptors}
+                        descriptors={wrappedDescriptors}
                         navigation={navigation}
                         describe={describe}
                     />
@@ -119,7 +140,7 @@ function createPlatformStackNavigatorComponent<RouterOptions extends PlatformSta
                     )}
                 </NavigationContent>
             ),
-            [NavigationContent, customCodePropsWithCustomState, describe, descriptors, mappedState, navigation, props],
+            [NavigationContent, customCodePropsWithCustomState, describe, wrappedDescriptors, mappedState, navigation, props],
         );
 
         // eslint-disable-next-line react/jsx-props-no-spreading
diff --git a/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts b/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts
index 87d8141437a5..eb0c95880c86 100644
--- a/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts
@@ -56,6 +56,7 @@ type CreatePlatformStackNavigatorComponentOptions<RouterOptions extends Platform
     useCustomEffects?: CustomEffectsHook<ParamList>;
     ExtraContent?: ExtraContent;
     NavigationContentWrapper?: NavigationContentWrapper;
+    freezeNonTopScreens?: boolean;
 };
 
 export type {CustomCodeProps, CustomStateHookProps, CustomEffectsHookProps, CreatePlatformStackNavigatorComponentOptions, ExtraContentProps};
diff --git a/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/index.tsx b/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/index.tsx
index 72c272305de0..779bfbd03da7 100644
--- a/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/index.tsx
+++ b/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/index.tsx
@@ -166,11 +166,12 @@ function AttachmentModalBaseContent({
             return;
         }
 
-        if (onConfirm) {
-            onConfirm(Object.assign(files ?? {}, {source} as FileObject));
-        }
-
         onClose?.();
+
+        // Defer onConfirm to the next frame so the target screen has time to unfreeze and re-mount its refs (e.g. composerRef.clearWorklet)
+        requestAnimationFrame(() => {
+            onConfirm?.(Object.assign(files ?? {}, {source} as FileObject));
+        });
     }, [isConfirmButtonDisabled, onConfirm, onClose, files, source]);
 
     // Close the modal when the escape key is pressed
diff --git a/src/pages/workspace/members/WorkspaceInviteMessageComponent.tsx b/src/pages/workspace/members/WorkspaceInviteMessageComponent.tsx
index 4e95f50ca45d..267cfc26ae48 100644
--- a/src/pages/workspace/members/WorkspaceInviteMessageComponent.tsx
+++ b/src/pages/workspace/members/WorkspaceInviteMessageComponent.tsx
@@ -142,7 +142,7 @@ function WorkspaceInviteMessageComponent({
         }
 
         if ((backTo as string)?.endsWith('members')) {
-            Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.dismissModal());
+            Navigation.dismissModal();
             return;
         }
 
diff --git a/src/setup/index.ts b/src/setup/index.ts
index 1c8f5655ff0d..87c461a69442 100644
--- a/src/setup/index.ts
+++ b/src/setup/index.ts
@@ -2,6 +2,7 @@ import toSortedPolyfill from 'array.prototype.tosorted';
 import {I18nManager} from 'react-native';
 import Config from 'react-native-config';
 import Onyx from 'react-native-onyx';
+import {enableFreeze} from 'react-native-screens';
 import intlPolyfill from '@libs/IntlPolyfill';
 import {setDeviceID} from '@userActions/Device';
 import initOnyxDerivedValues from '@userActions/OnyxDerived';
@@ -14,6 +15,10 @@ import telemetry from './telemetry';
 const enableDevTools = Config?.USE_REDUX_DEVTOOLS ? Config.USE_REDUX_DEVTOOLS === 'true' : true;
 
 export default function () {
+    // Enable screen freezing on mobile to prevent unnecessary re-renders on screens that are not visible to the user.
+    // This is a no-op on web — for web, we use ScreenFreezeWrapper in SplitNavigator instead.
+    enableFreeze(true);
+
     telemetry();
 
     toSortedPolyfill.shim();
