diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml
index c7b8a1bb7e01..380b874c6c95 100644
--- a/.github/workflows/e2ePerformanceTests.yml
+++ b/.github/workflows/e2ePerformanceTests.yml
@@ -113,6 +113,8 @@ jobs:
 
       - name: Setup Node
         uses: ./.github/actions/composite/setupNode
+        with:
+          IS_DESKTOP_BUILD: 'true'
 
       - name: Make zip directory for everything to send to AWS Device Farm
         run: mkdir zip
diff --git a/Mobile-Expensify b/Mobile-Expensify
index 75361a078c87..1f1c233f53e0 160000
--- a/Mobile-Expensify
+++ b/Mobile-Expensify
@@ -1 +1 @@
-Subproject commit 75361a078c8792ae3a4f7b145c77d32357297ed2
+Subproject commit 1f1c233f53e03d601039a5ed41ca84ee9ae8a1e8
diff --git a/android/app/build.gradle b/android/app/build.gradle
index ddbc3ceb9033..7e8b398f1268 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -114,8 +114,8 @@ android {
         minSdkVersion rootProject.ext.minSdkVersion
         targetSdkVersion rootProject.ext.targetSdkVersion
         multiDexEnabled rootProject.ext.multiDexEnabled
-        versionCode 1009011207
-        versionName "9.1.12-7"
+        versionCode 1009011300
+        versionName "9.1.13-0"
         // Supported language variants must be declared here to avoid from being removed during the compilation.
         // This also helps us to not include unnecessary language variants in the APK.
         resConfigs "en", "es"
diff --git a/android/app/src/main/java/com/expensify/chat/navbar/NavBarManagerModule.kt b/android/app/src/main/java/com/expensify/chat/navbar/NavBarManagerModule.kt
index 5c566df606eb..dd02d8aba1bd 100644
--- a/android/app/src/main/java/com/expensify/chat/navbar/NavBarManagerModule.kt
+++ b/android/app/src/main/java/com/expensify/chat/navbar/NavBarManagerModule.kt
@@ -1,10 +1,12 @@
 package com.expensify.chat.navbar
 
+import android.content.res.Resources
 import androidx.core.view.WindowInsetsControllerCompat
+import com.expensify.chat.R
 import com.facebook.react.bridge.ReactApplicationContext
 import com.facebook.react.bridge.ReactContextBaseJavaModule
 import com.facebook.react.bridge.ReactMethod
-import com.facebook.react.bridge.UiThreadUtil;
+import com.facebook.react.bridge.UiThreadUtil
 
 class NavBarManagerModule(
     private val mReactContext: ReactApplicationContext,
@@ -24,4 +26,18 @@ class NavBarManagerModule(
             }
         }
     }
+
+    @ReactMethod
+    fun getType(): String {
+        val resources = mReactContext.resources
+        val resourceId = resources.getIdentifier("config_navBarInteractionMode", "integer", "android");
+        if (resourceId > 0) {
+            val navBarInteractionMode = resources.getInteger(resourceId)
+            when (navBarInteractionMode) {
+                0, 1 -> return "soft-keys"
+                2 -> return "gesture-bar"
+            }
+        }
+        return "soft-keys";
+    }
 }
diff --git a/assets/images/product-illustrations/emptystate__receiptfairy.svg b/assets/images/product-illustrations/emptystate__receiptfairy.svg
new file mode 100644
index 000000000000..ccdeda5926f8
--- /dev/null
+++ b/assets/images/product-illustrations/emptystate__receiptfairy.svg
@@ -0,0 +1,154 @@
+<svg width="148" height="180" viewBox="0 0 148 180" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M38.8328 58.0929C38.8328 58.0929 34.6354 57.9801 33.6149 61.7237C32.5943 65.4673 34.5225 67.7365 36.4507 68.757C36.4507 68.757 37.061 69.2519 38.379 69.0981C39.6969 68.9442 40.761 68.4186 40.761 68.4186C40.761 68.4186 47.2277 81.0109 62.6533 80.8955C78.079 80.7801 83.8661 73.5211 84.8866 66.4904C85.9072 59.457 84.32 53.4442 80.802 47.8878C77.2866 42.3288 76.0379 40.4006 76.0379 40.4006L49.4943 40.7417C49.4943 40.7417 38.7174 49.1365 38.8302 58.0981L38.8328 58.0929Z" fill="#F2C8AA"/>
+<path d="M64.5842 124.678C64.5842 124.678 65.5714 125.822 66.0586 126.947C66.5458 128.073 67.5329 129.104 68.3278 129.558C69.1227 130.011 71.0509 130.691 71.0509 130.691C71.0509 130.691 72.4124 130.578 72.6381 128.988C72.6381 128.988 74.6791 128.081 74.5663 126.832L75.474 124.791C75.474 124.791 76.8355 123.77 76.2689 122.635C75.7022 121.499 75.0201 120.819 75.0201 120.819L71.1637 119.686L68.7817 119.46C68.7817 119.46 65.1509 121.501 64.5842 124.678Z" fill="#F2C8AA"/>
+<path d="M111.546 87.4742C111.546 87.4742 114.381 90.3101 114.381 93.487C114.381 93.487 115.969 93.146 116.538 93.146H127.54L127.766 92.1255L127.653 91.3306L127.766 88.4947V87.1332C127.766 87.1332 127.671 85.1562 125.838 85.0921C124.005 85.028 117.897 85.0921 117.897 85.0921L118.379 84.0152C118.379 84.0152 119.392 82.5024 118.72 82.0588C118.048 81.6152 116.933 81.9742 116.507 82.4844C116.081 82.9947 114.381 84.7819 114.125 84.9511C113.869 85.1203 111.546 87.4742 111.546 87.4742Z" fill="#F2C8AA"/>
+<path d="M49.3842 40.368C49.3842 40.368 49.6586 41.5578 49.8945 41.5603C50.1304 41.5629 58.9124 43.1757 65.5483 43.0911C72.1842 43.0065 76.438 41.0501 76.438 41.0501C76.438 41.0501 72.4406 22.9296 66.6534 15.2731C61.0381 6.76545 54.9124 2.93725 51.1688 1.83212C47.4252 0.726989 50.3175 5.57571 50.4022 6.17058C50.4868 6.76545 52.8688 19.1013 51.6791 27.5244C50.4868 35.9475 49.3816 40.3706 49.3816 40.3706L49.3842 40.368Z" fill="#0185FF"/>
+<path d="M37.3585 81.8024C37.3585 81.8024 30.2123 86.2255 29.5302 92.2383C28.8482 98.2511 33.6149 102.674 38.4918 104.261C43.3687 105.849 46.5456 106.531 46.5456 106.531C46.5456 106.531 50.8559 118.554 60.3841 122.979L62.9944 124.113L65.9431 117.646C65.9431 117.646 59.0226 113.561 56.6405 107.664C56.6405 107.664 70.1405 107.89 73.8815 107.323C77.6226 106.756 87.9482 104.713 89.9892 103.692C92.0303 102.672 92.7123 102.897 93.8456 103.013C94.979 103.125 106.323 102.218 112.11 95.6383L108.82 89.9665C108.82 89.9665 101.561 95.4101 97.0226 95.5255C97.0226 95.5255 99.179 89.0588 91.1251 84.5229C83.0713 79.9844 80.2354 77.2639 80.2354 77.2639C80.2354 77.2639 70.3662 83.6152 63.6739 83.3896C56.9815 83.1639 40.9867 80.8947 40.9867 80.8947L37.3559 81.8024H37.3585Z" fill="#0185FF"/>
+<path d="M44.4483 73.2941C44.4483 73.2941 43.5124 77.1223 40.6201 79.1633C37.7277 81.2043 36.1098 83.6736 35.9406 84.4377C35.7713 85.2018 35.5995 87.671 39.0021 87.7556C42.4047 87.8402 46.9149 84.4377 46.9149 84.4377C46.9149 84.4377 46.4893 87.8402 51.2534 88.1812C56.0175 88.5223 57.379 85.3736 57.379 85.3736C57.379 85.3736 59.8457 88.4351 63.4201 88.1812C66.9944 87.9248 67.8431 85.5428 67.8431 85.5428C67.8431 85.5428 71.4175 88.4351 74.6482 88.0941C77.879 87.753 78.4765 84.6915 78.4765 84.6915C78.4765 84.6915 83.8354 89.2018 88.0893 87.9248C90.9816 87.2454 89.8764 84.1812 89.1944 83.5018C88.5149 82.8223 84.5149 80.6095 84.5149 80.6095C84.5149 80.6095 81.0277 78.312 80.9406 74.653C80.9406 74.653 77.3662 80.5223 64.7765 80.6941C52.1841 80.8633 45.5483 75.5889 44.4431 73.2915L44.4483 73.2941Z" fill="#CCF6FF"/>
+<path d="M33.3046 63.4252C33.3046 63.4252 33.8148 60.4482 34.92 59.5124C36.0251 58.5765 38.8328 58.0944 38.8328 58.0944C38.8328 58.0944 40.1943 51.3457 42.32 48.7072L49.1251 40.9662L48.4456 39.52C48.4456 39.52 46.4046 34.7559 36.5353 34.1611C26.6661 33.5662 22.8379 45.1354 22.7533 46.6662C22.6687 48.197 22.9225 55.8534 26.4969 59.5124C30.0713 63.1713 33.302 63.4252 33.302 63.4252H33.3046Z" fill="#E96DF2"/>
+<path d="M38.8326 58.0944C38.8326 58.0944 40.1685 57.997 40.9583 58.8329C41.748 59.6687 44.107 63.2559 45.8916 63.4277C45.8916 63.4277 45.1249 57.8123 45.807 55.1764C46.489 52.5405 48.6147 49.8175 49.3814 48.8816C50.148 47.9457 53.6352 44.1175 53.5506 42.2457L50.3172 41.479L49.125 40.9688C49.125 40.9688 40.7532 46.7662 38.8301 58.097L38.8326 58.0944Z" fill="#E96DF2"/>
+<path d="M42.3224 48.7055C42.3224 48.7055 47.7378 41.985 49.1275 40.9644L49.4967 39.7157C49.4967 39.7157 44.2224 39.0644 42.8044 41.7568C41.3865 44.4516 41.3865 46.2362 42.3224 48.7055Z" fill="#FED607"/>
+<path d="M60.3304 56.3909C62.868 56.3909 64.9252 53.9273 64.9252 50.8883C64.9252 47.8493 62.868 45.3857 60.3304 45.3857C57.7927 45.3857 55.7355 47.8493 55.7355 50.8883C55.7355 53.9273 57.7927 56.3909 60.3304 56.3909Z" fill="#FFFAF0"/>
+<path d="M72.1994 55.453C73.4225 54.4633 74.225 52.7889 74.225 50.8915C74.225 47.853 72.1686 45.3889 69.6302 45.3889C67.0917 45.3889 65.0353 47.853 65.0353 50.8915C65.0353 51.4761 65.1122 52.0402 65.2532 52.5684C65.2532 52.5684 67.0532 54.7428 67.7584 54.9171C68.4635 55.0915 70.5943 55.2581 70.5943 55.2581" fill="#FFFAF0"/>
+<path d="M59.5071 64.361L58.8276 65.8072C58.8276 65.8072 61.2943 71.1661 68.0148 70.4867C74.7353 69.8072 75.843 64.8713 75.843 64.8713L74.9071 63.679C74.9071 63.679 70.9379 66.1456 67.1661 65.8918C63.3943 65.6354 59.5097 64.361 59.5097 64.361H59.5071Z" fill="#FFFAF0"/>
+<path d="M59.5071 64.3598C59.5071 64.3598 65.9737 65.8905 68.0148 65.8905C70.0558 65.8905 74.9071 63.6777 74.9071 63.6777C74.9071 63.6777 72.4404 60.9546 70.3968 61.2957C68.3558 61.6367 67.2481 63.4213 67.2481 63.4213C67.2481 63.4213 65.2071 61.4649 63.6737 61.4649C62.1404 61.4649 59.6763 63.8469 59.5045 64.3572L59.5071 64.3598Z" fill="#0185FF"/>
+<path d="M58.9968 67.337C58.9968 67.337 60.0737 73.9165 67.7609 74.1422C75.4455 74.3678 75.5891 65.8037 75.5891 65.8037C75.5891 65.8037 72.7814 70.6524 67.5917 70.4832C62.4019 70.314 58.9994 67.3345 58.9994 67.3345L58.9968 67.337Z" fill="#0185FF"/>
+<path d="M87.8384 104.829C87.8384 104.829 67.9871 109.48 56.6435 107.665C56.6435 107.665 61.1819 115.493 67.7589 118.554L70.7076 119.575L75.0179 120.824C75.0179 120.824 76.8332 122.752 76.1512 123.772C75.4717 124.793 75.4717 125.247 75.4717 125.247L73.8845 128.082L72.6358 128.99C72.6358 128.99 73.0897 130.011 72.0691 130.352C71.0486 130.693 70.0281 130.465 70.0281 130.465L66.3973 127.97L64.5819 124.68C64.5819 124.68 50.8563 120.141 46.5461 106.531L38.4922 104.262C38.4922 104.262 21.8178 109.593 20.9102 133.3L25.2204 142.603C25.2204 142.603 59.2512 150.657 70.1409 149.408C81.0307 148.159 102.81 140.447 102.81 140.447C102.81 140.447 100.541 126.721 96.9127 121.39C93.2845 116.059 87.9512 110.726 87.8384 104.829Z" fill="#CCF6FF"/>
+<path d="M38.4945 104.26C38.4945 104.26 29.1919 101.311 29.3073 93.1447C29.4201 86.9063 35.2048 83.2755 35.2048 83.2755C35.2048 83.2755 44.6201 77.6037 44.4509 73.2934C44.4509 73.2934 42.0458 70.3447 40.7637 68.4165C40.7637 68.4165 40.3099 69.437 38.3817 69.096C36.4535 68.755 35.8868 68.3011 35.2048 67.6216C34.5253 66.9422 33.5022 64.2191 33.5022 64.2191C33.5022 64.2191 30.0996 62.2909 26.2432 62.4037C22.3868 62.5165 11.0432 67.055 10.2484 75.6755C10.2484 75.6755 1.06116 81.9139 1.2868 91.7832C1.51245 101.652 8.20733 109.14 15.4663 110.273C21.1381 111.293 25.2227 108.799 26.015 108.686C26.8073 108.573 32.0278 106.983 33.5022 107.099L38.4945 104.263V104.26Z" fill="#FFF2B2"/>
+<path d="M36.1968 75.5925C36.1968 75.5925 36.7634 75.5669 36.8763 74.9976L36.9891 74.4258L37.8122 74.6566L38.6634 74.1464L39.5147 75.3387L40.1096 75.4233L40.366 73.7207L40.6224 72.1899C40.6224 72.1899 40.7916 71.0848 40.1968 70.8284C39.6019 70.572 38.1557 70.7438 38.1557 70.7438L36.1993 70.6592C36.1993 70.6592 35.2891 71.0694 35.2634 71.3387C35.2378 71.6079 35.4327 73.5515 35.4327 73.5515L36.1993 75.5925H36.1968Z" fill="#FFFAF0"/>
+<path d="M38.2455 70.5369C38.8332 70.5369 39.3096 70.0605 39.3096 69.4728C39.3096 68.8851 38.8332 68.4087 38.2455 68.4087C37.6578 68.4087 37.1814 68.8851 37.1814 69.4728C37.1814 70.0605 37.6578 70.5369 38.2455 70.5369Z" fill="#FED607"/>
+<path d="M21.2224 131.657C21.2224 131.657 20.1173 141.442 20.8814 146.206C20.8814 146.206 30.4096 152.585 61.7173 153.352C93.025 154.119 103.489 146.29 103.489 146.29C103.489 146.29 102.043 134.039 101.107 131.742C101.107 131.742 95.9173 131.231 94.8122 139.57C94.8122 139.57 91.325 132.167 85.8788 132.765C80.4353 133.36 78.1378 141.188 78.1378 141.188C78.1378 141.188 75.5865 133.785 70.3968 133.701C65.2071 133.616 61.2096 142.124 61.2096 142.124C61.2096 142.124 57.9763 134.211 52.0224 134.042C46.066 133.872 43.684 141.613 43.684 141.613C43.684 141.613 42.9173 133.275 36.8789 133.106C30.8404 132.937 29.0506 139.572 29.0506 139.572C29.0506 139.572 26.584 131.406 21.2224 131.66V131.657Z" fill="#0185FF"/>
+<path d="M70.8225 120.255C70.8225 120.255 72.9199 122.296 74.3969 122.296L77.1199 117.248C77.1199 117.248 79.6712 116.453 79.3328 113.05C79.3328 113.05 80.7507 114.355 81.602 114.127C82.4533 113.901 83.0199 112.54 83.0763 111.971C83.1327 111.401 83.361 109.532 83.984 109.135C84.6071 108.737 87.9533 108.227 88.0122 107.263C88.0712 106.299 87.9866 105.486 87.4456 105.165C86.9045 104.845 84.5533 103.181 84.5533 103.181C84.5533 103.181 84.3276 102.104 84.2686 101.707C84.2097 101.309 84.1558 98.586 83.2481 98.3039C82.3404 98.0219 81.661 98.4732 81.4328 98.645C81.2046 98.8168 79.4481 100.742 78.8815 100.686C78.3148 100.63 75.0815 99.8347 75.0815 99.8347C75.0815 99.8347 73.6635 100.004 73.4379 100.686C73.2122 101.368 73.7225 102.501 73.7225 102.501C73.7225 102.501 74.6866 105.053 74.402 105.791C74.1174 106.53 72.4174 108.912 72.4174 108.912C72.4174 108.912 72.1328 110.104 73.3251 110.442L74.5174 110.783L74.2917 111.407C74.2917 111.407 72.1353 112.712 73.3276 115.435L70.8327 120.255H70.8225Z" fill="#FED607"/>
+<path d="M69.6893 130.239L66.3996 127.97L59.9329 140.277C59.9329 140.277 57.2098 140.165 56.9278 141.129C56.6431 142.093 58.7432 144.077 58.7432 144.077C58.7432 144.077 56.3047 144.985 55.8508 146.459C55.397 147.934 56.2483 149.521 57.2688 149.918C58.2893 150.316 60.5021 150.316 61.0688 149.295C61.6355 148.275 61.6919 147.254 61.6354 146.913C61.579 146.572 61.0124 144.872 61.0124 144.872C61.0124 144.872 64.0175 145.78 64.4714 144.703C64.9252 143.626 63.3944 142.152 63.3944 142.152L69.6893 130.242V130.239Z" fill="#FED607"/>
+<path d="M76.1533 117.024C77.7506 117.024 79.0456 115.729 79.0456 114.131C79.0456 112.534 77.7506 111.239 76.1533 111.239C74.5559 111.239 73.261 112.534 73.261 114.131C73.261 115.729 74.5559 117.024 76.1533 117.024Z" fill="#FEE45E"/>
+<path d="M58.7995 150.088C60.2722 150.088 61.4662 148.894 61.4662 147.421C61.4662 145.949 60.2722 144.755 58.7995 144.755C57.3267 144.755 56.1328 145.949 56.1328 147.421C56.1328 148.894 57.3267 150.088 58.7995 150.088Z" fill="#FEE45E"/>
+<path d="M64.6319 144.329C64.9889 143.358 63.562 141.94 61.4449 141.161C59.3278 140.383 57.3221 140.538 56.9652 141.508C56.6082 142.478 58.0351 143.896 60.1522 144.675C62.2693 145.454 64.275 145.299 64.6319 144.329Z" fill="#FEE45E"/>
+<path d="M49.3839 40.3689C49.3839 40.3689 49.8941 41.3048 50.3198 41.4741C50.7454 41.6433 54.9429 42.2125 54.9429 42.2125L55.4531 41.3613L56.9839 39.3202L56.8711 38.9792L53.5249 38.6946L51.7659 35.6895L51.3685 36.1997L50.2352 38.81L49.8942 39.0946L49.3839 40.3715V40.3689Z" fill="#FED607"/>
+<path d="M59.5918 34.7802L61.8046 36.9366V40.3956L64.9251 38.8648L68.1559 39.9982L67.7021 36.4828L69.7456 33.9315L66.3995 33.3059L64.4123 30.47L64.0738 30.8674L62.8815 33.5341L60.1585 34.1572L59.5918 34.7802Z" fill="#FED607"/>
+<path d="M75.4736 36.1426L74.2248 35.6323L73.6582 39.1503L70.7659 40.5682L71.1069 41.1349L72.9787 42.0426L76.4377 41.0503L75.4736 36.1426Z" fill="#FED607"/>
+<path d="M67.1354 29.2826L69.9712 26.9005L72.2969 27.1826L69.9148 21.057L67.0789 18.7903L66.7943 19.4134L66.2841 22.3621L63.2789 24.0646L66.5123 26.1057L67.1354 29.2826Z" fill="#FED607"/>
+<path d="M51.084 31.0404L53.3532 30.1891L56.5302 31.607L56.2455 27.807L58.5712 25.5378L55.3379 24.6865L53.6943 21.7378L53.2968 22.0198L51.8789 24.5173L51.084 31.0404Z" fill="#FED607"/>
+<path d="M53.3533 15.2704L56.1327 16.973L56.8712 20.1499L59.3097 18.1063L62.7686 18.5038L62.6558 17.2551L61.6917 15.1012L62.9943 12.0371L62.484 11.8115L59.3661 12.0961L57.2097 10.0525L56.6994 10.1653L56.1892 13.173L53.3533 14.7602V15.2704Z" fill="#FED607"/>
+<path d="M50.5172 7.38955L54.2044 8.06904L54.4864 7.50238L53.0685 4.38186L53.5223 2.73827L50.5172 1.77417L49.4403 2.17161V3.36135L50.5172 7.38955Z" fill="#FED607"/>
+<path d="M60.5276 123.316L64.866 125.019C64.866 125.019 66.3122 120.709 68.7788 119.46L68.5224 118.893L64.3532 116.852C64.3532 116.852 62.8224 117.363 63.5865 119.66C63.5865 119.66 60.184 121.106 60.525 123.319L60.5276 123.316Z" fill="#E96DF2"/>
+<path d="M107.746 90.8202C107.746 90.8202 108.597 92.6073 110.297 92.6073C110.297 92.6073 110.212 95.8407 111.317 96.0945L114.379 93.4843C114.379 93.4843 113.812 88.1253 111.543 87.4714L107.743 90.8176L107.746 90.8202Z" fill="#E96DF2"/>
+<path d="M52.6044 63.8588C54.1551 63.8588 55.4121 62.6017 55.4121 61.0511C55.4121 59.5005 54.1551 58.2434 52.6044 58.2434C51.0538 58.2434 49.7968 59.5005 49.7968 61.0511C49.7968 62.6017 51.0538 63.8588 52.6044 63.8588Z" fill="#E96DF2"/>
+<path d="M80.6793 63.8588C82.2299 63.8588 83.487 62.6017 83.487 61.0511C83.487 59.5005 82.2299 58.2434 80.6793 58.2434C79.1286 58.2434 77.8716 59.5005 77.8716 61.0511C77.8716 62.6017 79.1286 63.8588 80.6793 63.8588Z" fill="#E96DF2"/>
+<path d="M41.0919 68.5699C44.3381 75.1879 51.3201 80.7802 63.5073 80.7802C81.5432 80.7802 85.4612 69.7392 85.4612 61.5622C85.4612 52.0238 77.6304 43.6879 76.6099 41.134" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M49.3302 40.6982C49.3302 40.6982 39.5635 48.5444 38.8712 57.8059" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M60.274 56.5916C62.8428 56.5916 64.9253 54.0454 64.9253 50.9045C64.9253 47.7635 62.8428 45.2173 60.274 45.2173C57.7051 45.2173 55.6227 47.7635 55.6227 50.9045C55.6227 54.0454 57.7051 56.5916 60.274 56.5916Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M60.2742 47.4292C58.8434 47.4292 57.6306 48.3446 57.1768 49.6189L60.2742 50.7189L57.3896 52.301C57.9486 53.3189 59.0306 54.0087 60.2742 54.0087C62.0922 54.0087 63.5639 52.5369 63.5639 50.7189C63.5639 48.901 62.0922 47.4292 60.2742 47.4292Z" fill="#002140"/>
+<path d="M53.5535 45.6445C53.5535 45.6445 54.0073 47.5727 56.5022 47.1189" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M52.6174 48.4775C52.6174 48.4775 54.32 50.2929 55.679 49.2724" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M65.0584 51.6025C65.0354 51.3743 65.0251 51.141 65.0251 50.9076C65.0251 47.7666 67.1072 45.2205 69.6764 45.2205C72.2456 45.2205 74.3277 47.7666 74.3277 50.9076C74.3277 52.7897 73.5815 54.4564 72.4302 55.4923" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M69.5457 47.4292C68.1149 47.4292 66.9021 48.3446 66.4482 49.6189L69.5457 50.7189L66.6611 52.301C67.22 53.3189 68.3021 54.0087 69.5457 54.0087C71.3636 54.0087 72.8354 52.5369 72.8354 50.7189C72.8354 48.901 71.3636 47.4292 69.5457 47.4292Z" fill="#002140"/>
+<path d="M73.1201 47.0061C73.1201 47.0061 75.4175 47.1753 75.6714 45.6445" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M74.1406 49.0488C74.1406 49.0488 76.4381 49.218 76.6919 47.6873" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M64.9198 51.594C65.7813 53.0684 66.8095 54.6735 68.4634 55.094C69.2941 55.3042 70.1711 55.1786 71.0275 55.2555C71.8813 55.3325 72.8147 55.7094 73.1172 56.5119C73.4044 57.2709 72.9941 58.1581 72.3429 58.6427C71.6916 59.1273 70.8583 59.2863 70.0506 59.3607C69.1198 59.4453 68.1788 59.435 67.2506 59.3325C66.807 59.2812 66.3429 59.2017 65.9916 58.9273C65.6377 58.653 65.4429 58.1273 65.6711 57.7453C65.9736 57.2376 66.7557 57.3094 67.2557 57.6273" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M58.9404 75.0496C58.9404 75.0496 68.4686 80.1547 75.4456 74.3701" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M67.6741 70.4019C74.2254 70.4019 75.9254 64.8993 75.9254 64.8993C75.9254 64.8993 73.5433 61.2122 70.8767 61.2122C68.21 61.2122 67.2459 63.5942 67.2459 63.5942C67.2459 63.5942 65.8844 61.3814 63.2485 61.4686C60.61 61.5532 58.4844 65.8916 58.4844 65.8916C58.4844 65.8916 61.1228 70.4019 67.6715 70.4019H67.6741Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M59.8663 64.2387C59.8663 64.2387 67.874 68.4131 74.5664 63.8772" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M58.4867 65.8915C58.4867 65.8915 59.7636 74.0863 67.5328 74.0863C75.3021 74.0863 75.9277 64.8992 75.9277 64.8992" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M67.4763 66.1489V70.0053" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M63.3919 65.6384C63.3919 65.6384 62.8816 67.4538 63.0509 69.1538" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M71.333 65.5242C71.333 65.5242 72.2407 67.3396 72.1843 69.0396" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M39.697 68.942C39.7945 68.9138 39.8893 68.8805 39.9816 68.842C41.3688 68.2805 41.9047 67.1241 43.597 67.7343" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M53.6794 42.3811C52.9332 48.0683 42.8332 50.2375 46.1511 63.3401C44.3075 63.3401 42.8255 60.8734 41.7511 59.6657C38.7255 56.2657 34.5024 58.399 33.5588 62.2914C33.0742 64.2939 33.605 66.4298 35.2075 67.7965C35.6588 68.1837 36.2281 68.5144 36.846 68.7452" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M76.6071 41.1355C76.6071 41.1355 69.5431 6.66881 50.6302 1.5765C49.8661 1.37138 49.1636 2.05856 49.3584 2.82522C54.0738 21.4355 50.502 36.3278 49.361 40.2765C49.1969 40.8457 49.5482 41.4329 50.1277 41.5611C53.8866 42.3945 66.6584 44.7688 76.6071 41.1355Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M86.8996 104.847C93.315 102.608 97.3048 98.975 97.3048 93.4853C97.3048 82.7648 80.9176 83.3314 80.9176 74.8237" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M56.6252 107.669C58.797 107.787 61.0406 107.843 63.3406 107.843C66.7714 107.843 70.0816 107.723 73.2021 107.456" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M44.279 73.4629C44.279 80.268 29.3739 82.8783 29.3739 93.4834C29.3739 100.624 36.2662 104.658 46.4944 106.532" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M36.8201 60.8215C37.8739 62.5113 39.7431 63.6677 41.7252 63.8574" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M39.3611 63.2766C38.6252 63.8407 38.2149 64.8023 38.3149 65.7228" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M38.2357 70.7453C38.9664 70.7453 39.5587 70.1529 39.5587 69.4222C39.5587 68.6915 38.9664 68.0991 38.2357 68.0991C37.5049 68.0991 36.9126 68.6915 36.9126 69.4222C36.9126 70.1529 37.5049 70.7453 38.2357 70.7453Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M37.4921 70.5612C37.0434 70.4176 36.5409 70.3945 36.1024 70.5714C35.6639 70.7458 35.3024 71.1406 35.2332 71.6073C35.146 72.2048 35.5229 72.7637 35.6562 73.3535C35.7691 73.856 35.6998 74.3817 35.7819 74.8894C35.8357 75.2278 36.0511 75.6253 36.3947 75.5945C36.6306 75.574 36.7973 75.3483 36.8639 75.1201C36.9306 74.8919 36.9255 74.6509 36.9896 74.4227C37.0408 74.2432 37.2126 74.0432 37.3793 74.1253C37.5357 74.1996 37.5126 74.4278 37.5973 74.5791C37.6973 74.756 37.9742 74.7919 38.1152 74.6458C38.2306 74.5278 38.246 74.333 38.3716 74.2278C38.5639 74.0663 38.8716 74.2253 38.9921 74.4432C39.1127 74.6612 39.1255 74.9278 39.2306 75.1535C39.3767 75.474 39.787 75.7022 40.0896 75.5227C40.4614 75.3047 40.3639 74.7535 40.2998 74.3253C40.2075 73.7073 40.2998 73.0612 40.5562 72.4919C40.6306 72.3278 40.7178 72.1714 40.7614 71.9971C40.8665 71.5663 40.6639 71.0945 40.3127 70.8253C39.9614 70.556 39.487 70.4791 39.0511 70.556" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M33.3405 63.6379C27.1866 61.861 22.6687 56.002 22.6687 49.0481C22.6687 40.684 29.202 33.9045 37.2585 33.9045C41.5892 33.9045 45.6687 35.6994 48.6097 39.4174" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M42.3381 48.6397C41.1022 46.8013 41.0894 44.1936 42.492 42.0782C44.0792 39.6884 46.951 38.7218 49.3151 39.6269" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M42.7481 41.1349C42.7481 41.1349 40.5352 39.0093 36.707 38.9221" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M41.3868 44.4533C41.3868 44.4533 38.4945 44.9636 35.5586 43.7302" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M41.4716 46.792C41.4716 46.792 35.7716 47.8125 35.7716 52.2792" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M47.1152 84.1267C47.1152 84.1267 46.3203 88.1831 51.3408 88.1831C56.3613 88.1831 57.3255 85.1498 57.3255 85.1498C57.3255 85.1498 58.9511 88.1831 62.887 88.1831C66.8229 88.1831 67.846 85.2062 67.846 85.2062C67.846 85.2062 70.1383 88.1831 74.0537 88.1831C77.9691 88.1831 78.5357 84.5524 78.5357 84.5524" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M37.4405 81.5876C34.92 84.6953 35.0918 87.7569 38.92 87.7569C42.7482 87.7569 47.1148 84.1261 47.1148 84.1261" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M89.2432 83.5498C90.5714 86.0549 89.9227 88.1806 86.7329 88.1806C82.9047 88.1806 78.5381 84.5498 78.5381 84.5498" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M88.0919 105.919C88.0047 105.455 87.9329 104.973 87.879 104.473" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M38.8253 104.455C28.2843 108.006 19.0971 119.406 20.8099 146.319C29.8176 152.075 80.1817 158.711 103.664 146.29C101.469 119.478 91.0381 117.229 88.3484 107.188" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M67.8689 134.198C68.5766 133.936 69.333 133.785 70.1433 133.785C76.2689 133.785 77.9715 141.952 77.9715 141.952C77.9715 141.952 79.451 133.88 85.6022 132.895C91.7535 131.911 94.8176 139.908 94.8176 139.908C94.8176 139.908 95.2433 131.57 101.112 131.57" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M21.0691 131.477C27.0947 131.477 28.9665 139.823 28.9665 139.823C28.9665 139.823 29.9024 133.187 36.1127 133.187C42.323 133.187 43.5999 141.951 43.5999 141.951C43.5999 141.951 45.7947 133.93 52.0563 133.93C56.2999 133.93 58.7999 137.848 59.9717 140.374" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M33.3408 107.163C26.0716 107.163 25.3793 110.555 18.2819 110.555C9.69467 110.555 1.33826 102.253 1.33826 92.009C1.33826 81.7655 9.12288 73.4629 18.2819 73.4629C27.4408 73.4629 31.828 82.2885 34.8126 83.127" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M8.03839 95.9238C7.63069 94.6366 7.40503 93.2648 7.40503 91.8418C7.40503 84.4802 12.9999 78.511 19.5845 78.511" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M10.2946 75.7005C10.2946 69.2082 19.0715 62.5312 26.3612 62.5312C29.1176 62.5312 31.4407 63.3312 33.4253 64.4697" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M20.9686 85.7163C20.9686 85.7163 26.6686 89.5445 29.9866 89.7137" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M29.8149 97.3718C29.8149 97.3718 25.3047 97.5411 20.8816 99.4129" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M29.3741 93.4878C29.3741 93.4878 24.4561 94.1391 20.1177 92.7776" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M45.6409 93.8804C45.6409 93.8804 41.8973 116.17 64.6973 125.019" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M53.8923 92.6904C53.8923 92.6904 50.6589 110.552 69.2897 119.401" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M64.6968 125.021C64.6968 125.021 65.5455 120.336 69.2891 119.403" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M64.6968 125.019C65.9737 125.955 65.6045 128.309 70.1404 130.237" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M66.5483 128.075L59.838 140.629" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M73.187 115.65L70.7921 120.13" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M69.7894 130.395L63.3894 142.369" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M76.7458 117.375L74.097 122.331" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M84.1305 99.4584L84.2587 102.494C84.2792 102.982 84.5382 103.425 84.951 103.684L87.5254 105.299C88.5639 105.951 88.4049 107.51 87.2562 107.938L84.4074 108.999C83.951 109.169 83.6074 109.553 83.4895 110.025L82.7485 112.974C82.451 114.164 80.9177 114.494 80.1561 113.533L78.2664 111.151C77.9638 110.769 77.4921 110.561 77.0074 110.594L73.9741 110.802C72.751 110.887 71.9638 109.53 72.6408 108.51L74.3203 105.976C74.5895 105.571 74.6408 105.058 74.4613 104.607L73.3279 101.787C72.8715 100.648 73.9151 99.4815 75.0972 99.8097L78.0254 100.625C78.4946 100.756 78.9972 100.648 79.3715 100.335L81.7023 98.3866C82.6433 97.5995 84.0767 98.2328 84.128 99.4584H84.1305Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M51.8202 24.474L53.2099 21.9202C53.3715 21.6253 53.8022 21.6407 53.9381 21.9484L55.1202 24.6048C55.174 24.7279 55.2868 24.815 55.4176 24.8381L58.2766 25.3689C58.6074 25.4304 58.7253 25.8458 58.474 26.0714L56.3125 28.0176C56.2125 28.1073 56.1638 28.2407 56.1817 28.3714L56.5587 31.2535C56.6022 31.5868 56.2433 31.8279 55.9535 31.6586L53.4356 30.2048C53.3202 30.1381 53.1792 30.133 53.0586 30.1894L51.3304 31.0125" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M64.8304 30.6492L66.2611 33.18C66.3278 33.2954 66.4458 33.3723 66.5791 33.3851L69.474 33.6415C69.8099 33.6723 69.9663 34.0723 69.7381 34.321L67.774 36.4646C67.6842 36.562 67.6483 36.7005 67.6765 36.8313L68.3278 39.6646C68.4022 39.9928 68.0688 40.2646 67.7637 40.1261L65.1201 38.9184C64.9996 38.862 64.856 38.8697 64.7432 38.9389L62.2509 40.4338C61.9611 40.6082 61.5996 40.3748 61.6381 40.0389L61.9688 37.1518C61.9842 37.0184 61.9329 36.8877 61.8329 36.7979L59.6406 34.8877C59.3868 34.6672 59.4971 34.2492 59.8278 34.1825L62.6765 33.603C62.8073 33.5774 62.9176 33.4877 62.9688 33.3646L64.1073 30.6902C64.2381 30.38 64.6688 30.3569 64.8355 30.6492H64.8304Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M57.3124 10.0081L59.3201 12.1107C59.4125 12.2081 59.5458 12.2517 59.6791 12.2312L62.5483 11.7697C62.8817 11.7158 63.1304 12.0671 62.9714 12.3646L61.5919 14.9235C61.5278 15.0415 61.5278 15.1825 61.5894 15.303L62.915 17.8902C63.0688 18.1902 62.8124 18.5364 62.4817 18.4748L59.6227 17.9543C59.4919 17.9312 59.356 17.9723 59.2611 18.0671L57.2099 20.1287C56.9714 20.3671 56.5637 20.2312 56.5201 19.8953L56.1304 17.0133C56.1124 16.8799 56.0304 16.7646 55.9124 16.7056L53.3176 15.3928C53.0176 15.2415 53.0201 14.8107 53.3253 14.6646L55.9458 13.4056C56.0663 13.3466 56.1509 13.2338 56.1714 13.103L56.6176 10.2312C56.6689 9.89789 57.0791 9.76969 57.3124 10.0133V10.0081Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M53.7509 2.75977L52.9842 4.18028C52.9176 4.30592 52.915 4.45464 52.9791 4.58284L54.3894 7.33156C54.5535 7.64951 54.2791 8.01874 53.9278 7.95464L50.8868 7.40079C50.7458 7.37515 50.6022 7.4213 50.5022 7.5213" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M72.2969 27.1819L69.9148 26.8408C69.7815 26.8203 69.6481 26.8665 69.5558 26.9639L67.5558 29.0742C67.3251 29.3178 66.9122 29.1921 66.8584 28.8588L66.3994 25.987C66.3789 25.8537 66.2943 25.7408 66.1738 25.6844L63.5481 24.4357C63.243 24.2921 63.2379 23.8614 63.5379 23.7075L66.125 22.3844C66.243 22.3229 66.325 22.2075 66.343 22.0742L66.7199 19.1921C66.7635 18.8588 67.1712 18.7203 67.4097 18.9562L69.8071 21.3203" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M73.0458 42.066L71.0356 41.1095C70.7304 40.966 70.7253 40.5352 71.0253 40.3813L73.6125 39.0583C73.7304 38.9967 73.8125 38.8813 73.8304 38.748L74.2074 35.866C74.2509 35.5326 74.6587 35.3942 74.8971 35.6301L75.4048 36.3711" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M49.9662 38.9905C50.097 38.9649 50.2072 38.8751 50.2585 38.752L51.397 36.0777C51.5277 35.7674 51.9585 35.7443 52.1252 36.0367L53.5559 38.5674C53.6226 38.6828 53.7405 38.7597 53.8739 38.7726L56.7688 39.029C57.1047 39.0597 57.2611 39.4597 57.0329 39.7084L55.0688 41.852C54.979 41.9495 54.9431 42.0879 54.9713 42.2187" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M76.202 117.283C77.9721 117.283 79.4071 115.848 79.4071 114.078C79.4071 112.308 77.9721 110.873 76.202 110.873C74.4318 110.873 72.9968 112.308 72.9968 114.078C72.9968 115.848 74.4318 117.283 76.202 117.283Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M58.6538 150.409C60.2823 150.409 61.6025 149.089 61.6025 147.46C61.6025 145.832 60.2823 144.511 58.6538 144.511C57.0253 144.511 55.7051 145.832 55.7051 147.46C55.7051 149.089 57.0253 150.409 58.6538 150.409Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M64.4573 144.56C64.873 143.635 63.5418 142.136 61.4842 141.211C59.4266 140.286 57.4216 140.286 57.006 141.211C56.5904 142.136 57.9215 143.635 59.9791 144.56C62.0367 145.485 64.0417 145.485 64.4573 144.56Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M63.8457 178.618C88.7481 178.618 108.935 175.571 108.935 171.812C108.935 168.054 88.7481 165.007 63.8457 165.007C38.9433 165.007 18.756 168.054 18.756 171.812C18.756 175.571 38.9433 178.618 63.8457 178.618Z" fill="#002140"/>
+<path d="M97.2765 95.732C101.487 94.8012 106.223 92.3166 111.405 87.4141" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M91.2482 102.854C97.6046 103.764 105.605 102.008 114.553 93.5439" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M111.405 87.4172C111.405 87.4172 114.466 89.1198 114.553 93.5429" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M107.828 90.6501C108.046 91.7681 109.179 92.6271 110.315 92.5373C110.079 93.9527 110.128 95.4117 111.32 96.1784" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M64.3841 116.726C63.3995 117.477 63.0892 118.934 63.7046 119.918C62.22 120.406 60.8251 121.172 60.6354 122.634" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M88.3047 107.024L88.2201 106.642" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M117.81 85.0988C118.623 85.0347 119.517 85.0039 120.507 85.0039" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M114.11 94.0337C115.148 93.2414 116.561 93.2055 117.869 93.2055C120.612 93.2055 126.099 93.2055 126.099 93.2055C126.099 93.2055 127.333 93.2593 127.725 92.8593C128.12 92.4567 127.989 91.9003 127.63 91.5132C127.312 91.1747 126.864 90.9875 126.415 90.8721C125.63 90.6747 124.812 90.667 124.005 90.6619C122.838 90.6542 121.671 90.6465 120.505 90.6414" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M127.307 91.2342C127.479 91.183 127.631 91.1112 127.728 91.0112C128.123 90.6086 127.992 90.0522 127.633 89.665C127.315 89.3265 126.866 89.1394 126.418 89.024C125.633 88.8265 124.815 88.8189 124.007 88.8137C122.841 88.806 121.674 88.7983 120.507 88.7932" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M127.307 89.3622C127.479 89.3109 127.631 89.2391 127.728 89.1391C128.123 88.7365 127.992 88.1801 127.633 87.7929C127.315 87.4545 126.866 87.2673 126.418 87.1519C125.633 86.9545 124.815 86.9468 124.007 86.9417C122.841 86.934 121.674 86.9263 120.507 86.9211" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M127.307 87.4449C127.479 87.3936 127.631 87.3219 127.728 87.2219C128.123 86.8193 127.992 86.2629 127.633 85.8757C127.315 85.5372 126.866 85.3501 126.418 85.2347C125.633 85.0372 124.815 85.0295 124.007 85.0244C122.841 85.0167 121.674 85.009 120.507 85.0039" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M117.246 87.5277C117.41 87.3841 117.492 87.1713 117.551 86.9636C117.728 86.3379 117.756 85.6687 117.631 85.0302C117.948 84.5431 118.436 84.0559 118.772 83.5815C119.107 83.1072 119.266 82.4123 118.895 81.9661C118.692 81.7251 118.366 81.6072 118.054 81.6149C117.741 81.6225 117.436 81.7405 117.169 81.9072C116.372 82.4046 115.905 83.2764 115.351 84.0379C114.697 84.9379 112.997 85.6867 111.41 87.4174" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M70.1431 130.239C70.1431 130.239 72.3559 131.316 72.8661 128.877" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M69.3792 127.252C69.9715 127.677 70.692 128.093 71.574 128.467" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M71.5741 128.466C71.5741 128.466 73.7869 129.543 74.2972 127.104" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M70.3944 125.347C70.997 125.791 71.738 126.221 72.6534 126.608" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M72.6509 126.606C72.6509 126.606 74.8637 127.683 75.374 125.244" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M71.2433 123.238C71.9125 123.791 72.7792 124.338 73.9125 124.82" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M73.9149 124.822C73.9149 124.822 75.7995 125.743 76.3534 123.617C76.779 122.299 74.9406 120.758 74.9406 120.758" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M69.2921 119.403C69.9742 119.703 70.4331 119.59 71.1255 119.467" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M70.7921 120.13C71.546 121.489 74.2588 122.592 74.8664 122.538" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M47.1151 84.128C47.1151 84.128 49.5536 81.3767 49.7254 77.7178" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M57.3228 85.1476C57.3228 85.1476 58.3587 82.8887 58.1664 80.3887" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M67.9482 85.4045C67.9482 85.4045 67.1662 83.3327 67.079 80.9507" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M78.7793 84.7111C78.7793 84.7111 75.4178 81.7162 75.246 78.6521" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M28.9662 139.821V149.011" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M43.5972 141.525V151.648" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M77.9691 141.525V152.722" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M94.8148 139.313C94.8148 139.313 95.6328 144.759 95.6918 149.523" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M59.9329 150.287V153.01" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M137.359 70.0822L137.304 67.6011C137.304 67.6011 136.379 65.514 135.925 65.4492C135.471 65.3843 121.143 60.3748 121.143 60.3748C121.143 60.3748 119.819 60.7064 119.323 60.8161C118.827 60.9258 106.139 65.2846 106.139 65.2846C106.139 65.2846 104.925 65.8357 104.596 67.2146C104.267 68.5936 104.155 70.4139 104.155 70.4139C104.155 70.4139 103.823 70.7455 103.768 71.516C103.713 72.289 103.823 87.8414 103.823 87.8414C103.823 87.8414 103.713 88.779 104.87 88.8338C106.03 88.8887 137.633 88.8338 137.633 88.8338C137.633 88.8338 138.239 88.3376 138.239 87.7317C138.239 87.1258 138.459 70.7979 138.459 70.7979C138.459 70.7979 137.962 69.97 137.356 70.0797L137.359 70.0822Z" fill="#FFFAF0"/>
+<path d="M111.678 77.2763C111.678 77.2763 113.471 70.207 112.521 70.2219C111.571 70.2369 104.374 70.3591 104.374 70.3591C104.374 70.3591 103.768 70.5237 103.768 71.0199V71.5161L111.68 77.2738L111.678 77.2763Z" fill="#FFD7B0"/>
+<path d="M127.994 78.2887C128.298 78.9445 138.462 70.8005 138.462 70.8005C138.462 70.8005 138.185 69.9178 137.359 70.0823C136.534 70.2469 132.135 69.7382 130.851 70.2469C129.567 70.7556 127.689 77.6279 127.994 78.2862V78.2887Z" fill="#FFD7B0"/>
+<path d="M108.297 72.5882L108.638 74.9994L113.364 78.4655L128.37 78.3034C128.37 78.3034 132.429 74.9172 132.818 74.8598C133.18 67.6908 136.938 60.6739 136.938 60.6739L136.414 60.2575L133.759 60.7038L132.222 59.2501L129.799 60.8659L127.535 59.088L124.704 60.7038L123.006 58.8436L120.176 60.5417L119.044 58.3599L116.296 60.3797L113.952 58.4397C113.952 58.4397 108.294 61.0255 108.294 72.5857L108.297 72.5882Z" fill="#FBCCFF"/>
+<path d="M108.152 70.6015C108.364 70.6015 108.537 70.4293 108.537 70.2168C108.537 70.0044 108.364 69.8322 108.152 69.8322V70.6015ZM104.506 70.2168L104.504 70.6015H104.506V70.2168ZM108.152 69.8322H104.506V70.6015H108.152V69.8322ZM104.508 69.8322C103.818 69.8286 103.259 70.3888 103.259 71.0771H104.028C104.028 70.8129 104.242 70.6001 104.504 70.6015L104.508 69.8322ZM103.259 71.0771V88.0434H104.028V71.0771H103.259ZM103.259 88.0434C103.259 88.7321 103.818 89.2908 104.506 89.2908V88.5215C104.242 88.5215 104.028 88.3072 104.028 88.0434H103.259ZM104.506 89.2908H137.501V88.5215H104.506V89.2908ZM137.501 89.2908C138.19 89.2908 138.749 88.7321 138.749 88.0434H137.979C137.979 88.3072 137.765 88.5215 137.501 88.5215V89.2908ZM138.749 88.0434V71.0771H137.979V88.0434H138.749ZM138.749 71.0771C138.749 70.3884 138.19 69.8297 137.501 69.8297V70.599C137.765 70.599 137.979 70.8133 137.979 71.0771H138.749ZM137.501 69.8297H133.636V70.599H137.501V69.8297Z" fill="#002140"/>
+<path d="M107.782 88.6898C107.686 88.8793 107.761 89.1108 107.951 89.2068C108.14 89.3028 108.372 89.227 108.468 89.0375L107.782 88.6898ZM108.468 89.0375L113.652 78.8064L112.966 78.4587L107.782 88.6898L108.468 89.0375Z" fill="#002140"/>
+<path d="M128.438 78.3457C128.347 78.1538 128.118 78.072 127.926 78.163C127.734 78.2539 127.652 78.4833 127.743 78.6753L128.438 78.3457ZM127.743 78.6753L132.64 89.0061L133.335 88.6766L128.438 78.3457L127.743 78.6753Z" fill="#002140"/>
+<path d="M135.297 64.919C135.096 64.8488 134.877 64.9544 134.807 65.1549C134.736 65.3554 134.842 65.5748 135.043 65.645L135.297 64.919ZM135.469 65.3867L135.597 65.0241L135.596 65.0237L135.469 65.3867ZM137.304 67.9202L136.92 67.9236L136.92 67.9238L137.304 67.9202ZM135.043 65.645L135.342 65.7497L135.596 65.0237L135.297 64.919L135.043 65.645ZM135.341 65.7493C136.285 66.0834 136.911 66.9529 136.92 67.9236L137.689 67.9168C137.677 66.6134 136.837 65.463 135.597 65.0241L135.341 65.7493ZM136.92 67.9238L136.94 70.0309L137.709 70.0236L137.689 67.9165L136.92 67.9238Z" fill="#002140"/>
+<path d="M103.99 69.9723C103.99 70.1847 104.162 70.3569 104.374 70.3569C104.587 70.3569 104.759 70.1847 104.759 69.9723H103.99ZM106.224 65.2196L106.35 65.583L106.351 65.5829L106.224 65.2196ZM104.759 69.9723V67.783H103.99V69.9723H104.759ZM104.759 67.783C104.759 66.7988 105.392 65.9147 106.35 65.583L106.099 64.8561C104.838 65.2925 103.99 66.4631 103.99 67.783H104.759ZM106.351 65.5829L109.824 64.376L109.572 63.6494L106.098 64.8563L106.351 65.5829Z" fill="#002140"/>
+<path d="M103.99 71.3691C103.817 71.2464 103.577 71.2876 103.454 71.461C103.332 71.6345 103.373 71.8745 103.546 71.9971L103.99 71.3691ZM113.364 78.4681L113.142 78.7821C113.206 78.828 113.284 78.8527 113.364 78.8527V78.4681ZM128.148 78.4681V78.8527C128.229 78.8527 128.308 78.8272 128.373 78.7797L128.148 78.4681ZM103.546 71.9971L113.142 78.7821L113.586 78.154L103.99 71.3691L103.546 71.9971ZM113.364 78.8527H128.148V78.0835H113.364V78.8527ZM128.373 78.7797L138.59 71.3888L138.139 70.7655L127.922 78.1565L128.373 78.7797Z" fill="#002140"/>
+<path d="M108.045 75.0629C108.097 75.269 108.306 75.3943 108.512 75.3428C108.718 75.2913 108.843 75.0824 108.792 74.8764L108.045 75.0629ZM113.997 58.1206L114.301 57.8849C114.232 57.7964 114.128 57.7423 114.016 57.7365C113.905 57.7307 113.796 57.774 113.719 57.8549L113.997 58.1206ZM115.877 60.5444L115.573 60.7801C115.635 60.8607 115.727 60.9132 115.829 60.9259C115.93 60.9387 116.032 60.9108 116.113 60.8482L115.877 60.5444ZM118.847 58.2403L119.179 58.0476C119.124 57.9515 119.029 57.8841 118.92 57.8628C118.811 57.8415 118.699 57.8684 118.611 57.9364L118.847 58.2403ZM120.181 60.5444L119.848 60.7371C119.902 60.8302 119.992 60.8964 120.097 60.9198C120.202 60.9431 120.312 60.9215 120.4 60.8601L120.181 60.5444ZM122.968 58.6044L123.25 58.3426C123.12 58.2022 122.906 58.1792 122.749 58.2887L122.968 58.6044ZM124.891 60.674L124.609 60.9358C124.741 61.0774 124.957 61.0994 125.114 60.9872L124.891 60.674ZM127.577 58.759L127.851 58.4889C127.718 58.3544 127.507 58.3361 127.353 58.4458L127.577 58.759ZM129.651 60.8635L129.377 61.1335C129.504 61.2619 129.703 61.2852 129.855 61.1895L129.651 60.8635ZM132.489 59.0856L132.765 58.8183C132.639 58.6877 132.439 58.6632 132.285 58.7597L132.489 59.0856ZM134.307 60.9658L134.03 61.2331C134.138 61.3443 134.301 61.3803 134.446 61.3244L134.307 60.9658ZM137.277 60.0556L137.612 60.244C137.684 60.115 137.676 59.9557 137.591 59.8346C137.506 59.7134 137.359 59.6519 137.213 59.6763L137.277 60.0556ZM108.419 74.9696C108.792 74.8764 108.792 74.8765 108.792 74.8766C108.792 74.8766 108.792 74.8767 108.792 74.8767C108.792 74.8767 108.792 74.8766 108.792 74.8763C108.792 74.8758 108.791 74.8747 108.791 74.8731C108.79 74.8699 108.789 74.8647 108.787 74.8574C108.784 74.8428 108.779 74.82 108.772 74.7893C108.759 74.7278 108.74 74.6348 108.719 74.5125C108.676 74.2678 108.623 73.9061 108.582 73.4453C108.501 72.5235 108.471 71.2075 108.679 69.6413C109.094 66.5126 110.459 62.3797 114.275 58.3863L113.719 57.8549C109.774 61.9831 108.35 66.2747 107.916 69.5401C107.7 71.171 107.73 72.5444 107.816 73.5128C107.858 73.9972 107.915 74.3807 107.961 74.645C107.984 74.7772 108.005 74.8796 108.02 74.95C108.027 74.9852 108.033 75.0124 108.038 75.0313C108.04 75.0408 108.042 75.0482 108.043 75.0535C108.044 75.0561 108.044 75.0582 108.045 75.0598C108.045 75.0606 108.045 75.0612 108.045 75.0618C108.045 75.062 108.045 75.0623 108.045 75.0624C108.045 75.0627 108.045 75.0629 108.419 74.9696ZM113.693 58.3563L115.573 60.7801L116.181 60.3086L114.301 57.8849L113.693 58.3563ZM116.113 60.8482L119.082 58.5442L118.611 57.9364L115.641 60.2405L116.113 60.8482ZM118.514 58.433L119.848 60.7371L120.514 60.3516L119.179 58.0476L118.514 58.433ZM120.4 60.8601L123.188 58.9201L122.749 58.2887L119.961 60.2287L120.4 60.8601ZM122.687 58.8661L124.609 60.9358L125.173 60.4123L123.25 58.3426L122.687 58.8661ZM125.114 60.9872L127.8 59.0721L127.353 58.4458L124.668 60.3609L125.114 60.9872ZM127.303 59.029L129.377 61.1335L129.925 60.5935L127.851 58.4889L127.303 59.029ZM129.855 61.1895L132.693 59.4115L132.285 58.7597L129.447 60.5376L129.855 61.1895ZM132.212 59.353L134.03 61.2331L134.583 60.6984L132.765 58.8183L132.212 59.353ZM134.307 60.9658C134.446 61.3244 134.446 61.3244 134.446 61.3244C134.446 61.3244 134.446 61.3244 134.446 61.3244C134.446 61.3244 134.446 61.3244 134.446 61.3244C134.446 61.3243 134.446 61.3242 134.447 61.324C134.447 61.3237 134.449 61.3232 134.45 61.3226C134.454 61.3213 134.459 61.3193 134.466 61.3167C134.479 61.3115 134.5 61.3038 134.526 61.2938C134.578 61.2739 134.655 61.2452 134.75 61.2101C134.941 61.1399 135.207 61.0444 135.506 60.9433C136.112 60.7388 136.828 60.5204 137.34 60.435L137.213 59.6763C136.635 59.7728 135.867 60.0095 135.26 60.2146C134.953 60.3183 134.68 60.4162 134.485 60.4882C134.387 60.5242 134.308 60.5538 134.254 60.5744C134.226 60.5847 134.205 60.5928 134.191 60.5984C134.183 60.6012 134.178 60.6033 134.174 60.6048C134.172 60.6055 134.171 60.6061 134.17 60.6065C134.169 60.6067 134.169 60.6068 134.168 60.6069C134.168 60.607 134.168 60.607 134.168 60.607C134.168 60.6071 134.168 60.6071 134.168 60.6071C134.168 60.6071 134.168 60.6071 134.307 60.9658ZM136.941 59.8672C134.856 63.5784 133.731 67.3186 133.127 70.1279C132.825 71.5335 132.652 72.7084 132.555 73.5335C132.507 73.9461 132.477 74.2714 132.46 74.4945C132.451 74.6061 132.445 74.6921 132.441 74.7508C132.44 74.7801 132.438 74.8026 132.438 74.818C132.437 74.8257 132.437 74.8316 132.437 74.8358C132.437 74.8378 132.437 74.8394 132.436 74.8406C132.436 74.8412 132.436 74.8417 132.436 74.842C132.436 74.8422 132.436 74.8424 132.436 74.8425C132.436 74.8426 132.436 74.8427 132.821 74.8599C133.205 74.8771 133.205 74.8772 133.205 74.8772C133.205 74.8772 133.205 74.8772 133.205 74.8772C133.205 74.8771 133.205 74.8768 133.205 74.8765C133.205 74.8759 133.205 74.8748 133.205 74.8732C133.205 74.8701 133.205 74.8652 133.206 74.8586C133.206 74.8453 133.208 74.8249 133.209 74.7977C133.213 74.7434 133.218 74.6618 133.226 74.5549C133.243 74.3409 133.272 74.0254 133.319 73.6233C133.414 72.8188 133.582 71.6682 133.879 70.2897C134.472 67.5309 135.575 63.869 137.612 60.244L136.941 59.8672Z" fill="#002140"/>
+<path d="M114.361 65.4541H128.303" stroke="#002140" stroke-width="0.769231" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M113.633 71.7288H127.577" stroke="#002140" stroke-width="0.769231" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M113.633 74.8059H127.577" stroke="#002140" stroke-width="0.769231" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M113.693 68.6519H127.637" stroke="#002140" stroke-width="0.769231" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M100.429 51.9095L98.7547 48.7644L98.0116 49.0326L96.615 51.999L92.4281 52.8089L92.8011 53.6162L95.1259 56.0435L94.4753 59.7304L95.311 59.9092L98.6622 58.6495L102.011 59.9986L102.476 59.5489L102.198 55.7753L104.616 53.0771L104.246 52.6274L100.429 51.9095Z" fill="#5BE3AA"/>
+<path d="M98.9901 48.784L100.42 51.5851C100.507 51.7558 100.678 51.875 100.875 51.902L104.074 52.3517C104.568 52.4222 104.764 53.0073 104.408 53.3432L102.092 55.524C101.949 55.6567 101.884 55.849 101.918 56.0387L102.465 59.1161C102.549 59.5902 102.033 59.9532 101.593 59.7283L98.7293 58.2736C98.5554 58.1842 98.3451 58.1842 98.1684 58.2736L95.3052 59.7283C94.8649 59.9532 94.3489 59.5902 94.433 59.1161L94.9799 56.0387C95.0135 55.849 94.949 55.6567 94.806 55.524L92.4896 53.3432C92.1335 53.0073 92.3298 52.4222 92.8233 52.3517L96.0231 51.902C96.2194 51.875 96.3877 51.7558 96.4774 51.5851L97.9076 48.784C98.1292 48.3533 98.7658 48.3533 98.9873 48.784H98.9901Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M129.82 40.5899L127.933 36.9617L127.092 37.2711L125.52 40.6931L120.8 41.6275L121.218 42.5587L123.842 45.3589L123.105 49.6121L124.05 49.8184L127.828 48.3652L131.603 49.9215L132.128 49.4028L131.812 45.0495L134.54 41.9369L134.12 41.4181L129.82 40.5899Z" fill="#FED607"/>
+<path d="M128.303 37.2953L129.915 40.5266C130.013 40.7235 130.206 40.861 130.427 40.8923L134.034 41.4111C134.591 41.4923 134.812 42.1673 134.411 42.5549L131.799 45.0706C131.638 45.2237 131.565 45.4456 131.603 45.6643L132.22 49.2145C132.315 49.7614 131.733 50.1801 131.236 49.9207L128.009 48.2426C127.813 48.1394 127.576 48.1394 127.376 48.2426L124.149 49.9207C123.652 50.1801 123.07 49.7614 123.165 49.2145L123.782 45.6643C123.82 45.4456 123.747 45.2237 123.586 45.0706L120.974 42.5549C120.573 42.1673 120.794 41.4923 121.351 41.4111L124.958 40.8923C125.179 40.861 125.369 40.7235 125.47 40.5266L127.082 37.2953C127.332 36.7984 128.05 36.7984 128.299 37.2953H128.303Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M135.98 97.7187L134.729 95.3828L134.173 95.582L133.129 97.7851L130 98.3867L130.279 98.9883L132.017 100.789L131.53 103.527L132.155 103.66L134.66 102.727L137.162 103.726L137.51 103.393L137.303 100.59L139.109 98.5859L138.833 98.2539L135.98 97.7187Z" fill="#FBCCFF"/>
+<path d="M135.046 95.665L136.115 97.7454C136.18 97.8721 136.308 97.9606 136.454 97.9808L138.846 98.3148C139.215 98.3671 139.362 98.8017 139.095 99.0511L137.364 100.671C137.257 100.769 137.209 100.912 137.234 101.053L137.643 103.339C137.706 103.691 137.32 103.96 136.991 103.793L134.851 102.713C134.721 102.647 134.564 102.647 134.432 102.713L132.292 103.793C131.963 103.96 131.577 103.691 131.64 103.339L132.048 101.053C132.074 100.912 132.025 100.769 131.919 100.671L130.187 99.0511C129.921 98.8017 130.068 98.3671 130.437 98.3148L132.828 97.9808C132.975 97.9606 133.101 97.8721 133.168 97.7454L134.237 95.665C134.402 95.3451 134.878 95.3451 135.044 95.665H135.046Z" stroke="#002140" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/contributingGuides/FORMS.md b/contributingGuides/FORMS.md
index 469281d3e86b..be769faf568e 100644
--- a/contributingGuides/FORMS.md
+++ b/contributingGuides/FORMS.md
@@ -68,7 +68,7 @@ Browsers use the name prop to autofill information into the input. Here's a [ref
 
 ```jsx
 <InputWrapper
-    InputComponent={TextInput} 
+    InputComponent={TextInput}
     name="fname"
 />
 ```
@@ -118,7 +118,7 @@ Once a user has “touched” an input, i.e. blurred the input, we will also sta
 
 All form fields will additionally be validated when the form is submitted. Although we are validating on blur this additional step is necessary to cover edge cases where forms are auto-filled or when a form is submitted by pressing enter (i.e. there will be only a ‘submit’ event and no ‘blur’ event to hook into).
 
-The Form component takes care of validation internally and the only requirement is that we pass a validate callback prop. The validate callback takes in the input values as argument and should return an object with shape `{[inputID]: errorMessage}`. 
+The Form component takes care of validation internally and the only requirement is that we pass a validate callback prop. The validate callback takes in the input values as argument and should return an object with shape `{[inputID]: errorMessage}`.
 
 Here's an example for a form that has two inputs, `routingNumber` and `accountNumber`:
 
@@ -332,10 +332,10 @@ An example of this can be seen in the [ACHContractStep](https://github.com/Expen
 ### Safe Area Padding
 
 Any `FormProvider.tsx` that has a button at the bottom. If the `<FormProvider>` is inside a `<ScreenWrapper>`, the bottom safe area inset is handled automatically (`includeSafeAreaPaddingBottom` needs to be set to `true`, but its the default).
-If you have custom requirements and can't use `<ScreenWrapper includeSafeAreaPaddingBottom={true}>`, you can use the `useStyledSafeAreaInsets()` hook:
+If you have custom requirements and can't use `<ScreenWrapper includeSafeAreaPaddingBottom={true}>`, you can use the `useSafeAreaPaddings()` hook:
 
 ```jsx
-const { paddingTop, paddingBottom, safeAreaPaddingBottomStyle } = useStyledSafeAreaInsets();
+const { paddingTop, paddingBottom, safeAreaPaddingBottomStyle } = useSafeAreaPaddings();
 
 <View styles={[safeAreaPaddingBottomStyle, styles.pb5]}>
     <FormProvider>
diff --git a/docs/articles/expensify-classic/bank-accounts-and-payments/Third-Party-Payments.md b/docs/articles/expensify-classic/bank-accounts-and-payments/Third-Party-Payments.md
deleted file mode 100644
index 7d318fd35143..000000000000
--- a/docs/articles/expensify-classic/bank-accounts-and-payments/Third-Party-Payments.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Third-Party Payments
-description: Reimburse reports and pay bills using PayPal or Venmo.
----
-Expensify integrates with PayPal and Venmo, which can be used to reimburse employees or pay bills. Some of the key benefits of using a third-party payment provider are:
-- Faster Reimbursements: Expedite the reimbursement process and reduce the time it takes for employees to receive their funds.
-- Secure Transactions: Benefit from the security features and protocols provided by trusted payment providers.
-- Centralized Expense Management: Consolidate all your expenses and payments within Expensify for a more efficient financial workflow.
-
-# Connect a third-party payment option
-
-To connect a third-party payment platform to Expensify:
-1. Log into your Expensify web account
-2. Head to **Settings > Account > Payments > Alternative Payment Accounts**
-3. Choose PayPal or Venmo
-     - **PayPal**: Enter your username in the `paypal.me/` field
-     - **Venmo**: Receive invoices via Venmo by adding your mobile phone number as a Secondary Login
-
-{% include faq-begin.md %}
-
-## Can I use multiple third-party payment providers with Expensify?
-
-Yes, you can link both your Venmo and PayPal accounts to Expensify if you'd like. 
-
-## Is there a limit on the amount I can reimburse using third party payments?
-
-The payment limit is dependent on the settings configured within your Expensify account as well as the limits imposed by the third-party payment provider.
-
-{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Enable-Global-Reimbursements.md b/docs/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Enable-Global-Reimbursements.md
index 02ee7b7ce04a..72ba03e600ee 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Enable-Global-Reimbursements.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Enable-Global-Reimbursements.md
@@ -1,81 +1,192 @@
 ---
 title: Enable Global Reimbursements
 description: Send international payments
+keywords: Expensify Classic, foreign bank validation, global reimbursement, Canada, Europe, Singapore, Australia, United Kingdom, international reimbursements
 ---
-<div id="expensify-classic" markdown="1">
 
-Enabling global reimbursements allows you to send direct reimbursements to countries worldwide if your company’s bank account is in the US, UK, Canada, Europe, or Australia. 
+If your company’s business bank account is in the US, Canada, the UK, Europe, Australia, or Singapore, you can send direct reimbursements to nearly any country worldwide! 
 
-# For USD accounts
+The process to enable international reimbursements depends on the currency of your reimbursement bank account, so be sure to review the corresponding instructions below. 
 
-{% include info.html %}
-Before you can complete this process, you must first connect a **verified** U.S. bank account, and your employees receiving payments from this account must also connect their **deposit-only** U.S. bank account.
-{% include end-info.html %}
+---
+
+# If the Reimbursement Account is in the U.S. (USD)
+
+Before you begin, ensure you have a verified U.S. business bank account connected. Once global reimbursement is enabled on your account, employees receiving payments will connect their **non-USD bank account**.
 
-## Step 1: Request global reimbursements
+## Step 1: Connect a U.S Business Bank Account
 
-Once your verified U.S. bank account has been added and verified, you can request that global reimbursements be enabled on your account.
+If you haven't already, follow the instructions to [Connect a US Business Bank Account](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-US-Business-Bank-Account). 
 
-## Step 2: Re-verify the bank account
+## Step 2: Verify the Bank Account for Global Reimbursements
 
 1. Hover over **Settings**, then click **Workspaces**. 
-2. Select the workspace.
 3. Click the **Reports** tab on the left. 
 4. Ensure that the workspace currency is set to **USD**. 
 5. Click the **Reimbursements** tab on the left.
-6. Ensure that the reimbursement method is set to **Direct** and that the right bank account is selected. 
+6. Ensure that the reimbursement method is set to **Direct** and that the correct bank account is selected. 
 7. Click the **Payments** tab on the left.
 8. Click **Enable Global Reimbursement** next to the bank account.  
-9. Complete the International Reimbursement DocuSign form. 
+9. Complete the Global Reimbursement DocuSign form.
+10. Once the form is complete, it is automatically sent to our Compliance Team for review. 
 
-Once the form is complete, it is automatically sent to our Compliance Team for review. Our Support Team will contact you with more details if additional information is required, which may include: 
+**Our Support Team will contact you with more details if additional information is required, which may include:** 
 - An authorization letter
 - Proof of address and ID for the reimburser and/or company directors
 - Independently certified documentation, such as a shareholder agreement from a lawyer, notary, or public accountant if an individual owns more than 25% of the company
 
-# For AUD, CAD, GBP, and EUR accounts
+## Step 3: Start Reimbursing Internationally
+
+After the bank account is verified for international payments, set the correct bank account as the reimbursement account:
+
+1. Under **Settings** > **Workspaces** > **Group** > **[Workspace Name]** > **Reimbursements**
+2. Select the reimbursement account as the default account.
+3. Ask your employees to add their deposit-only bank account.
+   - They can do this by logging into their Expensify accounts, heading to **Settings** > **Account** > **Payments**, and clicking **Add Deposit-Only Bank Account**. 
+
+---
+
+# If the Bank Account is Outside of the U.S (AUD, CAD, GBP, EUR, and SGD Currencies)
+
+**Overview of the International Bank Account Setup:**
+1. Connect the reimbursement account to Expensify.
+2. Complete DocuSign Form.
+3. Expensify's Compliance Team Reviews the Application: Depending on the country, the team approves the request or requests additional documentation.
+4. Expensify sends test deposits to the provided bank account: Expensify asks the customer to confirm test deposit amounts.
+5. Admin Actions Required:
+     - Set the reimbursement account under **Settings > Workspaces > [Workspace Name] > Reimbursements**.
+     - Ensure employees add their deposit-only bank accounts under **Settings > Account > Payments > Add Deposit-Only Bank Account**.
 
-## Step 1: Add the bank account
+## Step 1: Connect the Bank Account
 
 1. Hover over **Settings**, then click **Workspaces**. 
-2. Select the workspace.
-3. Click the **Reports** tab on the left. 
-4. Ensure that the selected workspace currency matches your reimbursement bank account currency.
-5. Click the **Reimbursements** tab on the left.
-6. Set the reimbursement method to **Direct**. 
-7. Click **Add Business Bank Account**.
-8. If necessary, click **Switch Country** to select the correct country if not automatically selected.
-9. Enter the bank account details, then click **Save & Continue**.
-10. Complete the International Reimbursement DocuSign form. 
+2. Click the **Reports** tab on the left. 
+3. Ensure that the selected workspace currency matches your reimbursement bank account currency.
+4. Click the **Reimbursements** tab on the left.
+5. Set the reimbursement method to **Direct**. 
+6. Click **Add Business Bank Account**.
+7. Click **Switch Country** and adjust the **Currency** so the information is correct.
+8. Click **Save & Continue**.
+9. Enter the details of your bank account and click **Save & Continue**.
 
-Once the form is complete, it is automatically sent to our Compliance Team for review. Our Support Team will contact you with more details if additional information is required, which may include: 
-- An authorization letter
-- Proof of address and ID for the reimburser and/or company directors
-- Independently certified documentation, such as a shareholder agreement from a lawyer, notary, or public accountant if an individual owns more than 25% of the company
+## Step 2: Verify the Bank Account for Global Reimbursements
+
+1. Complete the Global Reimbursement DocuSign form.
+2. Once the form is complete, it is automatically sent to our Compliance Team for review.
+3. See the **Requirements for Global Reimbursement** section below to determine which additional information is required to set up international reimbursements for your entity.
+4. If prompted, upload one of the following:
+   - **Voided check** with business name and account details
+   - **Bank statement** showing the business name and account information
+   - **Bank letter** confirming the account details
+
+**Our Support Team will contact you via Concierge with more details if additional information is required.** 
+
+
+## Step 3: Start Reimbursing Internationally
 
-{% include faq-begin.md %}
+After the bank account is verified for international payments, set the correct bank account as the reimbursement account:
 
-**Can multiple people send reimbursements internationally?**
+1. Under **Settings** > **Workspaces** > **Group** > **[Workspace Name]** > **Reimbursements**
+2. Select the reimbursement account as the default account.
+3. Ask your employees to add their deposit-only bank account.
+   - They can do this by logging into their Expensify accounts, heading to **Settings** > **Account** > **Payments**, and clicking **Add Deposit-Only Bank Account**. 
+
+---
+
+# Requirements for International Reimbursement
+
+## U.S.
+**Requirements:**
+- ✅ Partner Application Form
+- ✅ Address Verification Document (e.g., utility bill, lease agreement)
+- ✅ Bank Statement for Direct Debit Setup
+
+**Direct Debit Timeline:**
+⏳ Takes 1 day to set up once onboarding is complete and the bank account is verified.
+
+## Canada
+**Requirements:**
+- ✅ Partner Application Form
+- ✅ Address Verification Document
+- ✅ Bank Statement for Direct Debit Setup
+- ✅ Proof of Beneficial Ownership
+
+**Direct Debit Timeline:**
+⏳ Takes 1 day to set up once onboarding is complete and the bank account is verified.
+
+## United Kingdom
+**Requirements:**
+- ✅ Partner Application Form
+- ✅ Address Verification Document
+- ✅ Bank Statement for Direct Debit Setup
+- ✅ Proof of Beneficial Ownership
+- ✅ Copy of ID and Proof of Address for Signatories
+
+**Direct Debit Timeline:**
+⏳ Can only be set up after onboarding is complete.
+
+## European Union
+**Requirements:**
+- ✅ Partner Application Form
+- ✅ Address Verification Document
+- ✅ Bank Statement for Direct Debit Setup
+- ✅ Proof of Beneficial Ownership
+- ✅ Certified Copies of ID & Address for UBOs (Only if the company is in Jersey)
+
+**Special Notes:**
+🇮🇹 Italy: Requires "Codice Fiscale" (Tax Identification Number).
+🇪🇸 Spain: Driver's license not accepted as ID.
+
+**Direct Debit Timeline:**
+⏳ Can only be set up after onboarding is complete.
+
+## Australia
+**Requirements:**
+- ✅ Partner Application Form
+- ✅ Address Verification Document
+- ✅ Bank Statement for Direct Debit Setup
+- ✅ Proof of Beneficial Ownership
+- ✅ Copy of ID & Proof of Address for all Signatories
+
+**Special Notes:**
+Expensify's Compliance Team must send a PDS FSG to company directors before onboarding.
+
+**Direct Debit Timeline:**
+⏳ Takes 1 day to set up once onboarding is complete and the bank account is verified.
+
+## Singapore
+**Requirements:**
+- ✅ Partner Application Form
+- ✅ Address Verification Document
+- ✅ Proof of Beneficial Ownership
+- ✅ Director/Board Resolution
+- ✅ Memorandum & Articles of Association
+- ✅ Certified Copies of ID & Address for UBOs
+
+**Direct Debit Timeline:**
+⏳ Takes 3 weeks to set up. Clients are encouraged to pre-fund the account while waiting.
+
+---
 
-Once your company is authorized to send global payments, the individual who verified the bank account can share it with additional admins on the workspace. This will enable them to be able to send global reimbursements.
+# FAQ
 
-**How long does it take to verify an account for global payments?**
+## Can multiple people send reimbursements internationally?
 
-The verification process can take anywhere from a few business days to several weeks  depending on the information provided in the DocuSign form, if additional information is required for compliance.
+Yes, once your company is authorized to send international payments, the individual who verified the bank account can share it with additional admins on the workspace, enabling them to send global reimbursements.
 
-**My employee doesn’t have the option to add their non-USD bank account as a deposit account. What should they do?**
+## How long does it take to verify an account for global payments?
 
-Have the employee double-check that their [default workspace](https://help.expensify.com/articles/expensify-classic/workspaces/Navigate-multiple-workspaces) is set as the workspace that’s connected to the bank you’re using to send global payments. 
+The verification process can take anywhere from a few business days to several weeks, depending on the information provided in the DocuSign form and if additional information is required for compliance.
 
-**Who is the “Authorized User” and the “User” on the International Reimbursement DocuSign form?**
+## Why can't my employee add a non-USD bank account?
 
-- **Authorized User**: The person who will process global reimbursements. The Authorized User should be the same person who manages the bank account connection in Expensify.
-- **User**: You can leave this section blank because the “User” is Expensify.
+Make sure your employee's default workspace is set to the one linked to the bank you're using for global payments. They can confirm their default workspace by following [these steps](https://help.expensify.com/articles/expensify-classic/workspaces/Navigate-multiple-workspaces).
 
-**Does Global Reimbursement support Sepa in the EU?**
+## Who are the “Authorized User” and the “User” on the International Reimbursement DocuSign form?
 
-Global Reimbursement uses Sepa B2B to facilitate payments from EU-based accounts. Sepa Core is not supported.
+- **Authorized User**: The person who will process international reimbursements. The Authorized User should be the same person who manages the bank account connection in Expensify.
+- **User**: Expensify (leave blank).
 
-{% include faq-end.md %}
+## Does Global Reimbursement in Expensify support SEPA (Single Euro Payments Area) in the EU?
 
-</div>
+Global Reimbursement uses SEPA B2B to facilitate payments from EU-based accounts. SEPA Core is not supported.
diff --git a/docs/articles/expensify-classic/bank-accounts-and-payments/payments/Get-reimbursed-faster-as-a-non-US-employee.md b/docs/articles/expensify-classic/bank-accounts-and-payments/payments/Get-reimbursed-faster-as-a-non-US-employee.md
deleted file mode 100644
index 30dea99bbfde..000000000000
--- a/docs/articles/expensify-classic/bank-accounts-and-payments/payments/Get-reimbursed-faster-as-a-non-US-employee.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: Get Reimbursed Faster as a Non-US Employee
-description: How to use Wise to get paid faster
----
-
-If you are an overseas employee who works for a US-based company, you can use Wise to be reimbursed for expenses just as quickly as your US-based colleagues. Wise (formerly TransferWise) is an FCA-regulated global money transfer service. 
-
-Here’s how it works:
-
-1. When you sign up for a Wise account, you are provided with a USD checking account number and a routing number to use as your Expensify bank account. 
-2. Once you receive a reimbursement, it will be deposited directly into your Wise account. 
-3. You can then convert your funds into 40+ different currencies and withdraw them to your local bank account. If you live in the UK or EU, you can also get a debit card to spend money directly from your Wise account.
-
-## Set up reimbursements through Wise
-
-1. Check with your company to see if you can submit your expenses in USD.
-2. Sign up for a Wise Borderless Account and get verified (verification can take up to 3 days).
-3. In Expensify, [add a deposit-only bank account](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-Personal-US-Bank-Account) with your Wise USD account and ACH routing numbers (NOT the wire transfer routing number). 
-
-{% include info.html %}
-Do not include spaces in the Wise account number, which should be 16 digits.
-{% include end-info.html %}
-
-If your expenses are not in USD, Expensify will automatically convert them to USD when they are added to your expense report. Once you submit your expenses to your company’s USD workspace and they are approved, you will receive the reimbursement for the approved report total in USD in your Wise account. 
diff --git a/docs/articles/expensify-classic/bank-accounts-and-payments/payments/Receive-Payments.md b/docs/articles/expensify-classic/bank-accounts-and-payments/payments/Receive-Payments.md
index 00fb236e1763..c036c316896d 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-payments/payments/Receive-Payments.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-payments/payments/Receive-Payments.md
@@ -1,36 +1,82 @@
 ---
-title: Receive payments
-description: Receive reimbursements from an employer
+title: Receive Payments
+description: Learn how to receive reimbursements through Expensify, including ACH, Wise, PayPal, and Venmo options.
+keywords: [reimbursement, ACH, bank account, Wise, PayPal, Venmo, Rapid Reimbursement]
 ---
-<div id="expensify-classic" markdown="1">
 
-To get paid after submitting a report for reimbursement, you must first connect a personal U.S. bank account or a personal Australian bank account. Then once your employer approves your report or invoice, the reimbursement will be paid directly to your bank account.
-Funds for U.S. and global payments are generally deposited within a maximum of four to five business days: 2 days for the funds to be debited from the business bank account, and 2-3 business days for the ACH or wire to deposit into the employee account.
+To receive a reimbursement after submitting an expense report, you must first [connect a personal bank account](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-Personal-Bank-Account) to Expensify. Once your employer approves your report or invoice, the reimbursement is deposited directly into your bank account.
 
-However, banks only process ACH transactions before the daily cutoff (generally 3 p.m. PST) and only on business weekdays that are not bank holidays. This may affect when the payment is disbursed. If the payment qualifies for Rapid Reimbursement, you may receive the payment sooner.
+**Processing Times:**  
+- U.S. and global payments generally take **4-5 business days**:  
+  - **2 days** for the business account to process the debit  
+  - **2-3 business days** for ACH or wire transfer to your account  
+- Payments initiated **after 3 p.m. PST** or on **weekends/bank holidays** may be delayed.  
+- If your payment qualifies for **Rapid Reimbursement**, you may receive it sooner.
 
-{% include info.html %}
-Companies also have the option to submit payments outside of Expensify via check, cash, or a third-party payment processor. Check with your Workspace Admin to know how you will be reimbursed.
-{% include end-info.html %}
- 
-# Rapid Reimbursement (U.S. only)
+Your company or client also has the option to pay you via **check, a third-party payment processor, or outside of Expensify**. Check with your **Workspace Admin** or payor to confirm the payment method.
 
-With Expensify’s ACH reimbursement, payments may be eligible for reimbursement by the next business day with Rapid Reimbursement if they meet the following qualifications:
-- **Deposit-only accounts**: Payment must not exceed $100 
-- **Verified business bank accounts**: The account does not disburse more than $10,000 within a 24-hour time period.
+---
+
+# Rapid Reimbursement (U.S. Only)
+
+Expensify’s **Rapid Reimbursement** allows eligible ACH payments to process **within one business day** if they meet the following conditions:
+
+- **Deposit-only accounts:** Payment must not exceed **$100**.  
+- **Verified business bank accounts:** Total disbursements must not exceed **$10,000** within 24 hours.
+
+If payments exceed these limits, they follow the standard **4-5 business day ACH timeframe**.
+
+---
+
+# Global Reimbursements via Wise
+
+For employees outside the U.S., Expensify partners with **Wise (formerly TransferWise)** to enable **faster global reimbursements**.
 
-If the payment amount exceeds the limit, funds will be deposited within the typical ACH time frame of four to five business days. 
+## How It Works
+1. Sign up for a **Wise account** to receive a USD checking account number and ACH routing number.
+2. Add these details as a **deposit-only bank account** in Expensify.
+3. When your reimbursement is approved, it is deposited into your Wise account.
+4. Convert funds into **40+ currencies** or withdraw them to your local bank. **UK and EU users can also request a Wise debit card**.
 
-{% include faq-begin.md %}
+## Setting Up Wise for Expensify
+1. Confirm with your employer if **USD expenses** can be submitted.  
+2. Open a **Wise Borderless Account** and complete **verification** (may take up to **3 days**).  
+3. Add your **Wise USD account and ACH routing number** to Expensify.  
 
-**Is there a way I can track my payment?**
+**Important:** Use the **ACH routing number**, *not* the wire transfer routing number.
+
+Expensify will **automatically convert non-USD expenses** to USD before submission.
+
+---
+
+# Third-Party Payment Options
+
+Expensify integrates with **PayPal** and **Venmo** to provide alternative reimbursement options.
+
+## Benefits of Third-Party Payments
+- **Faster reimbursements** compared to standard ACH transfers.  
+- **Enhanced security** via trusted payment platforms.  
+- **Streamlined expense management** within Expensify.
+
+## Connecting a Third-Party Payment Option
+1. Log into your **Expensify account**.
+2. Navigate to **Settings > Account > Payments > Alternative Payment Accounts**.
+3. Select **PayPal** or **Venmo**:
+   - **PayPal**: Enter your **PayPal.Me** username.
+   - **Venmo**: Enter your **mobile number** (must match your Venmo account).
+
+---
 
-For U.S. ACH payments and global reimbursements, the expected date of reimbursement is provided at the top of the report and in the comments section of the report. Funds will be deposited within the typical ACH time frame of four to five business days unless the payment is eligible for Rapid Reimbursement. 
+# FAQ
 
-**For global payments, what currency is the payment provided in?**
+## Can I link multiple third-party payment providers?
+Yes, you can link both **PayPal and Venmo** to your Expensify account.
 
-Global payments are reimbursed in the recipient's currency. 
+## Is there a limit on third-party reimbursements?
+Limits depend on **Expensify settings** and **third-party provider restrictions**.
 
-{% include faq-end.md %}
+## How can I track my reimbursement?
+For **ACH and global payments**, Expensify displays the **expected deposit date** at the top of your expense report and in the report comments.
 
-</div>
+## What currency will my global reimbursement be in?
+Expensify will reimburse you in your local currency, based on the conversion at the time of payout.
diff --git a/docs/articles/expensify-classic/expensify-partner-program/Card-Revenue-Share.md b/docs/articles/expensify-classic/expensify-partner-program/Card-Revenue-Share.md
index 663a5e3cd9c8..96d961c479a9 100644
--- a/docs/articles/expensify-classic/expensify-partner-program/Card-Revenue-Share.md
+++ b/docs/articles/expensify-classic/expensify-partner-program/Card-Revenue-Share.md
@@ -1,27 +1,42 @@
 ---
-title: Expensify Card revenue share for ExpensifyApproved! partners
-description: Earn money when your clients adopt the Expensify Card
+title: Expensify-Card-Revenue-Share.md
+description: Learn how ExpensifyApproved! partner accountants can earn revenue by helping clients adopt the Expensify Card.
+keywords: [Expensify Card, revenue share, ExpensifyApproved! partner, accountant earnings]
 ---
-You can now earn additional income for your firm every time your client uses their Expensify Card. In short, your firm gets 0.5% of your clients’ total Expensify Card spend as cash back. The more your clients spend, the more cashback your firm receives!
 
-This program is currently only available to US-based ExpensifyApproved! partner accountants.
+ExpensifyApproved! Accounting Partners in the US can now earn additional income through the Expensify Card. Your firm will receive **0.5% of your clients’ total Expensify Card spend** as cashback -- More client spending means more revenue for your firm!
 
-# Become a Domain Admin
-To benefit from this program, you or a member of your firm must be a domain admin on the client’s domain in Expensify:
-1. Head to *Settings > Domains*
-2. Click the client's domain
-     - If you can click on the domain and access the domain settings, you are a Domain Admin
-     - If you’re not a Domain Admin, your client can add you as one by heading to **Settings > Domains > [Client's Domain] > Domain Admins > Add Admin**.
+**Note:** This program is currently available only to **US-based ExpensifyApproved! partner accountants**.
 
-_**Note:** You can view all domain admins under Settings > Domains > [Client's Domain] > Domain Admins._
+---
+
+# How to Earn Revenue
+
+## 1. Become a Domain Admin
+To qualify, you or a member of your firm must be a **Domain Admin** on the client’s domain in Expensify.
+
+Steps to becoming a Domain Admin:
+1. Go to **Settings > Domains**.
+2. Click on your client’s domain.
+   - If you can access the domain settings, you are a Domain Admin.
+   - If you are not a Domain Admin, ask your client to add you:
+     - Navigate to **Settings > Domains > [Client's Domain] > Domain Admins > Add Admin**.
+
+**Tip:** You can view all Domain Admins under **Settings > Domains > [Client's Domain] > Domain Admins**.
 
-# Connect a deposit-only business bank account
-[Follow these instructions](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-US-Business-Bank-Account#connect-a-business-deposit-only-account) to connect a deposit-only business bank account.
+---
+
+## 2. Connect a Deposit-Only Business Bank Account
+To receive your revenue share, connect a **deposit-only business bank account**:
+
+[Follow these instructions](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-US-Business-Bank-Account#connect-a-business-deposit-only-account) to complete the setup.
 
-Once that's complete, any revenue earned will be deposited directly into that bank account. 
+Once connected, all earned revenue will be deposited directly into this account.
+
+---
 
-{% include faq-begin.md %}
+# FAQ
 
-## What if my firm is not permitted to accept revenue share from our clients?
+## What if my firm cannot accept revenue share from clients?
 
-We understand that different firms may have different policies. If your firm is unable to accept this revenue share, you can pass the revenue share back to your client to give them an additional 0.5% of cash back using your own internal payment tools.
+We understand that some firms have restrictions on receiving revenue share. If your firm cannot accept the cashback, you can choose to pass the 0.5% cashback directly to your client using your internal payment tools.
diff --git a/docs/articles/expensify-classic/expensify-partner-program/Referral-Program.md b/docs/articles/expensify-classic/expensify-partner-program/Referral-Program.md
deleted file mode 100644
index 3153e6e217fa..000000000000
--- a/docs/articles/expensify-classic/expensify-partner-program/Referral-Program.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: Refer a Friend to New Expensify!
-description: Share your invite link with a friend, start a chat with a coworker or request money from your boss
----
-<!-- The lines above are required by Jekyll to process the .md file -->
-
-# About
-
-New Expensify's referral program is currently paused. Please check back later. 
-
-[New Expensify](https://new.expensify.com/) is growing thanks to members like you who love it so much that they tell their friends, family, colleagues, managers, and fellow business founders to use it, too. 
-
-# How to refer a friend to New Expensify
-
-1. There are a bunch of different ways to refer someone to New Expensify:
-   - Start a chat
-   - Submit an expense to them
-   - Split an expense with them
-   - Pay someone (them)
-   - Assign them a task
-   - @ mention them
-   - Invite them to a room
-   - Add them to a workspace
-     
-
-{% include faq-begin.md %}
-
-- **Where can I find my referral link?** 
-
-In New Expensify, go to **Settings** > **Share code** > **Get $250** to retrieve your invite link.
-{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md b/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md
index 8243833dcc23..a8c54842e13e 100644
--- a/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md
+++ b/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md
@@ -1,77 +1,82 @@
 ---
 title: Expensify Partner Support
-description: Understanding support for our partners
+description: Learn about Expensify's Partner Support program, including training, dedicated partner managers, and real-time chat support.
+keywords: [ExpensifyApproved, partner support, training, partner manager, onboarding, concierge]
 ---
 
-# Overview
-As an ExpensifyApproved! Partner, your firm gains access to a specialized suite of support services. We're here to ensure your clients have the tools and resources they need, every step of the way.
-Our well-rounded support methodology is designed to provide comprehensive assistance, ensuring that both you and your clients have a seamless experience. Have questions or want to delve deeper? Don't hesitate to reach out to your dedicated Partner Manager to get started!
+As an **ExpensifyApproved! Partner**, your firm gains access to exclusive support services designed to enhance your experience and help your clients succeed. This guide outlines the key support resources available to you.
 
+# ExpensifyApproved! University
 
-## 1. ExpensifyApproved! University
-**Purpose:** Equip your team with a comprehensive understanding of Expensify.
+**Purpose:** Train and certify your team on Expensify.
 
 **Benefits:**
-- Foundation-level knowledge about the platform.
-- 3 CPE credits upon successful completion (US-only).
-- Unlock exclusive partner perks, including tickets to ExpensiCon!
-- Visit university.Expensify.com to access our comprehensive training program.
+- Gain foundational knowledge of Expensify.
+- Earn **3 CPE credits** (US-only).
+- Unlock partner perks, including tickets to **ExpensiCon**.
+- Access training at [university.expensify.com](https://university.expensify.com).
 
-## 2. Partner Manager
-**Role:** 
-A Partner Manager is a dedicated point of contact for your firm Partner Managers support our accounting partners by providing recommendations for client’s accounts, assisting with firm-wide training, and ensuring partners receive the full benefits of our partnership program. They will actively monitor open technical issues and be proactive with recommendations to increase efficiency.
+---
+
+# Partner Manager
 
+Your **Partner Manager** is your dedicated contact for strategic support.
 
-**Key Responsibilities:**
-- Handle any escalations promptly.
+## Key Responsibilities:
+- Handle escalations promptly.
 - Organize firm-wide training sessions.
-- Assist with strategic planning and the introduction of new features.
-- Once you've completed the ExpensifyApproved! University, log in to your Expensify account. Click on the "Support" option to connect with your dedicated Partner Manager.
+- Provide recommendations to optimize your clients' accounts.
+- Assist with strategic planning and feature adoption.
 
-**How do I know if I have a Partner Manager?**
+## How to Connect with Your Partner Manager
+To be assigned a **Partner Manager**, you must complete the **ExpensifyApproved! University** training. Once completed, check your **Expensify account**:
+- Look for the **ExpensifyApproved!** logo in the bottom left-hand corner.
+- Navigate to `Support` to message your **Partner Manager**.
 
-For your firm to be assigned a Partner Manager, you must complete the ExpensifyApproved! University training course. Every external accountant or bookkeeper who completes the training is automatically enrolled in our program and receives all the benefits, including access to the Partner Manager. So everyone at your firm must complete the training to receive the maximum benefit.
+**Contact Options:**
+1. Log in to [new.expensify.com](https://new.expensify.com) and search for your **Partner Manager**.
+2. Reply to any email from your **Partner Manager**.
 
-You can check to see if you’ve completed the course and enrolled in the ExpensifyApproved! Accountants program simply by logging into your Expensify account. In the bottom left-hand corner of the website, you will see the ExpensifyApproved! logo.
+**Checking Availability:**
+- Your **Partner Manager's** status in **New Expensify** will show as **"Online"** or display their working hours.
 
-**How do I contact my Partner Manager?**
-1. Signing in to new.expensify.com and searching for your Partner Manager
-2. Replying to or clicking the chat link on any email you get from your Partner Manager
+**Scheduling a Call:**
+- You can request a call for discussions on client onboarding, training, and best practices.
+- For general support questions, use **Concierge chat** for immediate assistance.
 
-**How do I know if my Partner Manager is online?**
+---
 
-You will be able to see if they are online via their status in new.expensify.com, which will either say “online” or have their working hours.
+# Client Setup Specialist
 
-**Can I get on a call with my Partner Manager?**
+**Purpose:** Ensure seamless onboarding for your referred clients.
 
-Of course! You can ask your Partner Manager to schedule a call whenever you think one might be helpful. Partner Managers can discuss client onboarding strategies, firm-wide training, and client setups.
+**Duties:**
+- Assist with Expensify setup and **accounting integrations**.
+- Ensure clients have the necessary tools and knowledge.
+- To connect with a **Client Setup Specialist**, log in and navigate to `Support`.
 
-We recommend continuing to work with Concierge for general support questions, as this team is always online and available to help immediately.
+---
 
-## 3. Client Setup Specialist
-**Purpose:** Ensure smooth onboarding for every client you refer.
+# Client Account Manager
 
-**Duties:**
-- Comprehensive assistance with setting up Expensify.
-- Help with configuring accounting integrations.
-- Ensure clients have the tools and knowledge they need to thrive.
-- After logging into Expensify, click on the "Support" option in the left-hand navigation pane. This will connect you directly to your assigned Client Onboarding Manager.
-
-## 4. Client Account Manager
-**Role:** Dedicated support for ongoing client needs.
+**Role:** Provide ongoing support for client accounts.
 
 **Responsibilities:**
-- Address day-to-day product inquiries.
-- Assist clients in navigating and optimizing their use of Expensify.
-- After logging into Expensify, click on the "Support" option in the left-hand navigation pane. This will connect you directly to your assigned Account Manager.
+- Address daily product-related inquiries.
+- Guide clients in optimizing their **Expensify experience**.
+- To contact your **Client Account Manager**, log in and go to `Support`.
+
+---
 
-## 5. Concierge chat support
-**Availability:** Real-time support for any urgent inquiries.
+# Concierge Chat Support
+
+**Availability:** Real-time support for immediate inquiries.
 
 **Features:**
-- Immediate assistance with an average response time of under two minutes.
-- Available to both accountants and clients for all product-related questions.
-- For instant assistance, click on the chat bubble located at the bottom right-hand corner of your screen when logged in.
+- **Response time under 2 minutes**.
+- Available to **both accountants and clients**.
+- Click the **chat bubble** in the bottom right-hand corner of Expensify for instant help.
 
+---
 
-Our well-rounded support methodology is designed to provide comprehensive assistance, ensuring that both you and your clients have a seamless experience. Have questions or want to delve deeper? Don't hesitate to reach out to your dedicated Partner Manager. You can find your partner manager by logging into Expensify and clicking the "Support" button in the left hand navigator. 
+Expensify's Partner Support ensures you and your clients receive elevated support in Expensify. If you need further guidance, reach out via `Support` in your Expensify account or connect directly with your Partner Manager!
diff --git a/docs/articles/new-expensify/getting-started/Using-Reports-in-New-Expensify.md b/docs/articles/new-expensify/getting-started/Using-Reports-in-New-Expensify.md
index 7c2016b4e212..bc4afbe957a7 100644
--- a/docs/articles/new-expensify/getting-started/Using-Reports-in-New-Expensify.md
+++ b/docs/articles/new-expensify/getting-started/Using-Reports-in-New-Expensify.md
@@ -24,6 +24,8 @@ Expensify's Reports feature introduces a powerful way to access and manage finan
 - **Cross-platform consistency** - Enjoy a seamless experience across desktop and mobile platforms.
 - **Saved reports** - Save and revisit frequently used report queries for recurring tasks.
 
+![A photo of the Reports page]({{site.url}}/assets/images/ExpensifyHelp-Reports-1-v2.png){:width="100%"}
+
 ---
 
 # Report Filters
@@ -37,6 +39,8 @@ Expensify’s report filters help users narrow down results to find specific dat
   - Trips: Drafts, Upcoming, In Progress, Past
 - **Advanced filters** - Enable precise reports using query syntax (e.g., `type:expenses status:approved`).
 
+![A photo of common report filter]({{site.url}}/assets/images/ExpensifyHelp-SearchFormat.png){:width="100%"}
+
 ---
 
 # Search Format
diff --git a/docs/redirects.csv b/docs/redirects.csv
index 26d902954652..cf7fd558e5cf 100644
--- a/docs/redirects.csv
+++ b/docs/redirects.csv
@@ -663,3 +663,6 @@ https://help.expensify.com/articles/expensify-classic/reports/Add-comments-and-a
 https://help.expensify.com/articles/expensify-classic/expensify-card/Statements,https://help.expensify.com/articles/expensify-classic/expensify-card/Expensify-Card-Statements
 https://help.expensify.com/articles/expensify-classic/expensify-billing/Out-of-date-Billing,https://help.expensify.com/articles/expensify-classic/expensify-billing/Out-of-Date-Billing
 https://help.expensify.com/articles/expensify-classic/settings/Set-time-zone,https://help.expensify.com/articles/expensify-classic/settings/Set-Time-Zone
+https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Get-reimbursed-faster-as-a-non-US-employee,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Receive-Payments
+https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/Third-Party-Payments,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Receive-Payments
+https://help.expensify.com/articles/expensify-classic/expensify-partner-program/Referral-Program,https://use.expensify.com/accountants-program
\ No newline at end of file
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index 4a7b8f7a1e3a..5259b0cfc5ef 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -23,7 +23,7 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>9.1.12</string>
+	<string>9.1.13</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleURLTypes</key>
@@ -44,7 +44,7 @@
 		</dict>
 	</array>
 	<key>CFBundleVersion</key>
-	<string>9.1.12.7</string>
+	<string>9.1.13.0</string>
 	<key>FullStory</key>
 	<dict>
 		<key>OrgId</key>
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index d7e45b02f7d2..6c877542b6f2 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
 	<key>CFBundlePackageType</key>
 	<string>BNDL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>9.1.12</string>
+	<string>9.1.13</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>9.1.12.7</string>
+	<string>9.1.13.0</string>
 </dict>
 </plist>
diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist
index 664e379b3d79..2c9338f0d407 100644
--- a/ios/NotificationServiceExtension/Info.plist
+++ b/ios/NotificationServiceExtension/Info.plist
@@ -11,9 +11,9 @@
 	<key>CFBundleName</key>
 	<string>$(PRODUCT_NAME)</string>
 	<key>CFBundleShortVersionString</key>
-	<string>9.1.12</string>
+	<string>9.1.13</string>
 	<key>CFBundleVersion</key>
-	<string>9.1.12.7</string>
+	<string>9.1.13.0</string>
 	<key>NSExtension</key>
 	<dict>
 		<key>NSExtensionPointIdentifier</key>
diff --git a/package-lock.json b/package-lock.json
index 4d5098f0c62c..0b70c75704bc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "new.expensify",
-  "version": "9.1.12-7",
+  "version": "9.1.13-0",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "new.expensify",
-      "version": "9.1.12-7",
+      "version": "9.1.13-0",
       "hasInstallScript": true,
       "license": "MIT",
       "dependencies": {
diff --git a/package.json b/package.json
index d51c0ad899d3..dbcb50f41f0e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "new.expensify",
-  "version": "9.1.12-7",
+  "version": "9.1.13-0",
   "author": "Expensify, Inc.",
   "homepage": "https://new.expensify.com",
   "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
diff --git a/src/App.tsx b/src/App.tsx
index 8dd2631a6b7d..3e6fc9ac2a27 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -17,6 +17,7 @@ import InitialURLContextProvider from './components/InitialURLContextProvider';
 import {InputBlurContextProvider} from './components/InputBlurContext';
 import KeyboardProvider from './components/KeyboardProvider';
 import {LocaleContextProvider} from './components/LocaleContextProvider';
+import NavigationBar from './components/NavigationBar';
 import OnyxProvider from './components/OnyxProvider';
 import PopoverContextProvider from './components/PopoverProvider';
 import {ProductTrainingContextProvider} from './components/ProductTrainingContext';
@@ -118,6 +119,7 @@ function App({url, hybridAppSettings, timestamp}: AppProps) {
                                     <Expensify />
                                 </ColorSchemeWrapper>
                             </ErrorBoundary>
+                            <NavigationBar />
                         </ComposeProviders>
                     </GestureHandlerRootView>
                 </InitialURLContextProvider>
diff --git a/src/CONST.ts b/src/CONST.ts
index 1d4a682fa262..a5542620fdf9 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -781,6 +781,7 @@ const CONST = {
         NEWDOT_INTERNATIONAL_DEPOSIT_BANK_ACCOUNT: 'newDotInternationalDepositBankAccount',
         NSQS: 'nsqs',
         CUSTOM_RULES: 'customRules',
+        TABLE_REPORT_VIEW: 'tableReportView',
     },
     BUTTON_STATES: {
         DEFAULT: 'default',
@@ -1026,7 +1027,7 @@ const CONST = {
     GITHUB_RELEASE_URL: 'https://api.github.com/repos/expensify/app/releases/latest',
     ADD_SECONDARY_LOGIN_URL: encodeURI('settings?param={"section":"account","openModal":"secondaryLogin"}'),
     MANAGE_CARDS_URL: 'domain_companycards',
-    FEES_URL: `${USE_EXPENSIFY_URL}/fees`,
+    FEES_URL: `${EXPENSIFY_URL}/fees`,
     SAVE_WITH_EXPENSIFY_URL: `${USE_EXPENSIFY_URL}/savings-calculator`,
     CFPB_PREPAID_URL: 'https://cfpb.gov/prepaid',
     STAGING_NEW_EXPENSIFY_URL: 'https://staging.new.expensify.com',
@@ -1311,6 +1312,7 @@ const CONST = {
                     CORPORATE_UPGRADE: 'POLICYCHANGELOG_CORPORATE_UPGRADE',
                     TEAM_DOWNGRADE: 'POLICYCHANGELOG_TEAM_DOWNGRADE',
                 },
+                RESOLVED_DUPLICATES: 'RESOLVEDDUPLICATES',
                 ROOM_CHANGE_LOG: {
                     INVITE_TO_ROOM: 'INVITETOROOM',
                     REMOVE_FROM_ROOM: 'REMOVEFROMROOM',
@@ -1531,6 +1533,20 @@ const CONST = {
         LIGHT: 'light',
         DARK: 'dark',
     },
+    NAVIGATION_BAR_TYPE: {
+        // We consider there to be no navigation bar in one of these cases:
+        // 1. The device has physical navigation buttons
+        // 2. The device uses gesture navigation without a gesture bar.
+        // 3. The device uses hidden (auto-hiding) soft keys.
+        NONE: 'none',
+        SOFT_KEYS: 'soft-keys',
+        GESTURE_BAR: 'gesture-bar',
+    },
+    // Currently, in Android there is no native API to detect the type of navigation bar (soft keys vs. gesture).
+    // The navigation bar on (standard) Android devices is around 30-50dpi tall. (Samsung: 40dpi, Huawei: ~34dpi)
+    // To leave room to detect soft-key navigation bars on non-standard Android devices,
+    // we set this height threshold to 30dpi, since gesture bars will never be taller than that. (Samsung & Huawei: ~14-15dpi)
+    NAVIGATION_BAR_ANDROID_SOFT_KEYS_MINIMUM_HEIGHT_THRESHOLD: 30,
     TRANSACTION: {
         DEFAULT_MERCHANT: 'Expense',
         UNKNOWN_MERCHANT: 'Unknown Merchant',
@@ -1928,6 +1944,7 @@ const CONST = {
         AUTO_CREATE_VENDOR: 'autoCreateVendor',
         REIMBURSEMENT_ACCOUNT_ID: 'reimbursementAccountID',
         COLLECTION_ACCOUNT_ID: 'collectionAccountID',
+        ACCOUNTING_METHOD: 'accountingMethod',
     },
 
     XERO_CONFIG: {
@@ -2460,7 +2477,7 @@ const CONST = {
         BANCORP_WALLET_PROGRAM_ID: '660',
         PROGRAM_ISSUERS: {
             EXPENSIFY_PAYMENTS: 'Expensify Payments LLC',
-            BANCORP_BANK: 'The Bancorp Bank',
+            BANCORP_BANK: 'The Bancorp Bank, N.A.',
         },
     },
 
@@ -3363,7 +3380,7 @@ const CONST = {
             `(?<!^[^\`\n]*(?:\`[^\`\n]*\`[^\`\n]*)*\`[^\`\n]*)@[\\w\\-\\+\\'#@]+(?:\\.[\\w\\-\\'\\+]+)*|@[\\w\\-\\+\\'#@]+(?:\\.[\\w\\-\\'\\+]+)*(?![^\n]*\`)`,
             'gim',
         ),
-        REPORT_ID_FROM_PATH: /\/r\/(\d+)/,
+        REPORT_ID_FROM_PATH: /(?<!\/search)\/r\/(\d+)/,
         DISTANCE_MERCHANT: /^[0-9.]+ \w+ @ (-|-\()?[^0-9.\s]{1,3} ?[0-9.]+\)? \/ \w+$/,
         WHITESPACE: /\s+/g,
 
@@ -6231,6 +6248,7 @@ const CONST = {
     },
 
     DOT_SEPARATOR: '•',
+    BULLET: '●',
 
     DEFAULT_TAX: {
         defaultExternalID: 'id_TAX_EXEMPT',
@@ -6358,6 +6376,7 @@ const CONST = {
             SORT_BY: 'sortBy',
             SORT_ORDER: 'sortOrder',
             POLICY_ID: 'policyID',
+            GROUP_BY: 'groupBy',
         },
         SYNTAX_FILTER_KEYS: {
             DATE: 'date',
@@ -6394,6 +6413,7 @@ const CONST = {
             SORT_BY: 'sort-by',
             SORT_ORDER: 'sort-order',
             POLICY_ID: 'workspace',
+            GROUP_BY: 'group-by',
             DATE: 'date',
             AMOUNT: 'amount',
             EXPENSE_TYPE: 'expense-type',
@@ -6422,6 +6442,12 @@ const CONST = {
         },
     },
 
+    EXPENSE: {
+        TYPE: {
+            CASH_CARD_NAME: 'Cash Expense',
+        },
+    },
+
     REFERRER: {
         NOTIFICATION: 'notification',
     },
@@ -6784,6 +6810,7 @@ const CONST = {
         SCAN_TEST_TOOLTIP_MANAGER: 'scanTestTooltipManager',
         SCAN_TEST_CONFIRMATION: 'scanTestConfirmation',
     },
+    CHANGE_POLICY_TRAINING_MODAL: 'changePolicyModal',
     SMART_BANNER_HEIGHT: 152,
 
     NAVIGATION_TESTS: {
@@ -6815,6 +6842,7 @@ const CONST = {
     },
     SKIPPABLE_COLLECTION_MEMBER_IDS: [String(DEFAULT_NUMBER_ID), '-1', 'undefined', 'null', 'NaN'] as string[],
     SETUP_SPECIALIST_LOGIN: 'Setup Specialist',
+    ILLUSTRATION_ASPECT_RATIO: 39 / 22,
 } as const;
 
 type Country = keyof typeof CONST.ALL_COUNTRIES;
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 59ced1d61589..23f90c1411d6 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -39,8 +39,8 @@ const ROUTES = {
 
     SEARCH_ROOT: {
         route: 'search',
-        getRoute: ({query, name, groupBy}: {query: SearchQueryString; name?: string; groupBy?: string}) => {
-            return `search?q=${encodeURIComponent(query)}${groupBy ? `&groupBy=${groupBy}` : ''}${name ? `&name=${name}` : ''}` as const;
+        getRoute: ({query, name}: {query: SearchQueryString; name?: string}) => {
+            return `search?q=${encodeURIComponent(query)}${name ? `&name=${name}` : ''}` as const;
         },
     },
     SEARCH_SAVED_SEARCH_RENAME: {
@@ -79,9 +79,9 @@ const ROUTES = {
         },
     },
     SEARCH_MONEY_REQUEST_REPORT: {
-        route: 'search/report/:reportID',
+        route: 'search/r/:reportID',
         getRoute: ({reportID, backTo}: {reportID: string; backTo?: string}) => {
-            const baseRoute = `search/view/${reportID}` as const;
+            const baseRoute = `search/r/${reportID}` as const;
             return getUrlWithBackToParam(baseRoute, backTo);
         },
     },
@@ -310,6 +310,7 @@ const ROUTES = {
     NEW_CHAT_EDIT_NAME: 'new/chat/confirm/name/edit',
     NEW_ROOM: 'new/room',
 
+    NEW_REPORT_WORKSPACE_SELECTION: 'new-report-workspace-selection',
     REPORT: 'r',
     REPORT_WITH_ID: {
         route: 'r/:reportID?/:reportActionID?',
@@ -405,6 +406,10 @@ const ROUTES = {
         route: 'r/:reportID/details/export/:connectionName',
         getRoute: (reportID: string, connectionName: ConnectionName, backTo?: string) => getUrlWithBackToParam(`r/${reportID}/details/export/${connectionName as string}` as const, backTo),
     },
+    REPORT_WITH_ID_CHANGE_WORKSPACE: {
+        route: 'r/:reportID/change-workspace',
+        getRoute: (reportID: string, backTo?: string) => getUrlWithBackToParam(`r/${reportID}/change-workspace` as const, backTo),
+    },
     REPORT_SETTINGS: {
         route: 'r/:reportID/settings',
         getRoute: (reportID: string, backTo?: string) => getUrlWithBackToParam(`r/${reportID}/settings` as const, backTo),
@@ -1171,11 +1176,19 @@ const ROUTES = {
     },
     WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR: {
         route: 'settings/workspaces/:policyID/accounting/quickbooks-online/account-selector',
-        getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/account-selector` as const,
+        getRoute: (policyID: string | undefined) => `settings/workspaces/${policyID}/accounting/quickbooks-online/account-selector` as const,
     },
     WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR: {
         route: 'settings/workspaces/:policyID/accounting/quickbooks-online/invoice-account-selector',
-        getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/invoice-account-selector` as const,
+        getRoute: (policyID: string | undefined) => `settings/workspaces/${policyID}/accounting/quickbooks-online/invoice-account-selector` as const,
+    },
+    WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_AUTO_SYNC: {
+        route: 'settings/workspaces/:policyID/connections/quickbooks-online/advanced/autosync',
+        getRoute: (policyID: string | undefined) => `settings/workspaces/${policyID}/connections/quickbooks-online/advanced/autosync` as const,
+    },
+    WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD: {
+        route: 'settings/workspaces/:policyID/connections/quickbooks-online/advanced/autosync/accounting-method',
+        getRoute: (policyID: string | undefined) => `settings/workspaces/${policyID}/connections/quickbooks-online/advanced/autosync/accounting-method` as const,
     },
     WORKSPACE_ACCOUNTING_CARD_RECONCILIATION: {
         route: 'settings/workspaces/:policyID/accounting/:connection/card-reconciliation',
@@ -1680,6 +1693,10 @@ const ROUTES = {
         route: 'hold-expense-educational',
         getRoute: (backTo?: string) => getUrlWithBackToParam('hold-expense-educational', backTo),
     },
+    CHANGE_POLICY_EDUCATIONAL: {
+        route: 'change-workspace-educational',
+        getRoute: (backTo?: string) => getUrlWithBackToParam('change-workspace-educational', backTo),
+    },
     TRAVEL_MY_TRIPS: 'travel',
     TRAVEL_TCS: {
         route: 'travel/terms/:domain/accept',
@@ -2074,11 +2091,11 @@ const ROUTES = {
     },
     POLICY_ACCOUNTING_NETSUITE_AUTO_SYNC: {
         route: 'settings/workspaces/:policyID/connections/netsuite/advanced/autosync',
-        getRoute: (policyID: string) => `settings/workspaces/${policyID}/connections/netsuite/advanced/autosync` as const,
+        getRoute: (policyID: string | undefined) => `settings/workspaces/${policyID}/connections/netsuite/advanced/autosync` as const,
     },
     POLICY_ACCOUNTING_NETSUITE_ACCOUNTING_METHOD: {
         route: 'settings/workspaces/:policyID/connections/netsuite/advanced/autosync/accounting-method',
-        getRoute: (policyID: string) => `settings/workspaces/${policyID}/connections/netsuite/advanced/autosync/accounting-method` as const,
+        getRoute: (policyID: string | undefined) => `settings/workspaces/${policyID}/connections/netsuite/advanced/autosync/accounting-method` as const,
     },
     POLICY_ACCOUNTING_NSQS_SETUP: {
         route: 'settings/workspaces/:policyID/accounting/nsqs/setup',
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index 0825b540244f..759755a04617 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -164,7 +164,9 @@ const SCREENS = {
         NEW_CHAT: 'NewChat',
         DETAILS: 'Details',
         PROFILE: 'Profile',
+        NEW_REPORT_WORKSPACE_SELECTION: 'New_Report_Workspace_Selection',
         REPORT_DETAILS: 'Report_Details',
+        REPORT_CHANGE_WORKSPACE: 'ReportChangeWorkspace',
         WORKSPACE_CONFIRMATION: 'Workspace_Confirmation',
         REPORT_SETTINGS: 'Report_Settings',
         REPORT_DESCRIPTION: 'Report_Description',
@@ -327,12 +329,20 @@ const SCREENS = {
         EDIT: 'PrivateNotes_Edit',
     },
 
+    NEW_REPORT_WORKSPACE_SELECTION: {
+        ROOT: 'NewReportWorkspaceSelection_Root',
+    },
+
     REPORT_DETAILS: {
         ROOT: 'Report_Details_Root',
         SHARE_CODE: 'Report_Details_Share_Code',
         EXPORT: 'Report_Details_Export',
     },
 
+    REPORT_CHANGE_WORKSPACE: {
+        ROOT: 'ReportChangeWorkspace_Root',
+    },
+
     WORKSPACE_CONFIRMATION: {ROOT: 'Workspace_Confirmation_Root'},
 
     WORKSPACE: {
@@ -361,6 +371,8 @@ const SCREENS = {
             QUICKBOOKS_ONLINE_CLASSES_DISPLAYED_AS: 'Policy_Accounting_Quickbooks_Online_Import_Classes_Displayed_As',
             QUICKBOOKS_ONLINE_CUSTOMERS_DISPLAYED_AS: 'Policy_Accounting_Quickbooks_Online_Import_Customers_Displayed_As',
             QUICKBOOKS_ONLINE_LOCATIONS_DISPLAYED_AS: 'Policy_Accounting_Quickbooks_Online_Import_Locations_Displayed_As',
+            QUICKBOOKS_ONLINE_AUTO_SYNC: 'Policy_Accounting_Quickbooks_Online_Auto_Sync',
+            QUICKBOOKS_ONLINE_ACCOUNTING_METHOD: 'Policy_Accounting_Quickbooks_Online_Accounting_Method',
             QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT: 'Workspace_Accounting_Quickbooks_Desktop_Export_Company_Card_Expense_Account_Select',
             QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_COMPANY_CARD_SELECT: 'Workspace_Accounting_Quickbooks_Desktop_Export_Company_Card_Expense_Select',
             QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT: 'Workspace_Accounting_Quickbooks_Desktop_Export_Company_Card_Expense',
@@ -646,6 +658,7 @@ const SCREENS = {
     DETAILS_ROOT: 'Details_Root',
     PROFILE_ROOT: 'Profile_Root',
     PROCESS_MONEY_REQUEST_HOLD_ROOT: 'ProcessMoneyRequestHold_Root',
+    CHANGE_POLICY_EDUCATIONAL_ROOT: 'ChangePolicyEducational_Root',
     REPORT_DESCRIPTION_ROOT: 'Report_Description_Root',
     REPORT_PARTICIPANTS: {
         ROOT: 'ReportParticipants_Root',
diff --git a/src/components/Attachments/AttachmentView/index.tsx b/src/components/Attachments/AttachmentView/index.tsx
index 2c07863ea2e8..93729a8e0da3 100644
--- a/src/components/Attachments/AttachmentView/index.tsx
+++ b/src/components/Attachments/AttachmentView/index.tsx
@@ -14,7 +14,7 @@ import Text from '@components/Text';
 import {usePlaybackContext} from '@components/VideoPlayerContexts/PlaybackContext';
 import useLocalize from '@hooks/useLocalize';
 import useNetwork from '@hooks/useNetwork';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useStyleUtils from '@hooks/useStyleUtils';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
@@ -116,7 +116,7 @@ function AttachmentView({
     const {updateCurrentlyPlayingURL} = usePlaybackContext();
 
     const theme = useTheme();
-    const {safeAreaPaddingBottomStyle} = useStyledSafeAreaInsets();
+    const {safeAreaPaddingBottomStyle} = useSafeAreaPaddings();
     const styles = useThemeStyles();
     const StyleUtils = useStyleUtils();
     const [loadComplete, setLoadComplete] = useState(false);
diff --git a/src/components/AutoCompleteSuggestions/index.tsx b/src/components/AutoCompleteSuggestions/index.tsx
index 8d91525c25bc..a459cc193b40 100644
--- a/src/components/AutoCompleteSuggestions/index.tsx
+++ b/src/components/AutoCompleteSuggestions/index.tsx
@@ -64,7 +64,7 @@ function AutoCompleteSuggestions<TSuggestion>({measureParentContainerAndReportCu
     const StyleUtils = useStyleUtils();
     const insets = useSafeAreaInsets();
     const {keyboardHeight, isKeyboardAnimatingRef} = useKeyboardState();
-    const {paddingBottom: bottomInset, paddingTop: topInset} = StyleUtils.getSafeAreaPadding(insets ?? undefined);
+    const {paddingBottom: bottomInset, paddingTop: topInset} = StyleUtils.getPlatformSafeAreaPadding(insets ?? undefined);
 
     useEffect(() => {
         const container = containerRef.current;
@@ -103,8 +103,20 @@ function AutoCompleteSuggestions<TSuggestion>({measureParentContainerAndReportCu
             let bottomValue = windowHeight - (cursorCoordinates.y - scrollValue + y) - keyboardHeight;
             const widthValue = shouldUseNarrowLayout ? width : CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH;
 
-            const isEnoughSpaceToRenderMenuAboveForBig = isEnoughSpaceToRenderMenuAboveCursor({y, cursorCoordinates, scrollValue, contentHeight: contentMaxHeight, topInset});
-            const isEnoughSpaceToRenderMenuAboveForSmall = isEnoughSpaceToRenderMenuAboveCursor({y, cursorCoordinates, scrollValue, contentHeight: contentMinHeight, topInset});
+            const isEnoughSpaceToRenderMenuAboveForBig = isEnoughSpaceToRenderMenuAboveCursor({
+                y,
+                cursorCoordinates,
+                scrollValue,
+                contentHeight: contentMaxHeight,
+                topInset,
+            });
+            const isEnoughSpaceToRenderMenuAboveForSmall = isEnoughSpaceToRenderMenuAboveCursor({
+                y,
+                cursorCoordinates,
+                scrollValue,
+                contentHeight: contentMinHeight,
+                topInset,
+            });
 
             const newLeftOffset = shouldUseNarrowLayout ? x : bigScreenLeftOffset;
             // If the suggested word is longer than 150 (approximately half the width of the suggestion popup), then adjust a new position of popup
@@ -139,9 +151,11 @@ function AutoCompleteSuggestions<TSuggestion>({measureParentContainerAndReportCu
         });
     }, [measureParentContainerAndReportCursor, windowHeight, windowWidth, keyboardHeight, shouldUseNarrowLayout, suggestionsLength, bottomInset, topInset, isKeyboardAnimatingRef]);
 
-    if ((containerState.width === 0 && containerState.left === 0 && containerState.bottom === 0) || (containerState.cursorCoordinates.x === 0 && containerState.cursorCoordinates.y === 0)) {
+    // Prevent rendering if container dimensions are not set or if we have no suggestions
+    if ((containerState.width === 0 && containerState.left === 0 && containerState.bottom === 0) || !suggestionsLength) {
         return null;
     }
+
     return (
         <AutoCompleteSuggestionsPortal
             // eslint-disable-next-line react/jsx-props-no-spreading
diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx
index 3166b45f0064..6fc43cd9b236 100644
--- a/src/components/BlockingViews/BlockingView.tsx
+++ b/src/components/BlockingViews/BlockingView.tsx
@@ -11,6 +11,7 @@ import Lottie from '@components/Lottie';
 import type DotLottieAnimation from '@components/LottieAnimations/types';
 import Text from '@components/Text';
 import TextLink from '@components/TextLink';
+import useBottomSafeSafeAreaPaddingStyle from '@hooks/useBottomSafeSafeAreaPaddingStyle';
 import useLocalize from '@hooks/useLocalize';
 import useThemeStyles from '@hooks/useThemeStyles';
 import Navigation from '@libs/Navigation/Navigation';
@@ -47,6 +48,9 @@ type BaseBlockingViewProps = {
 
     /** Additional styles to apply to the container */
     containerStyle?: StyleProp<ViewStyle>;
+
+    /** Whether to add bottom safe area padding to the view. */
+    addBottomSafeAreaPadding?: boolean;
 };
 
 type BlockingViewIconProps = {
@@ -94,7 +98,8 @@ function BlockingView({
     animationWebStyle = {},
     CustomSubtitle,
     contentFitImage,
-    containerStyle,
+    containerStyle: containerStyleProp,
+    addBottomSafeAreaPadding = false,
 }: BlockingViewProps) {
     const styles = useThemeStyles();
     const {translate} = useLocalize();
@@ -132,6 +137,8 @@ function BlockingView({
         );
     }, [styles, subtitleText, shouldEmbedLinkWithSubtitle, CustomSubtitle]);
 
+    const containerStyle = useBottomSafeSafeAreaPaddingStyle({addBottomSafeAreaPadding, style: containerStyleProp});
+
     return (
         <View style={[styles.flex1, styles.alignItemsCenter, styles.justifyContentCenter, styles.ph10, containerStyle]}>
             {!!animation && (
diff --git a/src/components/BlockingViews/FullPageNotFoundView.tsx b/src/components/BlockingViews/FullPageNotFoundView.tsx
index d751d8bc666b..b9afe868878c 100644
--- a/src/components/BlockingViews/FullPageNotFoundView.tsx
+++ b/src/components/BlockingViews/FullPageNotFoundView.tsx
@@ -50,6 +50,9 @@ type FullPageNotFoundViewProps = {
 
     /** Whether we should display the button that opens new SearchRouter */
     shouldDisplaySearchRouter?: boolean;
+
+    /** Whether to add bottom safe area padding to the view. */
+    addBottomSafeAreaPadding?: boolean;
 };
 
 // eslint-disable-next-line rulesdir/no-negated-variables
@@ -67,6 +70,7 @@ function FullPageNotFoundView({
     shouldForceFullScreen = false,
     subtitleStyle,
     shouldDisplaySearchRouter,
+    addBottomSafeAreaPadding = true,
 }: FullPageNotFoundViewProps) {
     const styles = useThemeStyles();
     const {translate} = useLocalize();
@@ -93,6 +97,7 @@ function FullPageNotFoundView({
                         shouldShowLink={shouldShowLink}
                         onLinkPress={onLinkPress}
                         subtitleStyle={subtitleStyle}
+                        addBottomSafeAreaPadding={addBottomSafeAreaPadding}
                     />
                 </View>
             </ForceFullScreenView>
diff --git a/src/components/BlockingViews/FullPageOfflineBlockingView.tsx b/src/components/BlockingViews/FullPageOfflineBlockingView.tsx
index 787752dd4e72..dc5c210b3178 100644
--- a/src/components/BlockingViews/FullPageOfflineBlockingView.tsx
+++ b/src/components/BlockingViews/FullPageOfflineBlockingView.tsx
@@ -6,7 +6,12 @@ import useTheme from '@hooks/useTheme';
 import type ChildrenProps from '@src/types/utils/ChildrenProps';
 import BlockingView from './BlockingView';
 
-function FullPageOfflineBlockingView({children}: ChildrenProps) {
+type FullPageOfflineBlockingViewProps = ChildrenProps & {
+    /** Whether to add bottom safe area padding to the view. */
+    addBottomSafeAreaPadding?: boolean;
+};
+
+function FullPageOfflineBlockingView({children, addBottomSafeAreaPadding = true}: FullPageOfflineBlockingViewProps) {
     const {translate} = useLocalize();
     const {isOffline} = useNetwork();
 
@@ -19,6 +24,7 @@ function FullPageOfflineBlockingView({children}: ChildrenProps) {
                 iconColor={theme.offline}
                 title={translate('common.youAppearToBeOffline')}
                 subtitle={translate('common.thisFeatureRequiresInternet')}
+                addBottomSafeAreaPadding={addBottomSafeAreaPadding}
             />
         );
     }
diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx
index 5baba39107ac..fe3e28dcf50c 100644
--- a/src/components/Button/index.tsx
+++ b/src/components/Button/index.tsx
@@ -2,7 +2,7 @@ import {useIsFocused} from '@react-navigation/native';
 import type {ForwardedRef} from 'react';
 import React, {useCallback, useMemo, useState} from 'react';
 import type {GestureResponderEvent, LayoutChangeEvent, StyleProp, TextStyle, ViewStyle} from 'react-native';
-import {ActivityIndicator, View} from 'react-native';
+import {ActivityIndicator, StyleSheet, View} from 'react-native';
 import Icon from '@components/Icon';
 import * as Expensicons from '@components/Icon/Expensicons';
 import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
@@ -152,6 +152,12 @@ type ButtonProps = Partial<ChildrenProps> & {
 
     /** The text displays under the first line */
     secondLineText?: string;
+
+    /**
+     * Whether the button should have a background layer in the color of theme.appBG.
+     * This is needed for buttons that allow content to display under them.
+     */
+    shouldBlendOpacity?: boolean;
 };
 
 type KeyboardShortcutComponentProps = Pick<ButtonProps, 'isDisabled' | 'isLoading' | 'onPress' | 'pressOnEnter' | 'allowBubble' | 'enterKeyEventListenerPriority' | 'isPressOnEnterActive'>;
@@ -255,6 +261,7 @@ function Button(
         isPressOnEnterActive,
         isNested = false,
         secondLineText = '',
+        shouldBlendOpacity = false,
         ...rest
     }: ButtonProps,
     ref: ForwardedRef<View>,
@@ -356,6 +363,57 @@ function Button(
         return textComponent;
     };
 
+    const buttonStyles = useMemo<StyleProp<ViewStyle>>(
+        () => [
+            styles.button,
+            StyleUtils.getButtonStyleWithIcon(styles, small, medium, large, !!icon, !!(text?.length > 0), shouldShowRightIcon),
+            success ? styles.buttonSuccess : undefined,
+            danger ? styles.buttonDanger : undefined,
+            isDisabled ? styles.buttonOpacityDisabled : undefined,
+            isDisabled && !danger && !success ? styles.buttonDisabled : undefined,
+            shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
+            shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
+            text && shouldShowRightIcon ? styles.alignItemsStretch : undefined,
+            innerStyles,
+            link && styles.bgTransparent,
+        ],
+        [
+            StyleUtils,
+            danger,
+            icon,
+            innerStyles,
+            isDisabled,
+            large,
+            link,
+            medium,
+            shouldRemoveLeftBorderRadius,
+            shouldRemoveRightBorderRadius,
+            shouldShowRightIcon,
+            small,
+            styles,
+            success,
+            text,
+        ],
+    );
+
+    const buttonContainerStyles = useMemo<StyleProp<ViewStyle>>(
+        () => [buttonStyles, shouldBlendOpacity && styles.buttonBlendContainer],
+        [buttonStyles, shouldBlendOpacity, styles.buttonBlendContainer],
+    );
+
+    const buttonBlendForegroundStyle = useMemo<StyleProp<ViewStyle>>(() => {
+        if (!shouldBlendOpacity) {
+            return undefined;
+        }
+
+        const {backgroundColor, opacity} = StyleSheet.flatten(buttonStyles);
+
+        return {
+            backgroundColor,
+            opacity,
+        };
+    }, [buttonStyles, shouldBlendOpacity]);
+
     return (
         <>
             {pressOnEnter && (
@@ -402,6 +460,7 @@ function Button(
                 onPressIn={onPressIn}
                 onPressOut={onPressOut}
                 onMouseDown={onMouseDown}
+                shouldBlendOpacity={shouldBlendOpacity}
                 disabled={isLoading || isDisabled}
                 wrapperStyle={[
                     isDisabled ? {...styles.cursorDisabled, ...styles.noSelect} : {},
@@ -410,19 +469,7 @@ function Button(
                     shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
                     style,
                 ]}
-                style={[
-                    styles.button,
-                    StyleUtils.getButtonStyleWithIcon(styles, small, medium, large, !!icon, !!(text?.length > 0), shouldShowRightIcon),
-                    success ? styles.buttonSuccess : undefined,
-                    danger ? styles.buttonDanger : undefined,
-                    isDisabled ? styles.buttonOpacityDisabled : undefined,
-                    isDisabled && !danger && !success ? styles.buttonDisabled : undefined,
-                    shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
-                    shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
-                    text && shouldShowRightIcon ? styles.alignItemsStretch : undefined,
-                    innerStyles,
-                    link && styles.bgTransparent,
-                ]}
+                style={buttonContainerStyles}
                 isNested={isNested}
                 hoverStyle={[
                     shouldUseDefaultHover && !isDisabled ? styles.buttonDefaultHovered : undefined,
@@ -439,6 +486,7 @@ function Button(
                 onHoverIn={() => setIsHovered(true)}
                 onHoverOut={() => setIsHovered(false)}
             >
+                {shouldBlendOpacity && <View style={[StyleSheet.absoluteFill, buttonBlendForegroundStyle]} />}
                 {renderContent()}
                 {isLoading && (
                     <ActivityIndicator
diff --git a/src/components/ChangeWorkspaceMenuSectionList.tsx b/src/components/ChangeWorkspaceMenuSectionList.tsx
new file mode 100644
index 000000000000..2e159114264b
--- /dev/null
+++ b/src/components/ChangeWorkspaceMenuSectionList.tsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import {View} from 'react-native';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import convertToLTR from '@libs/convertToLTR';
+import variables from '@styles/variables';
+import type {TranslationPaths} from '@src/languages/types';
+import type IconAsset from '@src/types/utils/IconAsset';
+import Icon from './Icon';
+import * as Illustrations from './Icon/Illustrations';
+import RenderHTML from './RenderHTML';
+
+type ChangeWorkspaceMenuSection = {
+    /** The icon supplied with the section */
+    icon: IconAsset;
+
+    /** Translation key for the title */
+    titleTranslationKey: TranslationPaths;
+};
+
+const changeWorkspaceMenuSections: ChangeWorkspaceMenuSection[] = [
+    {
+        icon: Illustrations.FolderOpen,
+        titleTranslationKey: 'iou.changePolicyEducational.reCategorize',
+    },
+    {
+        icon: Illustrations.Workflows,
+        titleTranslationKey: 'iou.changePolicyEducational.workflows',
+    },
+];
+
+function ChangeWorkspaceMenuSectionList() {
+    const {translate} = useLocalize();
+    const styles = useThemeStyles();
+
+    return (
+        <>
+            {changeWorkspaceMenuSections.map((section) => (
+                <View
+                    key={section.titleTranslationKey}
+                    style={[styles.flexRow, styles.alignItemsCenter, styles.mt3]}
+                >
+                    <Icon
+                        width={variables.menuIconSize}
+                        height={variables.menuIconSize}
+                        src={section.icon}
+                        additionalStyles={[styles.mr4]}
+                    />
+                    <View style={[styles.flex1, styles.justifyContentCenter]}>
+                        <RenderHTML html={`<comment>${convertToLTR(translate(section.titleTranslationKey))}</comment>`} />
+                    </View>
+                </View>
+            ))}
+        </>
+    );
+}
+
+ChangeWorkspaceMenuSectionList.displayName = 'ChangeWorkspaceMenuSectionList';
+export default ChangeWorkspaceMenuSectionList;
diff --git a/src/components/CurrencySelectionList/index.tsx b/src/components/CurrencySelectionList/index.tsx
index fd0d4306f7c6..1052082480d3 100644
--- a/src/components/CurrencySelectionList/index.tsx
+++ b/src/components/CurrencySelectionList/index.tsx
@@ -18,6 +18,7 @@ function CurrencySelectionList({
     canSelectMultiple = false,
     recentlyUsedCurrencies,
     excludedCurrencies = [],
+    ...restProps
 }: CurrencySelectionListProps) {
     const [currencyList] = useOnyx(ONYXKEYS.CURRENCY_LIST);
     const [searchValue, setSearchValue] = useState('');
@@ -91,6 +92,8 @@ function CurrencySelectionList({
 
     return (
         <SelectionList
+            // eslint-disable-next-line react/jsx-props-no-spreading
+            {...restProps}
             sections={sections}
             ListItem={canSelectMultiple ? SelectableListItem : RadioListItem}
             textInputLabel={searchInputLabel}
diff --git a/src/components/CurrencySelectionList/types.ts b/src/components/CurrencySelectionList/types.ts
index 22068c849234..8ea68ede2dc7 100644
--- a/src/components/CurrencySelectionList/types.ts
+++ b/src/components/CurrencySelectionList/types.ts
@@ -1,11 +1,11 @@
-import type {ListItem} from '@components/SelectionList/types';
+import type {ListItem, SelectionListProps} from '@components/SelectionList/types';
 
 type CurrencyListItem = ListItem & {
     currencyName: string;
     currencyCode: string;
 };
 
-type CurrencySelectionListProps = {
+type CurrencySelectionListProps = Partial<SelectionListProps<CurrencyListItem>> & {
     /** Label for the search text input */
     searchInputLabel: string;
 
diff --git a/src/components/EmptyStateComponent/index.tsx b/src/components/EmptyStateComponent/index.tsx
index 058b2e564f89..d3a715ad8748 100644
--- a/src/components/EmptyStateComponent/index.tsx
+++ b/src/components/EmptyStateComponent/index.tsx
@@ -29,6 +29,7 @@ function EmptyStateComponent({
     lottieWebViewStyles,
     showsVerticalScrollIndicator,
     minModalHeight = 400,
+    addBottomSafeAreaPadding = false,
 }: EmptyStateComponentProps) {
     const styles = useThemeStyles();
     const [videoAspectRatio, setVideoAspectRatio] = useState(VIDEO_ASPECT_RATIO);
@@ -88,6 +89,7 @@ function EmptyStateComponent({
             showsVerticalScrollIndicator={showsVerticalScrollIndicator}
             contentContainerStyle={[{minHeight: minModalHeight}, styles.flexGrow1, styles.flexShrink0, containerStyles]}
             style={styles.flex1}
+            addBottomSafeAreaPadding={addBottomSafeAreaPadding}
         >
             <View style={[styles.skeletonBackground, styles.overflowHidden]}>
                 <SkeletonComponent
diff --git a/src/components/EmptyStateComponent/types.ts b/src/components/EmptyStateComponent/types.ts
index 7a6aee2760b3..a5eedd0878d3 100644
--- a/src/components/EmptyStateComponent/types.ts
+++ b/src/components/EmptyStateComponent/types.ts
@@ -25,6 +25,9 @@ type SharedProps<T> = {
     lottieWebViewStyles?: React.CSSProperties | undefined;
     minModalHeight?: number;
     showsVerticalScrollIndicator?: boolean;
+
+    /** Whether to add bottom safe area padding to the view. */
+    addBottomSafeAreaPadding?: boolean;
 };
 
 type MediaType<HeaderMedia, T extends MediaTypes> = SharedProps<T> & {
diff --git a/src/components/FeatureTrainingModal.tsx b/src/components/FeatureTrainingModal.tsx
index 613d786230f2..0307fdb90284 100644
--- a/src/components/FeatureTrainingModal.tsx
+++ b/src/components/FeatureTrainingModal.tsx
@@ -115,6 +115,12 @@ type FeatureTrainingModalSVGProps = {
 
     /** Determines how the image should be resized to fit its container */
     contentFitImage?: ImageContentFit;
+
+    /** The width of the image */
+    imageWidth?: number;
+
+    /** The height of the image */
+    imageHeight?: number;
 };
 
 // This page requires either an icon or a video/animation, but not both
@@ -143,6 +149,8 @@ function FeatureTrainingModal({
     contentInnerContainerStyles,
     contentOuterContainerStyles,
     modalInnerContainerStyle,
+    imageWidth,
+    imageHeight,
     isModalDisabled = true,
 }: FeatureTrainingModalProps) {
     const styles = useThemeStyles();
@@ -211,6 +219,8 @@ function FeatureTrainingModal({
                     <ImageSVG
                         src={image}
                         contentFit={contentFitImage}
+                        width={imageWidth}
+                        height={imageHeight}
                     />
                 )}
                 {!!videoURL && videoStatus === 'video' && (
@@ -241,6 +251,8 @@ function FeatureTrainingModal({
         );
     }, [
         image,
+        imageHeight,
+        imageWidth,
         contentFitImage,
         illustrationAspectRatio,
         styles.w100,
diff --git a/src/components/FixedFooter.tsx b/src/components/FixedFooter.tsx
index 90adaec7a27e..fe9179fa88b4 100644
--- a/src/components/FixedFooter.tsx
+++ b/src/components/FixedFooter.tsx
@@ -1,7 +1,8 @@
 import type {ReactNode} from 'react';
-import React from 'react';
+import React, {useMemo} from 'react';
 import type {StyleProp, ViewStyle} from 'react-native';
 import {View} from 'react-native';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useThemeStyles from '@hooks/useThemeStyles';
 
 type FixedFooterProps = {
@@ -10,16 +11,41 @@ type FixedFooterProps = {
 
     /** Styles to be assigned to Container */
     style?: StyleProp<ViewStyle>;
+
+    /** Whether to add bottom safe area padding to the content. */
+    addBottomSafeAreaPadding?: boolean;
+
+    /** Whether to stick the footer to the bottom of the screen. */
+    shouldStickToBottom?: boolean;
 };
 
-function FixedFooter({style, children}: FixedFooterProps) {
+function FixedFooter({style, children, addBottomSafeAreaPadding = false, shouldStickToBottom = false}: FixedFooterProps) {
     const styles = useThemeStyles();
+    const {paddingBottom} = useSafeAreaPaddings(true);
+
+    const footerStyle = useMemo<StyleProp<ViewStyle>>(() => {
+        const totalPaddingBottom = styles.pb5.paddingBottom + paddingBottom;
+
+        // If the footer should stick to the bottom, we use absolute positioning instead of flex.
+        // In this case, we need to use style.bottom instead of style.paddingBottom.
+        if (shouldStickToBottom) {
+            return {position: 'absolute', left: 0, right: 0, bottom: addBottomSafeAreaPadding ? totalPaddingBottom : styles.pb5.paddingBottom};
+        }
+
+        // If the footer should not stick to the bottom, we use flex and add the safe area padding in styles.paddingBottom.
+        if (addBottomSafeAreaPadding) {
+            return {paddingBottom: totalPaddingBottom};
+        }
+
+        // Otherwise, we just use the default bottom padding.
+        return styles.pb5;
+    }, [addBottomSafeAreaPadding, paddingBottom, shouldStickToBottom, styles.pb5]);
 
     if (!children) {
         return null;
     }
 
-    return <View style={[styles.ph5, styles.pb5, styles.flexShrink0, style]}>{children}</View>;
+    return <View style={[styles.ph5, styles.flexShrink0, footerStyle, style]}>{children}</View>;
 }
 
 FixedFooter.displayName = 'FixedFooter';
diff --git a/src/components/Form/FormProvider.tsx b/src/components/Form/FormProvider.tsx
index bf3746b61776..6c8d3f989e16 100644
--- a/src/components/Form/FormProvider.tsx
+++ b/src/components/Form/FormProvider.tsx
@@ -75,6 +75,12 @@ type FormProviderProps<TFormID extends OnyxFormKey = OnyxFormKey> = FormProps<TF
 
     /** Whether the form is loading */
     isLoading?: boolean;
+
+    /** Whether to add bottom safe area padding to the content. */
+    addBottomSafeAreaPadding?: boolean;
+
+    /** Whether the submit button should stick to the bottom of the screen. */
+    shouldSubmitButtonStickToBottom?: boolean;
 };
 
 function FormProvider(
diff --git a/src/components/Form/FormWrapper.tsx b/src/components/Form/FormWrapper.tsx
index cdc9a7129fa0..dfafa05b53b2 100644
--- a/src/components/Form/FormWrapper.tsx
+++ b/src/components/Form/FormWrapper.tsx
@@ -1,14 +1,14 @@
 import React, {useCallback, useMemo, useRef} from 'react';
 import type {RefObject} from 'react';
 // eslint-disable-next-line no-restricted-imports
-import type {ScrollView as RNScrollView, StyleProp, View, ViewStyle} from 'react-native';
-import {InteractionManager, Keyboard} from 'react-native';
+import type {ScrollView as RNScrollView, StyleProp, ViewStyle} from 'react-native';
+import {InteractionManager, Keyboard, View} from 'react-native';
 import {useOnyx} from 'react-native-onyx';
 import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
 import FormElement from '@components/FormElement';
 import ScrollView from '@components/ScrollView';
 import ScrollViewWithContext from '@components/ScrollViewWithContext';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useThemeStyles from '@hooks/useThemeStyles';
 import {getLatestErrorMessage} from '@libs/ErrorUtils';
 import type {OnyxFormKey} from '@src/ONYXKEYS';
@@ -39,6 +39,12 @@ type FormWrapperProps = ChildrenProps &
 
         /** Whether the form is loading */
         isLoading?: boolean;
+
+        /** If enabled, the content will have a bottom padding equal to account for the safe bottom area inset. */
+        addBottomSafeAreaPadding?: boolean;
+
+        /** Whether the submit button should stick to the bottom of the screen. */
+        shouldSubmitButtonStickToBottom?: boolean;
     };
 
 function FormWrapper({
@@ -62,9 +68,10 @@ function FormWrapper({
     isSubmitDisabled = false,
     isLoading = false,
     shouldScrollToEnd = false,
+    addBottomSafeAreaPadding = false,
+    shouldSubmitButtonStickToBottom = false,
 }: FormWrapperProps) {
     const styles = useThemeStyles();
-    const {paddingBottom: safeAreaInsetPaddingBottom} = useStyledSafeAreaInsets();
     const formRef = useRef<RNScrollView>(null);
     const formContentRef = useRef<View>(null);
 
@@ -103,13 +110,78 @@ function FormWrapper({
         focusInput?.focus?.();
     }, [errors, formState?.errorFields, inputRefs]);
 
+    const {paddingBottom} = useSafeAreaPaddings(true);
+    const SubmitButton = useMemo(
+        () =>
+            isSubmitButtonVisible && (
+                <FormAlertWithSubmitButton
+                    buttonText={submitButtonText}
+                    isDisabled={isSubmitDisabled}
+                    isAlertVisible={((!isEmptyObject(errors) || !isEmptyObject(formState?.errorFields)) && !shouldHideFixErrorsAlert) || !!errorMessage}
+                    isLoading={!!formState?.isLoading || isLoading}
+                    message={isEmptyObject(formState?.errorFields) ? errorMessage : undefined}
+                    onSubmit={onSubmit}
+                    footerContent={footerContent}
+                    onFixTheErrorsLinkPressed={onFixTheErrorsLinkPressed}
+                    containerStyles={[
+                        styles.mh0,
+                        styles.mt5,
+                        submitFlexEnabled ? styles.flex1 : {},
+                        submitButtonStyles,
+                        shouldSubmitButtonStickToBottom
+                            ? [
+                                  {
+                                      position: 'absolute',
+                                      left: 0,
+                                      right: 0,
+                                      bottom: styles.pb5.paddingBottom + paddingBottom,
+                                  },
+                                  style,
+                              ]
+                            : {},
+                    ]}
+                    enabledWhenOffline={enabledWhenOffline}
+                    isSubmitActionDangerous={isSubmitActionDangerous}
+                    disablePressOnEnter={disablePressOnEnter}
+                    enterKeyEventListenerPriority={1}
+                    shouldBlendOpacity={shouldSubmitButtonStickToBottom}
+                />
+            ),
+        [
+            disablePressOnEnter,
+            enabledWhenOffline,
+            errorMessage,
+            errors,
+            footerContent,
+            formState?.errorFields,
+            formState?.isLoading,
+            isLoading,
+            isSubmitActionDangerous,
+            isSubmitButtonVisible,
+            isSubmitDisabled,
+            onFixTheErrorsLinkPressed,
+            onSubmit,
+            paddingBottom,
+            shouldHideFixErrorsAlert,
+            shouldSubmitButtonStickToBottom,
+            style,
+            styles.flex1,
+            styles.mh0,
+            styles.mt5,
+            styles.pb5.paddingBottom,
+            submitButtonStyles,
+            submitButtonText,
+            submitFlexEnabled,
+        ],
+    );
+
     const scrollViewContent = useCallback(
         () => (
             <FormElement
                 key={formID}
                 ref={formContentRef}
                 // Note: the paddingBottom is only grater 0 if no parent has applied the inset yet:
-                style={[style, {paddingBottom: safeAreaInsetPaddingBottom + styles.pb5.paddingBottom}]}
+                style={[style, styles.pb5]}
                 onLayout={() => {
                     if (!shouldScrollToEnd) {
                         return;
@@ -122,77 +194,50 @@ function FormWrapper({
                 }}
             >
                 {children}
-                {isSubmitButtonVisible && (
-                    <FormAlertWithSubmitButton
-                        buttonText={submitButtonText}
-                        isDisabled={isSubmitDisabled}
-                        isAlertVisible={((!isEmptyObject(errors) || !isEmptyObject(formState?.errorFields)) && !shouldHideFixErrorsAlert) || !!errorMessage}
-                        isLoading={!!formState?.isLoading || isLoading}
-                        message={isEmptyObject(formState?.errorFields) ? errorMessage : undefined}
-                        onSubmit={onSubmit}
-                        footerContent={footerContent}
-                        onFixTheErrorsLinkPressed={onFixTheErrorsLinkPressed}
-                        containerStyles={[styles.mh0, styles.mt5, submitFlexEnabled ? styles.flex1 : {}, submitButtonStyles]}
-                        enabledWhenOffline={enabledWhenOffline}
-                        isSubmitActionDangerous={isSubmitActionDangerous}
-                        disablePressOnEnter={disablePressOnEnter}
-                        enterKeyEventListenerPriority={1}
-                    />
-                )}
+                {!shouldSubmitButtonStickToBottom && SubmitButton}
             </FormElement>
         ),
-        [
-            formID,
-            style,
-            safeAreaInsetPaddingBottom,
-            styles.pb5.paddingBottom,
-            styles.mh0,
-            styles.mt5,
-            styles.flex1,
-            children,
-            isSubmitButtonVisible,
-            submitButtonText,
-            isSubmitDisabled,
-            errors,
-            formState?.errorFields,
-            formState?.isLoading,
-            shouldHideFixErrorsAlert,
-            errorMessage,
-            isLoading,
-            onSubmit,
-            footerContent,
-            onFixTheErrorsLinkPressed,
-            submitFlexEnabled,
-            submitButtonStyles,
-            enabledWhenOffline,
-            isSubmitActionDangerous,
-            disablePressOnEnter,
-            shouldScrollToEnd,
-        ],
+        [formID, style, styles.pb5, children, shouldSubmitButtonStickToBottom, SubmitButton, shouldScrollToEnd],
     );
 
     if (!shouldUseScrollView) {
+        if (shouldSubmitButtonStickToBottom) {
+            return (
+                <>
+                    {scrollViewContent()}
+                    {SubmitButton}
+                </>
+            );
+        }
+
         return scrollViewContent();
     }
 
-    return scrollContextEnabled ? (
-        <ScrollViewWithContext
-            style={[styles.w100, styles.flex1]}
-            contentContainerStyle={styles.flexGrow1}
-            keyboardShouldPersistTaps="handled"
-            ref={formRef}
-        >
-            {scrollViewContent()}
-        </ScrollViewWithContext>
-    ) : (
-        <ScrollView
-            style={[styles.w100, styles.flex1]}
-            contentContainerStyle={styles.flexGrow1}
-            keyboardShouldPersistTaps="handled"
-            ref={formRef}
-        >
-            {scrollViewContent()}
-        </ScrollView>
+    return (
+        <View style={styles.flex1}>
+            {scrollContextEnabled ? (
+                <ScrollViewWithContext
+                    style={[styles.w100, styles.flex1]}
+                    contentContainerStyle={styles.flexGrow1}
+                    keyboardShouldPersistTaps="handled"
+                    addBottomSafeAreaPadding={addBottomSafeAreaPadding}
+                    ref={formRef}
+                >
+                    {scrollViewContent()}
+                </ScrollViewWithContext>
+            ) : (
+                <ScrollView
+                    style={[styles.w100, styles.flex1]}
+                    contentContainerStyle={styles.flexGrow1}
+                    keyboardShouldPersistTaps="handled"
+                    addBottomSafeAreaPadding={addBottomSafeAreaPadding}
+                    ref={formRef}
+                >
+                    {scrollViewContent()}
+                </ScrollView>
+            )}
+            {shouldSubmitButtonStickToBottom && SubmitButton}
+        </View>
     );
 }
 
diff --git a/src/components/FormAlertWithSubmitButton.tsx b/src/components/FormAlertWithSubmitButton.tsx
index fabb5e54cb60..3eb0b0abd508 100644
--- a/src/components/FormAlertWithSubmitButton.tsx
+++ b/src/components/FormAlertWithSubmitButton.tsx
@@ -62,6 +62,12 @@ type FormAlertWithSubmitButtonProps = {
 
     /** The priority to assign the enter key event listener to buttons. 0 is the highest priority. */
     enterKeyEventListenerPriority?: number;
+
+    /**
+     * Whether the button should have a background layer in the color of theme.appBG.
+     * This is needed for buttons that allow content to display under them.
+     */
+    shouldBlendOpacity?: boolean;
 };
 
 function FormAlertWithSubmitButton({
@@ -83,6 +89,7 @@ function FormAlertWithSubmitButton({
     useSmallerSubmitButtonSize = false,
     errorMessageStyle,
     enterKeyEventListenerPriority = 0,
+    shouldBlendOpacity = false,
 }: FormAlertWithSubmitButtonProps) {
     const styles = useThemeStyles();
     const style = [!footerContent ? {} : styles.mb3, buttonStyles];
@@ -107,6 +114,7 @@ function FormAlertWithSubmitButton({
                     {isOffline && !enabledWhenOffline ? (
                         <Button
                             success
+                            shouldBlendOpacity={shouldBlendOpacity}
                             isDisabled
                             text={buttonText}
                             style={style}
@@ -118,6 +126,7 @@ function FormAlertWithSubmitButton({
                         <Button
                             ref={buttonRef}
                             success
+                            shouldBlendOpacity={shouldBlendOpacity}
                             pressOnEnter={pressOnEnter}
                             enterKeyEventListenerPriority={enterKeyEventListenerPriority}
                             text={buttonText}
diff --git a/src/components/GrowlNotification/GrowlNotificationContainer/index.native.tsx b/src/components/GrowlNotification/GrowlNotificationContainer/index.native.tsx
index 0ca7756b0e0e..f7ddf2767402 100644
--- a/src/components/GrowlNotification/GrowlNotificationContainer/index.native.tsx
+++ b/src/components/GrowlNotification/GrowlNotificationContainer/index.native.tsx
@@ -11,7 +11,7 @@ function GrowlNotificationContainer({children, translateY}: GrowlNotificationCon
     const insets = useSafeAreaInsets();
     const animatedStyles = useAnimatedStyle(() => styles.growlNotificationTranslateY(translateY));
 
-    return <Animated.View style={[StyleUtils.getSafeAreaPadding(insets), styles.growlNotificationContainer, animatedStyles]}>{children}</Animated.View>;
+    return <Animated.View style={[StyleUtils.getPlatformSafeAreaPadding(insets), styles.growlNotificationContainer, animatedStyles]}>{children}</Animated.View>;
 }
 
 GrowlNotificationContainer.displayName = 'GrowlNotificationContainer';
diff --git a/src/components/HoldMenuSectionList.tsx b/src/components/HoldMenuSectionList.tsx
index 180b801c3f3c..b2dc5b1213e9 100644
--- a/src/components/HoldMenuSectionList.tsx
+++ b/src/components/HoldMenuSectionList.tsx
@@ -1,44 +1,42 @@
 import React from 'react';
 import {View} from 'react-native';
-import type {ImageSourcePropType} from 'react-native';
-import type {SvgProps} from 'react-native-svg';
 import useLocalize from '@hooks/useLocalize';
 import useThemeStyles from '@hooks/useThemeStyles';
 import variables from '@styles/variables';
 import type {TranslationPaths} from '@src/languages/types';
+import type IconAsset from '@src/types/utils/IconAsset';
 import Icon from './Icon';
 import * as Illustrations from './Icon/Illustrations';
 import Text from './Text';
 
 type HoldMenuSection = {
     /** The icon supplied with the section */
-    icon: React.FC<SvgProps> | ImageSourcePropType;
+    icon: IconAsset;
 
     /** Translation key for the title */
     titleTranslationKey: TranslationPaths;
 };
 
+const holdMenuSections: HoldMenuSection[] = [
+    {
+        icon: Illustrations.Stopwatch,
+        titleTranslationKey: 'iou.holdIsLeftBehind',
+    },
+    {
+        icon: Illustrations.RealtimeReport,
+        titleTranslationKey: 'iou.unholdWhenReady',
+    },
+];
+
 function HoldMenuSectionList() {
     const {translate} = useLocalize();
     const styles = useThemeStyles();
 
-    const holdMenuSections: HoldMenuSection[] = [
-        {
-            icon: Illustrations.Stopwatch,
-            titleTranslationKey: 'iou.holdIsLeftBehind',
-        },
-        {
-            icon: Illustrations.RealtimeReport,
-            titleTranslationKey: 'iou.unholdWhenReady',
-        },
-    ];
-
     return (
         <>
-            {holdMenuSections.map((section, i) => (
+            {holdMenuSections.map((section) => (
                 <View
-                    // eslint-disable-next-line react/no-array-index-key
-                    key={i}
+                    key={section.titleTranslationKey}
                     style={[styles.flexRow, styles.alignItemsCenter, styles.mt5]}
                 >
                     <Icon
@@ -58,6 +56,4 @@ function HoldMenuSectionList() {
 
 HoldMenuSectionList.displayName = 'HoldMenuSectionList';
 
-export type {HoldMenuSection};
-
 export default HoldMenuSectionList;
diff --git a/src/components/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts
index 737d588127a9..60961a746a8c 100644
--- a/src/components/Icon/Illustrations.ts
+++ b/src/components/Icon/Illustrations.ts
@@ -37,6 +37,7 @@ import ConciergeExclamation from '@assets/images/product-illustrations/concierge
 import CreditCardsBlue from '@assets/images/product-illustrations/credit-cards--blue.svg';
 import EmptyStateExpenses from '@assets/images/product-illustrations/emptystate__expenses.svg';
 import HoldExpense from '@assets/images/product-illustrations/emptystate__holdexpense.svg';
+import ReceiptFairy from '@assets/images/product-illustrations/emptystate__receiptfairy.svg';
 import EmptyStateTravel from '@assets/images/product-illustrations/emptystate__travel.svg';
 import FolderWithPapers from '@assets/images/product-illustrations/folder-with-papers.svg';
 import GpsTrackOrange from '@assets/images/product-illustrations/gps-track--orange.svg';
@@ -231,6 +232,7 @@ export {
     QRCode,
     RealtimeReport,
     HoldExpense,
+    ReceiptFairy,
     ReceiptEnvelope,
     Approval,
     WalletAlt,
diff --git a/src/components/KeyboardAvoidingView/index.android.tsx b/src/components/KeyboardAvoidingView/BaseKeyboardAvoidingView/index.android.tsx
similarity index 55%
rename from src/components/KeyboardAvoidingView/index.android.tsx
rename to src/components/KeyboardAvoidingView/BaseKeyboardAvoidingView/index.android.tsx
index ec2dc3bd18d7..5f185d18cd8e 100644
--- a/src/components/KeyboardAvoidingView/index.android.tsx
+++ b/src/components/KeyboardAvoidingView/BaseKeyboardAvoidingView/index.android.tsx
@@ -1,15 +1,12 @@
-/*
- * The KeyboardAvoidingView is only used on ios
- */
-import React from 'react';
+import type React from 'react';
 import type {KeyboardAvoidingViewProps} from 'react-native-keyboard-controller';
 import {KeyboardAvoidingView as KeyboardAvoidingViewComponent} from 'react-native-keyboard-controller';
 
-function KeyboardAvoidingView(props: KeyboardAvoidingViewProps) {
+function BaseKeyboardAvoidingView(props: KeyboardAvoidingViewProps) {
     // eslint-disable-next-line react/jsx-props-no-spreading
     return <KeyboardAvoidingViewComponent {...props} />;
 }
 
-KeyboardAvoidingView.displayName = 'KeyboardAvoidingView';
+BaseKeyboardAvoidingView.displayName = 'BaseKeyboardAvoidingView';
 
-export default KeyboardAvoidingView;
+export default BaseKeyboardAvoidingView;
diff --git a/src/components/KeyboardAvoidingView/BaseKeyboardAvoidingView/index.ios.tsx b/src/components/KeyboardAvoidingView/BaseKeyboardAvoidingView/index.ios.tsx
new file mode 100644
index 000000000000..f0136d4e6cba
--- /dev/null
+++ b/src/components/KeyboardAvoidingView/BaseKeyboardAvoidingView/index.ios.tsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import {KeyboardAvoidingView as KeyboardAvoidingViewComponent} from 'react-native';
+import type {KeyboardAvoidingViewProps} from '@components/KeyboardAvoidingView/types';
+
+function BaseKeyboardAvoidingView(props: KeyboardAvoidingViewProps) {
+    // eslint-disable-next-line react/jsx-props-no-spreading
+    return <KeyboardAvoidingViewComponent {...props} />;
+}
+
+BaseKeyboardAvoidingView.displayName = 'BaseKeyboardAvoidingView';
+
+export default BaseKeyboardAvoidingView;
diff --git a/src/components/KeyboardAvoidingView/BaseKeyboardAvoidingView/index.tsx b/src/components/KeyboardAvoidingView/BaseKeyboardAvoidingView/index.tsx
new file mode 100644
index 000000000000..e4fd93ef7302
--- /dev/null
+++ b/src/components/KeyboardAvoidingView/BaseKeyboardAvoidingView/index.tsx
@@ -0,0 +1,18 @@
+/*
+ * The KeyboardAvoidingView stub implementation for web and other platforms where the keyboard is handled automatically.
+ */
+import React from 'react';
+import {View} from 'react-native';
+import type {KeyboardAvoidingViewProps} from '@components/KeyboardAvoidingView/types';
+
+function BaseKeyboardAvoidingView(props: KeyboardAvoidingViewProps) {
+    const {behavior, contentContainerStyle, enabled, keyboardVerticalOffset, ...rest} = props;
+    return (
+        // eslint-disable-next-line react/jsx-props-no-spreading
+        <View {...rest} />
+    );
+}
+
+BaseKeyboardAvoidingView.displayName = 'BaseKeyboardAvoidingView';
+
+export default BaseKeyboardAvoidingView;
diff --git a/src/components/KeyboardAvoidingView/index.ios.tsx b/src/components/KeyboardAvoidingView/index.ios.tsx
deleted file mode 100644
index 171210eab7ac..000000000000
--- a/src/components/KeyboardAvoidingView/index.ios.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * The KeyboardAvoidingView is only used on ios
- */
-import React from 'react';
-import {KeyboardAvoidingView as KeyboardAvoidingViewComponent} from 'react-native';
-import type {KeyboardAvoidingViewProps} from './types';
-
-function KeyboardAvoidingView(props: KeyboardAvoidingViewProps) {
-    // eslint-disable-next-line react/jsx-props-no-spreading
-    return <KeyboardAvoidingViewComponent {...props} />;
-}
-
-KeyboardAvoidingView.displayName = 'KeyboardAvoidingView';
-
-export default KeyboardAvoidingView;
diff --git a/src/components/KeyboardAvoidingView/index.tsx b/src/components/KeyboardAvoidingView/index.tsx
index 7e2c7b8159a9..da2627186ab7 100644
--- a/src/components/KeyboardAvoidingView/index.tsx
+++ b/src/components/KeyboardAvoidingView/index.tsx
@@ -1,15 +1,22 @@
-/*
- * The KeyboardAvoidingView stub implementation for web and other platforms where the keyboard is handled automatically.
- */
-import React from 'react';
-import {View} from 'react-native';
+import React, {useMemo} from 'react';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
+import BaseKeyboardAvoidingView from './BaseKeyboardAvoidingView';
 import type {KeyboardAvoidingViewProps} from './types';
 
-function KeyboardAvoidingView(props: KeyboardAvoidingViewProps) {
-    const {behavior, contentContainerStyle, enabled, keyboardVerticalOffset, ...rest} = props;
+function KeyboardAvoidingView({shouldOffsetBottomSafeAreaPadding = false, keyboardVerticalOffset: keyboardVerticalOffsetProp, ...restProps}: KeyboardAvoidingViewProps) {
+    const {paddingBottom} = useSafeAreaPaddings(true);
+
+    const keyboardVerticalOffset = useMemo(
+        () => (keyboardVerticalOffsetProp ?? 0) + (shouldOffsetBottomSafeAreaPadding ? -paddingBottom : 0),
+        [keyboardVerticalOffsetProp, paddingBottom, shouldOffsetBottomSafeAreaPadding],
+    );
+
     return (
-        // eslint-disable-next-line react/jsx-props-no-spreading
-        <View {...rest} />
+        <BaseKeyboardAvoidingView
+            // eslint-disable-next-line react/jsx-props-no-spreading
+            {...restProps}
+            keyboardVerticalOffset={keyboardVerticalOffset}
+        />
     );
 }
 
diff --git a/src/components/KeyboardAvoidingView/types.ts b/src/components/KeyboardAvoidingView/types.ts
index 2c1ef64ced8f..3e6ed4e9d304 100644
--- a/src/components/KeyboardAvoidingView/types.ts
+++ b/src/components/KeyboardAvoidingView/types.ts
@@ -1,4 +1,12 @@
-import type {KeyboardAvoidingViewProps} from 'react-native';
+import type {KeyboardAvoidingViewProps as RNKeyboardAvoidingViewProps} from 'react-native';
+
+type KeyboardAvoidingViewProps = RNKeyboardAvoidingViewProps & {
+    /**
+     * Whether to compensate for the bottom safe area padding.
+     * The KeyboardAvoidingView will use a negative keyboardVerticalOffset.
+     */
+    shouldOffsetBottomSafeAreaPadding?: boolean;
+};
 
 // eslint-disable-next-line import/prefer-default-export
 export type {KeyboardAvoidingViewProps};
diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx
index 5f56f81cb990..3605a368d467 100644
--- a/src/components/Modal/BaseModal.tsx
+++ b/src/components/Modal/BaseModal.tsx
@@ -5,6 +5,7 @@ import ReactNativeModal from 'react-native-modal';
 import type {ValueOf} from 'type-fest';
 import ColorSchemeWrapper from '@components/ColorSchemeWrapper';
 import FocusTrapForModal from '@components/FocusTrap/FocusTrapForModal';
+import NavigationBar from '@components/NavigationBar';
 import useKeyboardState from '@hooks/useKeyboardState';
 import usePrevious from '@hooks/usePrevious';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
@@ -76,6 +77,7 @@ function BaseModal(
         swipeThreshold = 150,
         swipeDirection,
         shouldPreventScrollOnFocus = false,
+        enableEdgeToEdgeBottomSafeAreaPadding = false,
     }: BaseModalProps,
     ref: React.ForwardedRef<View>,
 ) {
@@ -204,7 +206,7 @@ function BaseModal(
         paddingBottom: safeAreaPaddingBottom,
         paddingLeft: safeAreaPaddingLeft,
         paddingRight: safeAreaPaddingRight,
-    } = StyleUtils.getSafeAreaPadding(safeAreaInsets);
+    } = StyleUtils.getPlatformSafeAreaPadding(safeAreaInsets);
 
     const modalPaddingStyles = shouldUseModalPaddingStyle
         ? StyleUtils.getModalPaddingStyles({
@@ -214,7 +216,8 @@ function BaseModal(
               safeAreaPaddingRight,
               shouldAddBottomSafeAreaMargin,
               shouldAddTopSafeAreaMargin,
-              shouldAddBottomSafeAreaPadding: (!avoidKeyboard || !keyboardStateContextValue?.isKeyboardShown) && shouldAddBottomSafeAreaPadding,
+              // enableEdgeToEdgeBottomSafeAreaPadding is used as a temporary solution to disable safe area bottom spacing on modals, to allow edge-to-edge content
+              shouldAddBottomSafeAreaPadding: !enableEdgeToEdgeBottomSafeAreaPadding && (!avoidKeyboard || !keyboardStateContextValue?.isKeyboardShown) && shouldAddBottomSafeAreaPadding,
               shouldAddTopSafeAreaPadding,
               modalContainerStyleMarginTop: modalContainerStyle.marginTop,
               modalContainerStyleMarginBottom: modalContainerStyle.marginBottom,
@@ -302,6 +305,7 @@ function BaseModal(
                             </View>
                         </FocusTrapForModal>
                     </ModalContent>
+                    <NavigationBar />
                 </ModalComponent>
             </View>
         </ModalContext.Provider>
diff --git a/src/components/Modal/types.ts b/src/components/Modal/types.ts
index 0ed3c91c7a3c..ddc1e2bbd0e3 100644
--- a/src/components/Modal/types.ts
+++ b/src/components/Modal/types.ts
@@ -110,6 +110,13 @@ type BaseModalProps = Partial<ReactNativeModalProps> &
 
         /** Whether to prevent the focus trap from scrolling the element into view. */
         shouldPreventScrollOnFocus?: boolean;
+
+        /**
+         * Temporary flag to disable safe area bottom spacing in modals and to allow edge-to-edge content.
+         * Modals should not always apply bottom safe area padding, instead it should be applied to the scrollable/bottom-docked content directly.
+         * This flag can be removed, once all components/screens have switched to edge-to-edge safe area handling.
+         */
+        enableEdgeToEdgeBottomSafeAreaPadding?: boolean;
     };
 
 export default BaseModalProps;
diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx
index 780571d9b4a8..e8b23b164b9e 100644
--- a/src/components/MoneyRequestConfirmationListFooter.tsx
+++ b/src/components/MoneyRequestConfirmationListFooter.tsx
@@ -19,7 +19,15 @@ import type {ThumbnailAndImageURI} from '@libs/ReceiptUtils';
 import {getThumbnailAndImageURIs} from '@libs/ReceiptUtils';
 import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils';
 import {hasEnabledTags} from '@libs/TagsOptionsListUtils';
-import {getTagForDisplay, getTaxAmount, getTaxName, isAmountMissing, isCreatedMissing, shouldShowAttendees as shouldShowAttendeesTransactionUtils} from '@libs/TransactionUtils';
+import {
+    getTagForDisplay,
+    getTaxAmount,
+    getTaxName,
+    isAmountMissing,
+    isCreatedMissing,
+    isFetchingWaypointsFromServer,
+    shouldShowAttendees as shouldShowAttendeesTransactionUtils,
+} from '@libs/TransactionUtils';
 import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
 import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow';
 import CONST from '@src/CONST';
@@ -29,6 +37,7 @@ import ROUTES from '@src/ROUTES';
 import type * as OnyxTypes from '@src/types/onyx';
 import type {Attendee, Participant} from '@src/types/onyx/IOU';
 import type {Unit} from '@src/types/onyx/Policy';
+import {isEmptyObject} from '@src/types/utils/EmptyObject';
 import Badge from './Badge';
 import ConfirmedRoute from './ConfirmedRoute';
 import MentionReportContext from './HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext';
@@ -239,6 +248,11 @@ function MoneyRequestConfirmationListFooter({
     const isMultilevelTags = useMemo(() => isMultiLevelTagsPolicyUtils(policyTags), [policyTags]);
     const shouldShowAttendees = useMemo(() => shouldShowAttendeesTransactionUtils(iouType, policy), [iouType, policy]);
 
+    const hasPendingWaypoints = transaction && isFetchingWaypointsFromServer(transaction);
+    const hasErrors = !isEmptyObject(transaction?.errors) || !isEmptyObject(transaction?.errorFields?.route) || !isEmptyObject(transaction?.errorFields?.waypoints);
+    // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+    const shouldShowMap = isDistanceRequest && !!(hasErrors || hasPendingWaypoints || iouType !== CONST.IOU.TYPE.SPLIT || !isReadOnly);
+
     const senderWorkspace = useMemo(() => {
         const senderWorkspaceParticipant = selectedParticipants.find((participant) => participant.isSender);
         return allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${senderWorkspaceParticipant?.policyID}`];
@@ -773,7 +787,7 @@ function MoneyRequestConfirmationListFooter({
                     disabled={didConfirm}
                 />
             )}
-            {isDistanceRequest && (
+            {shouldShowMap && (
                 <View style={styles.confirmationListMapItem}>
                     <ConfirmedRoute transaction={transaction ?? ({} as OnyxTypes.Transaction)} />
                 </View>
@@ -818,7 +832,7 @@ function MoneyRequestConfirmationListFooter({
                     <View style={styles.dividerLine} />
                 </>
             )}
-            {!isDistanceRequest &&
+            {!shouldShowMap &&
                 // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
                 (receiptImage || receiptThumbnail
                     ? receiptThumbnailContent
diff --git a/src/components/Navigation/TopLevelBottomTabBar/index.tsx b/src/components/Navigation/TopLevelBottomTabBar/index.tsx
index ed0e65e23dbb..ecc713293093 100644
--- a/src/components/Navigation/TopLevelBottomTabBar/index.tsx
+++ b/src/components/Navigation/TopLevelBottomTabBar/index.tsx
@@ -4,7 +4,7 @@ import {InteractionManager, View} from 'react-native';
 import {FullScreenBlockingViewContext} from '@components/FullScreenBlockingViewContextProvider';
 import BottomTabBar from '@components/Navigation/BottomTabBar';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useThemeStyles from '@hooks/useThemeStyles';
 import type {PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types';
 import getIsBottomTabVisibleDirectly from './getIsBottomTabVisibleDirectly';
@@ -26,7 +26,7 @@ type TopLevelBottomTabBarProps = {
 function TopLevelBottomTabBar({state}: TopLevelBottomTabBarProps) {
     const styles = useThemeStyles();
     const {shouldUseNarrowLayout} = useResponsiveLayout();
-    const {paddingBottom} = useStyledSafeAreaInsets();
+    const {paddingBottom} = useSafeAreaPaddings();
     const [isAfterClosingTransition, setIsAfterClosingTransition] = useState(false);
     const cancelAfterInteractions = useRef<ReturnType<typeof InteractionManager.runAfterInteractions> | undefined>();
     const {isBlockingViewVisible} = useContext(FullScreenBlockingViewContext);
diff --git a/src/components/NavigationBar/index.android.tsx b/src/components/NavigationBar/index.android.tsx
new file mode 100644
index 000000000000..a7e8fe9ccd07
--- /dev/null
+++ b/src/components/NavigationBar/index.android.tsx
@@ -0,0 +1,22 @@
+import {useMemo} from 'react';
+import {View} from 'react-native';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
+import useStyleUtils from '@hooks/useStyleUtils';
+import useTheme from '@hooks/useTheme';
+import CONST from '@src/CONST';
+
+/** NavigationBar renders a semi-translucent background behind the three-button navigation bar on Android. */
+function NavigationBar() {
+    const theme = useTheme();
+    const StyleUtils = useStyleUtils();
+    const {insets} = useSafeAreaPaddings();
+
+    const navigationBarType = useMemo(() => StyleUtils.getNavigationBarType(insets), [StyleUtils, insets]);
+
+    const isSoftKeyNavigation = navigationBarType === CONST.NAVIGATION_BAR_TYPE.SOFT_KEYS;
+
+    return isSoftKeyNavigation ? <View style={[{position: 'absolute', bottom: 0, left: 0, right: 0, height: insets.bottom, backgroundColor: theme.navigationBarBackgroundColor}]} /> : null;
+}
+NavigationBar.displayName = 'NavigationBar';
+
+export default NavigationBar;
diff --git a/src/components/NavigationBar/index.tsx b/src/components/NavigationBar/index.tsx
new file mode 100644
index 000000000000..d50404780bcd
--- /dev/null
+++ b/src/components/NavigationBar/index.tsx
@@ -0,0 +1,6 @@
+function NavigationBar() {
+    return null;
+}
+NavigationBar.displayName = 'NavigationBar';
+
+export default NavigationBar;
diff --git a/src/components/OfflineIndicator.tsx b/src/components/OfflineIndicator.tsx
index 337e5dd850f7..5b6a28156dc2 100644
--- a/src/components/OfflineIndicator.tsx
+++ b/src/components/OfflineIndicator.tsx
@@ -1,6 +1,7 @@
-import React, {useMemo} from 'react';
+import React from 'react';
 import type {StyleProp, ViewStyle} from 'react-native';
 import {View} from 'react-native';
+import useBottomSafeSafeAreaPaddingStyle from '@hooks/useBottomSafeSafeAreaPaddingStyle';
 import useLocalize from '@hooks/useLocalize';
 import useNetwork from '@hooks/useNetwork';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
@@ -17,22 +18,22 @@ type OfflineIndicatorProps = {
 
     /** Optional styles for the container */
     style?: StyleProp<ViewStyle>;
+
+    /** Whether to add bottom safe area padding to the view. */
+    addBottomSafeAreaPadding?: boolean;
 };
 
-function OfflineIndicator({style, containerStyles}: OfflineIndicatorProps) {
+function OfflineIndicator({style, containerStyles, addBottomSafeAreaPadding = false}: OfflineIndicatorProps) {
     const theme = useTheme();
     const styles = useThemeStyles();
     const {translate} = useLocalize();
     const {isOffline} = useNetwork();
     const {shouldUseNarrowLayout} = useResponsiveLayout();
 
-    const computedStyles = useMemo((): StyleProp<ViewStyle> => {
-        if (containerStyles) {
-            return containerStyles;
-        }
-
-        return shouldUseNarrowLayout ? styles.offlineIndicatorMobile : styles.offlineIndicator;
-    }, [containerStyles, shouldUseNarrowLayout, styles.offlineIndicatorMobile, styles.offlineIndicator]);
+    const computedStyles = useBottomSafeSafeAreaPaddingStyle({
+        addBottomSafeAreaPadding,
+        style: containerStyles ?? (shouldUseNarrowLayout ? styles.offlineIndicatorMobile : styles.offlineIndicator),
+    });
 
     if (!isOffline) {
         return null;
diff --git a/src/components/PopoverWithoutOverlay/index.tsx b/src/components/PopoverWithoutOverlay/index.tsx
index 7d58ad6d22be..5dfaddcab2df 100644
--- a/src/components/PopoverWithoutOverlay/index.tsx
+++ b/src/components/PopoverWithoutOverlay/index.tsx
@@ -7,8 +7,8 @@ import useSafeAreaInsets from '@hooks/useSafeAreaInsets';
 import useStyleUtils from '@hooks/useStyleUtils';
 import useThemeStyles from '@hooks/useThemeStyles';
 import useWindowDimensions from '@hooks/useWindowDimensions';
+import {onModalDidClose, setCloseModal, willAlertModalBecomeVisible} from '@libs/actions/Modal';
 import variables from '@styles/variables';
-import * as Modal from '@userActions/Modal';
 import viewRef from '@src/types/utils/viewRef';
 import type PopoverWithoutOverlayProps from './types';
 
@@ -54,13 +54,13 @@ function PopoverWithoutOverlay(
                 close: onClose,
                 anchorRef,
             });
-            removeOnClose = Modal.setCloseModal(onClose);
+            removeOnClose = setCloseModal(onClose);
         } else {
             onModalHide();
             close(anchorRef);
-            Modal.onModalDidClose();
+            onModalDidClose();
         }
-        Modal.willAlertModalBecomeVisible(isVisible, true);
+        willAlertModalBecomeVisible(isVisible, true);
 
         return () => {
             if (!removeOnClose) {
@@ -77,7 +77,7 @@ function PopoverWithoutOverlay(
         paddingBottom: safeAreaPaddingBottom,
         paddingLeft: safeAreaPaddingLeft,
         paddingRight: safeAreaPaddingRight,
-    } = useMemo(() => StyleUtils.getSafeAreaPadding(insets), [StyleUtils, insets]);
+    } = useMemo(() => StyleUtils.getPlatformSafeAreaPadding(insets), [StyleUtils, insets]);
 
     const modalPaddingStyles = useMemo(
         () =>
diff --git a/src/components/Pressable/PressableWithFeedback.tsx b/src/components/Pressable/PressableWithFeedback.tsx
index 10e6ac7bbca6..9eeb0980d027 100644
--- a/src/components/Pressable/PressableWithFeedback.tsx
+++ b/src/components/Pressable/PressableWithFeedback.tsx
@@ -37,6 +37,12 @@ type PressableWithFeedbackProps = PressableProps & {
 
     /** The color of the underlay that will show through when the Pressable is active. */
     underlayColor?: Color;
+
+    /**
+     * Whether the button should have a background layer in the color of theme.appBG.
+     * This is needed for buttons that allow content to display under them.
+     */
+    shouldBlendOpacity?: boolean;
 };
 
 function PressableWithFeedback(
@@ -47,6 +53,7 @@ function PressableWithFeedback(
         pressDimmingValue = variables.pressDimValue,
         hoverDimmingValue = variables.hoverDimValue,
         dimAnimationDuration,
+        shouldBlendOpacity,
         ...rest
     }: PressableWithFeedbackProps,
     ref: PressableRef,
@@ -56,7 +63,7 @@ function PressableWithFeedback(
 
     return (
         <OpacityView
-            shouldDim={!!(!rest.disabled && (isPressed || isHovered))}
+            shouldDim={!shouldBlendOpacity && !!(!rest.disabled && (isPressed || isHovered))}
             dimmingValue={isPressed ? pressDimmingValue : hoverDimmingValue}
             dimAnimationDuration={dimAnimationDuration}
             style={wrapperStyle}
diff --git a/src/components/ProcessMoneyRequestHoldMenu.tsx b/src/components/ProcessMoneyRequestHoldMenu.tsx
index 6ace3f5cdd37..32e7087eb296 100644
--- a/src/components/ProcessMoneyRequestHoldMenu.tsx
+++ b/src/components/ProcessMoneyRequestHoldMenu.tsx
@@ -1,10 +1,11 @@
-import {useNavigation} from '@react-navigation/native';
-import React, {useEffect, useMemo} from 'react';
+import React, {useMemo} from 'react';
 import {View} from 'react-native';
+import useBeforeRemove from '@hooks/useBeforeRemove';
 import useLocalize from '@hooks/useLocalize';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
 import useThemeStyles from '@hooks/useThemeStyles';
 import variables from '@styles/variables';
+import CONST from '@src/CONST';
 import FeatureTrainingModal from './FeatureTrainingModal';
 import HoldMenuSectionList from './HoldMenuSectionList';
 import * as Illustrations from './Icon/Illustrations';
@@ -22,15 +23,9 @@ type ProcessMoneyRequestHoldMenuProps = {
 function ProcessMoneyRequestHoldMenu({onClose, onConfirm}: ProcessMoneyRequestHoldMenuProps) {
     const {translate} = useLocalize();
     const styles = useThemeStyles();
-    const navigation = useNavigation();
     const {onboardingIsMediumOrLargerScreenWidth} = useResponsiveLayout();
 
-    useEffect(() => {
-        const unsub = navigation.addListener('beforeRemove', () => {
-            onClose();
-        });
-        return unsub;
-    }, [navigation, onClose]);
+    useBeforeRemove(onClose);
 
     const title = useMemo(
         () => (
@@ -50,7 +45,7 @@ function ProcessMoneyRequestHoldMenu({onClose, onConfirm}: ProcessMoneyRequestHo
             image={Illustrations.HoldExpense}
             contentFitImage="cover"
             width={variables.holdEducationModalWidth}
-            illustrationAspectRatio={39 / 22}
+            illustrationAspectRatio={CONST.ILLUSTRATION_ASPECT_RATIO}
             contentInnerContainerStyles={styles.mb5}
             modalInnerContainerStyle={styles.pt0}
             illustrationOuterContainerStyle={styles.p0}
diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx
index dabd209bf26b..ca365949a005 100644
--- a/src/components/ProductTrainingContext/index.tsx
+++ b/src/components/ProductTrainingContext/index.tsx
@@ -7,6 +7,7 @@ import * as Expensicons from '@components/Icon/Expensicons';
 import Text from '@components/Text';
 import useLocalize from '@hooks/useLocalize';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
+import useSidePane from '@hooks/useSidePane';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
 import {parseFSAttributes} from '@libs/Fullstory';
@@ -164,6 +165,7 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou
     const context = useContext(ProductTrainingContext);
     const styles = useThemeStyles();
     const theme = useTheme();
+    const {shouldHideToolTip} = useSidePane();
     const {translate} = useLocalize();
 
     if (!context) {
@@ -253,8 +255,8 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou
     ]);
 
     const shouldShowProductTrainingTooltip = useMemo(() => {
-        return shouldShow && shouldRenderTooltip(tooltipName);
-    }, [shouldRenderTooltip, tooltipName, shouldShow]);
+        return shouldShow && shouldRenderTooltip(tooltipName) && !shouldHideToolTip;
+    }, [shouldRenderTooltip, tooltipName, shouldShow, shouldHideToolTip]);
 
     const hideProductTrainingTooltip = useCallback(() => {
         if (!shouldShowProductTrainingTooltip) {
diff --git a/src/components/SafeAreaConsumer/index.tsx b/src/components/SafeAreaConsumer/index.tsx
index 416021242225..16cf84cfd698 100644
--- a/src/components/SafeAreaConsumer/index.tsx
+++ b/src/components/SafeAreaConsumer/index.tsx
@@ -7,7 +7,6 @@ import type SafeAreaConsumerProps from './types';
 /**
  * This component is a light wrapper around the SafeAreaInsetsContext.Consumer. There are several places where we
  * may need not just the insets, but the computed styles so we save a few lines of code with this.
- * Note: if you're working within a <ScreenWrapper> please use `useStyledSafeAreaInsets` instead.
  */
 function SafeAreaConsumer({children}: SafeAreaConsumerProps) {
     const StyleUtils = useStyleUtils();
@@ -16,7 +15,7 @@ function SafeAreaConsumer({children}: SafeAreaConsumerProps) {
         <SafeAreaInsetsContext.Consumer>
             {(safeAreaInsets) => {
                 const insets = StyleUtils.getSafeAreaInsets(safeAreaInsets);
-                const {paddingTop, paddingBottom} = StyleUtils.getSafeAreaPadding(insets);
+                const {paddingTop, paddingBottom} = StyleUtils.getPlatformSafeAreaPadding(insets);
 
                 return children({
                     paddingTop,
diff --git a/src/components/ScreenWrapper.tsx b/src/components/ScreenWrapper.tsx
index 021b0e240aea..6ea4ca3951ae 100644
--- a/src/components/ScreenWrapper.tsx
+++ b/src/components/ScreenWrapper.tsx
@@ -7,10 +7,11 @@ import {Keyboard, PanResponder, View} from 'react-native';
 import {useOnyx} from 'react-native-onyx';
 import {PickerAvoidingView} from 'react-native-picker-select';
 import type {EdgeInsets} from 'react-native-safe-area-context';
+import useBottomSafeSafeAreaPaddingStyle from '@hooks/useBottomSafeSafeAreaPaddingStyle';
 import useEnvironment from '@hooks/useEnvironment';
 import useInitialDimensions from '@hooks/useInitialWindowDimensions';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useTackInputFocus from '@hooks/useTackInputFocus';
 import useThemeStyles from '@hooks/useThemeStyles';
 import useWindowDimensions from '@hooks/useWindowDimensions';
@@ -114,6 +115,19 @@ type ScreenWrapperProps = {
 
     /** Overrides the focus trap default settings */
     focusTrapSettings?: FocusTrapForScreenProps['focusTrapSettings'];
+
+    /**
+     * Temporary flag to disable safe area bottom spacing in the ScreenWrapper and to allow edge-to-edge content
+     * The ScreenWrapper should not always apply bottom safe area padding, instead it should be applied to the scrollable/bottom-docked content directly.
+     * This flag can be removed, once all components/screens have switched to edge-to-edge safe area handling.
+     */
+    enableEdgeToEdgeBottomSafeAreaPadding?: boolean;
+
+    /**
+     * Whether the KeyboardAvoidingView should compensate for the bottom safe area padding.
+     * The KeyboardAvoidingView will use a negative keyboardVerticalOffset.
+     */
+    shouldKeyboardOffsetBottomSafeAreaPadding?: boolean;
 };
 
 type ScreenWrapperStatusContextType = {
@@ -130,7 +144,7 @@ function ScreenWrapper(
         shouldEnableMinHeight = false,
         includePaddingTop = true,
         keyboardAvoidingViewBehavior = 'padding',
-        includeSafeAreaPaddingBottom = true,
+        includeSafeAreaPaddingBottom: includeSafeAreaPaddingBottomProp = true,
         shouldEnableKeyboardAvoidingView = true,
         shouldEnablePickerAvoiding = true,
         headerGapStyles,
@@ -147,6 +161,8 @@ function ScreenWrapper(
         shouldUseCachedViewportHeight = false,
         focusTrapSettings,
         bottomContent,
+        enableEdgeToEdgeBottomSafeAreaPadding = false,
+        shouldKeyboardOffsetBottomSafeAreaPadding = enableEdgeToEdgeBottomSafeAreaPadding,
     }: ScreenWrapperProps,
     ref: ForwardedRef<View>,
 ) {
@@ -168,6 +184,8 @@ function ScreenWrapper(
 
     const [isSingleNewDotEntry] = useOnyx(ONYXKEYS.IS_SINGLE_NEW_DOT_ENTRY);
 
+    const includeSafeAreaPaddingBottom = enableEdgeToEdgeBottomSafeAreaPadding ? false : includeSafeAreaPaddingBottomProp;
+
     // We need to use isSmallScreenWidth instead of shouldUseNarrowLayout for a case where we want to show the offline indicator only on small screens
     // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
     const {isSmallScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout();
@@ -269,25 +287,41 @@ function ScreenWrapper(
         // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
     }, []);
 
-    const {insets, paddingTop, paddingBottom, safeAreaPaddingBottomStyle, unmodifiedPaddings} = useStyledSafeAreaInsets();
-    const paddingTopStyle: StyleProp<ViewStyle> = {};
-    const paddingBottomStyle: StyleProp<ViewStyle> = {};
+    const {insets, paddingTop, paddingBottom, safeAreaPaddingBottomStyle, unmodifiedPaddings} = useSafeAreaPaddings(enableEdgeToEdgeBottomSafeAreaPadding);
 
     const isSafeAreaTopPaddingApplied = includePaddingTop;
-    if (includePaddingTop) {
-        paddingTopStyle.paddingTop = paddingTop;
-    }
-    if (includePaddingTop && ignoreInsetsConsumption) {
-        paddingTopStyle.paddingTop = unmodifiedPaddings.top;
-    }
-
-    // We always need the safe area padding bottom if we're showing the offline indicator since it is bottom-docked.
-    if (includeSafeAreaPaddingBottom) {
-        paddingBottomStyle.paddingBottom = paddingBottom;
-    }
-    if (includeSafeAreaPaddingBottom && ignoreInsetsConsumption) {
-        paddingBottomStyle.paddingBottom = unmodifiedPaddings.bottom;
-    }
+    const paddingTopStyle: StyleProp<ViewStyle> = useMemo(() => {
+        if (includePaddingTop && ignoreInsetsConsumption) {
+            return {paddingTop: unmodifiedPaddings.top};
+        }
+        if (includePaddingTop) {
+            return {paddingTop};
+        }
+        return {};
+    }, [ignoreInsetsConsumption, includePaddingTop, paddingTop, unmodifiedPaddings.top]);
+
+    const showBottomContent = enableEdgeToEdgeBottomSafeAreaPadding ? !!bottomContent : true;
+    const edgeToEdgeBottomContentStyle = useBottomSafeSafeAreaPaddingStyle({addBottomSafeAreaPadding: true});
+    const legacyBottomContentStyle: StyleProp<ViewStyle> = useMemo(() => {
+        const shouldUseUnmodifiedPaddings = includeSafeAreaPaddingBottom && ignoreInsetsConsumption;
+        if (shouldUseUnmodifiedPaddings) {
+            return {
+                paddingBottom: unmodifiedPaddings.bottom,
+            };
+        }
+
+        return {
+            // We always need the safe area padding bottom if we're showing the offline indicator since it is bottom-docked.
+            paddingBottom: includeSafeAreaPaddingBottom ? paddingBottom : undefined,
+        };
+    }, [ignoreInsetsConsumption, includeSafeAreaPaddingBottom, paddingBottom, unmodifiedPaddings.bottom]);
+    const bottomContentStyle = useMemo(
+        () => (enableEdgeToEdgeBottomSafeAreaPadding ? edgeToEdgeBottomContentStyle : legacyBottomContentStyle),
+        [enableEdgeToEdgeBottomSafeAreaPadding, edgeToEdgeBottomContentStyle, legacyBottomContentStyle],
+    );
+
+    const addMobileOfflineIndicatorBottomSafeAreaPadding = enableEdgeToEdgeBottomSafeAreaPadding ? !bottomContent : !includeSafeAreaPaddingBottom;
+    const addWidescreenOfflineIndicatorBottomSafeAreaPadding = enableEdgeToEdgeBottomSafeAreaPadding ? !bottomContent : true;
 
     const isAvoidingViewportScroll = useTackInputFocus(isFocused && shouldEnableMaxHeight && shouldAvoidScrollOnVirtualViewport && isMobileWebKit());
     const contextValue = useMemo(
@@ -314,6 +348,7 @@ function ScreenWrapper(
                         style={[styles.w100, styles.h100, !isBlurred ? {maxHeight} : undefined, isAvoidingViewportScroll ? [styles.overflowAuto, styles.overscrollBehaviorContain] : {}]}
                         behavior={keyboardAvoidingViewBehavior}
                         enabled={shouldEnableKeyboardAvoidingView}
+                        shouldOffsetBottomSafeAreaPadding={shouldKeyboardOffsetBottomSafeAreaPadding}
                     >
                         <PickerAvoidingView
                             style={isAvoidingViewportScroll ? [styles.h100, {marginTop: 1}] : styles.flex1}
@@ -336,11 +371,8 @@ function ScreenWrapper(
                                     <>
                                         <OfflineIndicator
                                             style={[offlineIndicatorStyle]}
-                                            containerStyles={
-                                                includeSafeAreaPaddingBottom
-                                                    ? [styles.offlineIndicatorMobile]
-                                                    : [styles.offlineIndicatorMobile, {paddingBottom: paddingBottom + styles.offlineIndicatorMobile.paddingBottom}]
-                                            }
+                                            containerStyles={styles.offlineIndicatorMobile}
+                                            addBottomSafeAreaPadding={addMobileOfflineIndicatorBottomSafeAreaPadding}
                                         />
                                         {/* Since import state is tightly coupled to the offline state, it is safe to display it when showing offline indicator */}
                                         <ImportedStateIndicator />
@@ -351,6 +383,7 @@ function ScreenWrapper(
                                         <OfflineIndicator
                                             containerStyles={[]}
                                             style={[styles.pl5, styles.offlineIndicatorRow, offlineIndicatorStyle]}
+                                            addBottomSafeAreaPadding={addWidescreenOfflineIndicatorBottomSafeAreaPadding}
                                         />
                                         {/* Since import state is tightly coupled to the offline state, it is safe to display it when showing offline indicator */}
                                         <ImportedStateIndicator />
@@ -360,7 +393,7 @@ function ScreenWrapper(
                         </PickerAvoidingView>
                     </KeyboardAvoidingView>
                 </View>
-                <View style={paddingBottomStyle}>{bottomContent}</View>
+                {showBottomContent && <View style={bottomContentStyle}>{bottomContent}</View>}
             </View>
         </FocusTrapForScreens>
     );
diff --git a/src/components/ScrollView.tsx b/src/components/ScrollView.tsx
index a61c592015ee..8a2a4519e0d4 100644
--- a/src/components/ScrollView.tsx
+++ b/src/components/ScrollView.tsx
@@ -2,9 +2,20 @@ import React from 'react';
 import type {ForwardedRef} from 'react';
 // eslint-disable-next-line no-restricted-imports
 import {ScrollView as RNScrollView} from 'react-native';
-import type {ScrollViewProps} from 'react-native';
+import type {ScrollViewProps as RNScrollViewProps} from 'react-native';
+import useBottomSafeSafeAreaPaddingStyle from '@hooks/useBottomSafeSafeAreaPaddingStyle';
+
+type ScrollViewProps = RNScrollViewProps & {
+    /** Whether to add bottom safe area padding to the content. */
+    addBottomSafeAreaPadding?: boolean;
+};
+
+function ScrollView(
+    {children, scrollIndicatorInsets, contentContainerStyle: contentContainerStyleProp, addBottomSafeAreaPadding = false, ...props}: ScrollViewProps,
+    ref: ForwardedRef<RNScrollView>,
+) {
+    const contentContainerStyle = useBottomSafeSafeAreaPaddingStyle({addBottomSafeAreaPadding, style: contentContainerStyleProp});
 
-function ScrollView({children, scrollIndicatorInsets, ...props}: ScrollViewProps, ref: ForwardedRef<RNScrollView>) {
     return (
         <RNScrollView
             ref={ref}
@@ -12,6 +23,7 @@ function ScrollView({children, scrollIndicatorInsets, ...props}: ScrollViewProps
             // on middle/left side of scrollview. scrollIndicatorInsets with right
             // to closest value to 0 fixes this issue, 0 (default) doesn't work
             // See: https://github.com/Expensify/App/issues/31441
+            contentContainerStyle={contentContainerStyle}
             scrollIndicatorInsets={scrollIndicatorInsets ?? {right: Number.MIN_VALUE}}
             // eslint-disable-next-line react/jsx-props-no-spreading
             {...props}
diff --git a/src/components/ScrollViewWithContext.tsx b/src/components/ScrollViewWithContext.tsx
index 1b9bb2c09f56..d88d736e6cec 100644
--- a/src/components/ScrollViewWithContext.tsx
+++ b/src/components/ScrollViewWithContext.tsx
@@ -1,7 +1,8 @@
 import type {ForwardedRef, ReactNode} from 'react';
 import React, {createContext, forwardRef, useMemo, useRef, useState} from 'react';
 // eslint-disable-next-line no-restricted-imports
-import type {NativeScrollEvent, NativeSyntheticEvent, ScrollView as RNScrollView, ScrollViewProps} from 'react-native';
+import type {NativeScrollEvent, NativeSyntheticEvent, ScrollView as RNScrollView} from 'react-native';
+import type {ScrollViewProps} from './ScrollView';
 import ScrollView from './ScrollView';
 
 const MIN_SMOOTH_SCROLL_EVENT_THROTTLE = 16;
diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx
index ea8d923d9e8e..9407c59718bd 100644
--- a/src/components/Search/SearchAutocompleteList.tsx
+++ b/src/components/Search/SearchAutocompleteList.tsx
@@ -156,6 +156,7 @@ function SearchAutocompleteList(
     const [isInitialRender, setIsInitialRender] = useState(true);
 
     const typeAutocompleteList = Object.values(CONST.SEARCH.DATA_TYPES);
+    const groupByAutocompleteList = Object.values(CONST.SEARCH.GROUP_BY);
     const statusAutocompleteList = Object.values({...CONST.SEARCH.STATUS.EXPENSE, ...CONST.SEARCH.STATUS.INVOICE, ...CONST.SEARCH.STATUS.CHAT, ...CONST.SEARCH.STATUS.TRIP});
     const expenseTypes = Object.values(CONST.SEARCH.TRANSACTION_TYPE);
 
@@ -337,6 +338,12 @@ function SearchAutocompleteList(
 
                 return filteredTypes.map((type) => ({filterKey: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.TYPE, text: type}));
             }
+            case CONST.SEARCH.SYNTAX_ROOT_KEYS.GROUP_BY: {
+                const filteredGroupBy = groupByAutocompleteList.filter(
+                    (groupByValue) => groupByValue.toLowerCase().includes(autocompleteValue.toLowerCase()) && !alreadyAutocompletedKeys.includes(groupByValue.toLowerCase()),
+                );
+                return filteredGroupBy.map((groupByValue) => ({filterKey: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.GROUP_BY, text: groupByValue}));
+            }
             case CONST.SEARCH.SYNTAX_ROOT_KEYS.STATUS: {
                 const filteredStatuses = statusAutocompleteList
                     .filter((status) => status.includes(autocompleteValue.toLowerCase()) && !alreadyAutocompletedKeys.includes(status))
@@ -405,6 +412,7 @@ function SearchAutocompleteList(
         workspaceCardFeeds,
         cardAutocompleteList,
         allCards,
+        groupByAutocompleteList,
     ]);
 
     const sortedRecentSearches = useMemo(() => {
diff --git a/src/components/Search/SearchPageHeader/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader/SearchPageHeader.tsx
index 8197083b44c0..09f03326c555 100644
--- a/src/components/Search/SearchPageHeader/SearchPageHeader.tsx
+++ b/src/components/Search/SearchPageHeader/SearchPageHeader.tsx
@@ -46,12 +46,11 @@ type SearchPageHeaderProps = {
     searchRouterListVisible?: boolean;
     hideSearchRouterList?: () => void;
     onSearchRouterFocus?: () => void;
-    shouldGroupByReports?: boolean;
 };
 
 type SearchHeaderOptionValue = DeepValueOf<typeof CONST.SEARCH.BULK_ACTION_TYPES> | undefined;
 
-function SearchPageHeader({queryJSON, searchName, searchRouterListVisible, hideSearchRouterList, onSearchRouterFocus, shouldGroupByReports}: SearchPageHeaderProps) {
+function SearchPageHeader({queryJSON, searchName, searchRouterListVisible, hideSearchRouterList, onSearchRouterFocus}: SearchPageHeaderProps) {
     const {translate} = useLocalize();
     const theme = useTheme();
     const styles = useThemeStyles();
@@ -433,7 +432,6 @@ function SearchPageHeader({queryJSON, searchName, searchRouterListVisible, hideS
                 searchName={searchName}
                 hideSearchRouterList={hideSearchRouterList}
                 inputRightComponent={InputRightComponent}
-                shouldGroupByReports={shouldGroupByReports}
             />
             <ConfirmModal
                 isVisible={isDeleteExpensesConfirmModalVisible}
diff --git a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx
index 2a1fe41ce5cd..35fd8c2d30ef 100644
--- a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx
+++ b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx
@@ -35,6 +35,7 @@ import variables from '@styles/variables';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
+import KeyboardUtils from '@src/utils/keyboard';
 import SearchTypeMenuPopover from './SearchTypeMenuPopover';
 
 // When counting absolute positioning, we need to account for borders
@@ -47,18 +48,9 @@ type SearchPageHeaderInputProps = {
     onSearchRouterFocus?: () => void;
     searchName?: string;
     inputRightComponent: React.ReactNode;
-    shouldGroupByReports?: boolean;
 };
 
-function SearchPageHeaderInput({
-    queryJSON,
-    searchRouterListVisible,
-    hideSearchRouterList,
-    onSearchRouterFocus,
-    searchName,
-    inputRightComponent,
-    shouldGroupByReports,
-}: SearchPageHeaderInputProps) {
+function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRouterList, onSearchRouterFocus, searchName, inputRightComponent}: SearchPageHeaderInputProps) {
     const {translate} = useLocalize();
     const [showPopupButton, setShowPopupButton] = useState(true);
     const styles = useThemeStyles();
@@ -252,7 +244,7 @@ function SearchPageHeaderInput({
                                 onSearchQueryChange={onSearchQueryChange}
                                 isFullWidth
                                 onSubmit={() => {
-                                    submitSearch(textInputValue);
+                                    KeyboardUtils.dismiss().then(() => submitSearch(textInputValue));
                                 }}
                                 autoFocus={false}
                                 onFocus={onFocus}
@@ -271,7 +263,6 @@ function SearchPageHeaderInput({
                             >
                                 <SearchTypeMenuPopover
                                     queryJSON={queryJSON}
-                                    shouldGroupByReports={shouldGroupByReports}
                                     searchName={searchName}
                                 />
                             </Animated.View>
diff --git a/src/components/Search/SearchPageHeader/SearchTypeMenuPopover.tsx b/src/components/Search/SearchPageHeader/SearchTypeMenuPopover.tsx
index 1f3f49886e71..8eac3505f1af 100644
--- a/src/components/Search/SearchPageHeader/SearchTypeMenuPopover.tsx
+++ b/src/components/Search/SearchPageHeader/SearchTypeMenuPopover.tsx
@@ -10,8 +10,8 @@ import type {SearchQueryJSON} from '@components/Search/types';
 import ThreeDotsMenu from '@components/ThreeDotsMenu';
 import useDeleteSavedSearch from '@hooks/useDeleteSavedSearch';
 import useLocalize from '@hooks/useLocalize';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useSingleExecution from '@hooks/useSingleExecution';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
 import useWindowDimensions from '@hooks/useWindowDimensions';
@@ -39,16 +39,15 @@ type SavedSearchMenuItem = MenuItemWithLink & {
 type SearchTypeMenuNarrowProps = {
     queryJSON: SearchQueryJSON;
     searchName?: string;
-    shouldGroupByReports?: boolean;
 };
 
-function SearchTypeMenuPopover({queryJSON, searchName, shouldGroupByReports}: SearchTypeMenuNarrowProps) {
+function SearchTypeMenuPopover({queryJSON, searchName}: SearchTypeMenuNarrowProps) {
     const theme = useTheme();
     const styles = useThemeStyles();
     const {singleExecution} = useSingleExecution();
     const {windowHeight} = useWindowDimensions();
     const {translate} = useLocalize();
-    const {hash, policyID} = queryJSON;
+    const {hash, policyID, groupBy} = queryJSON;
     const {showDeleteModal, DeleteConfirmModal} = useDeleteSavedSearch();
     const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
     const [session] = useOnyx(ONYXKEYS.SESSION);
@@ -58,7 +57,8 @@ function SearchTypeMenuPopover({queryJSON, searchName, shouldGroupByReports}: Se
     const [userCardList] = useOnyx(ONYXKEYS.CARD_LIST);
     const [workspaceCardFeeds] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST);
     const allCards = useMemo(() => mergeCardListWithWorkspaceFeeds(workspaceCardFeeds ?? CONST.EMPTY_OBJECT, userCardList), [userCardList, workspaceCardFeeds]);
-    const {unmodifiedPaddings} = useStyledSafeAreaInsets();
+    const {unmodifiedPaddings} = useSafeAreaPaddings();
+    const shouldGroupByReports = groupBy === CONST.SEARCH.GROUP_BY.REPORTS;
     const cardFeedNamesWithType = useMemo(() => {
         return getCardFeedNamesWithType({workspaceCardFeeds, userCardList, translate});
     }, [translate, workspaceCardFeeds, userCardList]);
diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx
index 24bdb14e03eb..3fbf4d083147 100644
--- a/src/components/Search/index.tsx
+++ b/src/components/Search/index.tsx
@@ -52,7 +52,6 @@ type SearchProps = {
     contentContainerStyle?: StyleProp<ViewStyle>;
     isSearchScreenFocused?: boolean;
     onContentSizeChange?: (w: number, h: number) => void;
-    shouldGroupByReports?: boolean;
 };
 
 const transactionItemMobileHeight = 100;
@@ -127,7 +126,7 @@ function prepareTransactionsList(item: TransactionListItemType, selectedTransact
     };
 }
 
-function Search({queryJSON, onSearchListScroll, isSearchScreenFocused, contentContainerStyle, onContentSizeChange, shouldGroupByReports}: SearchProps) {
+function Search({queryJSON, onSearchListScroll, isSearchScreenFocused, contentContainerStyle, onContentSizeChange}: SearchProps) {
     const {isOffline} = useNetwork();
     const {shouldUseNarrowLayout} = useResponsiveLayout();
     const styles = useThemeStyles();
@@ -150,13 +149,14 @@ function Search({queryJSON, onSearchListScroll, isSearchScreenFocused, contentCo
     const {selectionMode} = useMobileSelectionMode();
     const [offset, setOffset] = useState(0);
 
-    const {type, status, sortBy, sortOrder, hash} = queryJSON;
+    const {type, status, sortBy, sortOrder, hash, groupBy} = queryJSON;
 
     const [currentSearchResults] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`);
     const [transactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION);
     const previousTransactions = usePrevious(transactions);
     const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS);
     const previousReportActions = usePrevious(reportActions);
+    const shouldGroupByReports = groupBy === CONST.SEARCH.GROUP_BY.REPORTS;
 
     useEffect(() => {
         if (!currentSearchResults?.search?.type) {
@@ -267,7 +267,7 @@ function Search({queryJSON, onSearchListScroll, isSearchScreenFocused, contentCo
             return [];
         }
         return getSections(type, status, searchResults.data, searchResults.search, shouldGroupByReports);
-    }, [searchResults, status, type, shouldGroupByReports]);
+    }, [searchResults, type, status, shouldGroupByReports]);
 
     useEffect(() => {
         /** We only want to display the skeleton for the status filters the first time we load them for a specific data type */
diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts
index 3dc408cc27c3..d5be6bb83cf4 100644
--- a/src/components/Search/types.ts
+++ b/src/components/Search/types.ts
@@ -58,6 +58,7 @@ type InvoiceSearchStatus = ValueOf<typeof CONST.SEARCH.STATUS.INVOICE>;
 type TripSearchStatus = ValueOf<typeof CONST.SEARCH.STATUS.TRIP>;
 type ChatSearchStatus = ValueOf<typeof CONST.SEARCH.STATUS.CHAT>;
 type SearchStatus = ExpenseSearchStatus | InvoiceSearchStatus | TripSearchStatus | ChatSearchStatus | Array<ExpenseSearchStatus | InvoiceSearchStatus | TripSearchStatus | ChatSearchStatus>;
+type SearchGroupBy = ValueOf<typeof CONST.SEARCH.GROUP_BY>;
 
 type SearchContext = {
     currentSearchHash: number;
@@ -96,7 +97,8 @@ type SearchFilterKey =
     | ValueOf<typeof CONST.SEARCH.SYNTAX_FILTER_KEYS>
     | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.TYPE
     | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.STATUS
-    | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.POLICY_ID;
+    | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.POLICY_ID
+    | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.GROUP_BY;
 
 type UserFriendlyKey = ValueOf<typeof CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS>;
 
@@ -112,6 +114,7 @@ type SearchQueryAST = {
     status: SearchStatus;
     sortBy: SearchColumnType;
     sortOrder: SortOrder;
+    groupBy?: SearchGroupBy;
     filters: ASTNode;
     policyID?: string;
 };
diff --git a/src/components/SectionList/BaseSectionList.tsx b/src/components/SectionList/BaseSectionList.tsx
new file mode 100644
index 000000000000..dc40211030b4
--- /dev/null
+++ b/src/components/SectionList/BaseSectionList.tsx
@@ -0,0 +1,24 @@
+import React, {forwardRef} from 'react';
+import useBottomSafeSafeAreaPaddingStyle from '@hooks/useBottomSafeSafeAreaPaddingStyle';
+import AnimatedSectionList from './AnimatedSectionList';
+import type {SectionListProps, SectionListRef} from './types';
+
+function BaseSectionList<ItemT, SectionT>(
+    {addBottomSafeAreaPadding = false, contentContainerStyle: contentContainerStyleProp, ...restProps}: SectionListProps<ItemT, SectionT>,
+    ref: SectionListRef<ItemT, SectionT>,
+) {
+    const contentContainerStyle = useBottomSafeSafeAreaPaddingStyle({addBottomSafeAreaPadding, style: contentContainerStyleProp});
+
+    return (
+        <AnimatedSectionList
+            contentContainerStyle={contentContainerStyle}
+            // eslint-disable-next-line react/jsx-props-no-spreading
+            {...restProps}
+            ref={ref}
+        />
+    );
+}
+
+BaseSectionList.displayName = 'BaseSectionList';
+
+export default forwardRef(BaseSectionList);
diff --git a/src/components/SectionList/index.android.tsx b/src/components/SectionList/index.android.tsx
index 157e546b3ea9..d9877fd5afca 100644
--- a/src/components/SectionList/index.android.tsx
+++ b/src/components/SectionList/index.android.tsx
@@ -1,10 +1,10 @@
 import React, {forwardRef} from 'react';
-import AnimatedSectionList from './AnimatedSectionList';
+import BaseSectionList from './BaseSectionList';
 import type {SectionListProps, SectionListRef} from './types';
 
 function SectionListWithRef<ItemT, SectionT>(props: SectionListProps<ItemT, SectionT>, ref: SectionListRef<ItemT, SectionT>) {
     return (
-        <AnimatedSectionList
+        <BaseSectionList
             // eslint-disable-next-line react/jsx-props-no-spreading
             {...props}
             ref={ref}
diff --git a/src/components/SectionList/index.tsx b/src/components/SectionList/index.tsx
index b478d3c2bdf2..746eff3b6c7c 100644
--- a/src/components/SectionList/index.tsx
+++ b/src/components/SectionList/index.tsx
@@ -1,10 +1,10 @@
 import React, {forwardRef} from 'react';
-import AnimatedSectionList from './AnimatedSectionList';
+import BaseSectionList from './BaseSectionList';
 import type {SectionListProps, SectionListRef} from './types';
 
 function SectionList<ItemT, SectionT>(props: SectionListProps<ItemT, SectionT>, ref: SectionListRef<ItemT, SectionT>) {
     return (
-        <AnimatedSectionList
+        <BaseSectionList
             // eslint-disable-next-line react/jsx-props-no-spreading
             {...props}
             ref={ref}
diff --git a/src/components/SectionList/types.ts b/src/components/SectionList/types.ts
index 9aef028559e6..cd9a6d5bf2af 100644
--- a/src/components/SectionList/types.ts
+++ b/src/components/SectionList/types.ts
@@ -1,7 +1,11 @@
 import type {ForwardedRef} from 'react';
-import type {SectionList, SectionListProps as SectionListPropsRN} from 'react-native';
+import type {SectionListProps as RNSectionListProps, SectionList} from 'react-native';
+
+type SectionListProps<ItemT, SectionT> = RNSectionListProps<ItemT, SectionT> & {
+    /** Whether to add bottom safe area padding to the content. */
+    addBottomSafeAreaPadding?: boolean;
+};
 
-type SectionListProps<ItemT, SectionT> = SectionListPropsRN<ItemT, SectionT>;
 type SectionListRef<ItemT, SectionT> = ForwardedRef<SectionList<ItemT, SectionT>>;
 
 export type {SectionListProps, SectionListRef};
diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx
index 67cf5e5a3841..c1e3818a12e2 100644
--- a/src/components/SelectionList/BaseSelectionList.tsx
+++ b/src/components/SelectionList/BaseSelectionList.tsx
@@ -16,13 +16,14 @@ import Text from '@components/Text';
 import TextInput from '@components/TextInput';
 import useActiveElementRole from '@hooks/useActiveElementRole';
 import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager';
+import useBottomSafeSafeAreaPaddingStyle from '@hooks/useBottomSafeSafeAreaPaddingStyle';
 import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
 import useKeyboardState from '@hooks/useKeyboardState';
 import useLocalize from '@hooks/useLocalize';
 import usePrevious from '@hooks/usePrevious';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useScrollEnabled from '@hooks/useScrollEnabled';
 import useSingleExecution from '@hooks/useSingleExecution';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
 import useThemeStyles from '@hooks/useThemeStyles';
 import getSectionsWithIndexOffset from '@libs/getSectionsWithIndexOffset';
 import {addKeyDownPressListener, removeKeyDownPressListener} from '@libs/KeyboardShortcut/KeyDownPressListener';
@@ -33,7 +34,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';
 import arraysEqual from '@src/utils/arraysEqual';
 import BaseSelectionListItemRenderer from './BaseSelectionListItemRenderer';
 import FocusAwareCellRendererComponent from './FocusAwareCellRendererComponent';
-import type {BaseSelectionListProps, ButtonOrCheckBoxRoles, FlattenedSectionsReturn, ListItem, SectionListDataType, SectionWithIndexOffset, SelectionListHandle} from './types';
+import type {ButtonOrCheckBoxRoles, FlattenedSectionsReturn, ListItem, SectionListDataType, SectionWithIndexOffset, SelectionListHandle, SelectionListProps} from './types';
 
 const getDefaultItemHeight = () => variables.optionRowHeight;
 
@@ -115,7 +116,7 @@ function BaseSelectionList<TItem extends ListItem>(
         listItemWrapperStyle,
         shouldIgnoreFocus = false,
         scrollEventThrottle,
-        contentContainerStyle,
+        contentContainerStyle: contentContainerStyleProp,
         shouldHighlightSelectedItem = false,
         shouldKeepFocusedItemAtTopOfViewableArea = false,
         shouldDebounceScrolling = false,
@@ -127,7 +128,8 @@ function BaseSelectionList<TItem extends ListItem>(
         listItemTitleContainerStyles,
         isScreenFocused = false,
         shouldSubscribeToArrowKeyEvents = true,
-    }: BaseSelectionListProps<TItem>,
+        addBottomSafeAreaPadding = false,
+    }: SelectionListProps<TItem>,
     ref: ForwardedRef<SelectionListHandle>,
 ) {
     const styles = useThemeStyles();
@@ -823,11 +825,24 @@ function BaseSelectionList<TItem extends ListItem>(
             </View>
         );
 
-    const {safeAreaPaddingBottomStyle} = useStyledSafeAreaInsets();
+    const {safeAreaPaddingBottomStyle} = useSafeAreaPaddings();
+    const paddingBottomStyle = useMemo(
+        () => (!isKeyboardShown || !!footerContent) && includeSafeAreaPaddingBottom && safeAreaPaddingBottomStyle,
+        [footerContent, includeSafeAreaPaddingBottom, isKeyboardShown, safeAreaPaddingBottomStyle],
+    );
+
+    // If the default confirm button is visible and it is bottom-sticky,
+    // we need to add additional padding bottom to the content container.
+    const contentContainerStyle = useBottomSafeSafeAreaPaddingStyle({
+        addBottomSafeAreaPadding: false, // Bottom safe area padding is already applied in the SectionList
+        style: contentContainerStyleProp,
+    });
+
+    const shouldHideContentBottomSafeAreaPadding = showConfirmButton || !!footerContent;
 
     // TODO: test _every_ component that uses SelectionList
     return (
-        <View style={[styles.flex1, (!isKeyboardShown || !!footerContent) && includeSafeAreaPaddingBottom && safeAreaPaddingBottomStyle, containerStyle]}>
+        <View style={[styles.flex1, !addBottomSafeAreaPadding && paddingBottomStyle, containerStyle]}>
             {shouldShowTextInput && !shouldShowTextInputAfterHeader && renderInput()}
             {/* If we are loading new options we will avoid showing any header message. This is mostly because one of the header messages says there are no options. */}
             {/* This is misleading because we might be in the process of loading fresh options from the server. */}
@@ -884,6 +899,7 @@ function BaseSelectionList<TItem extends ListItem>(
                         onEndReached={onEndReached}
                         onEndReachedThreshold={onEndReachedThreshold}
                         scrollEventThrottle={scrollEventThrottle}
+                        addBottomSafeAreaPadding={!shouldHideContentBottomSafeAreaPadding && addBottomSafeAreaPadding}
                         contentContainerStyle={contentContainerStyle}
                         CellRendererComponent={shouldPreventActiveCellVirtualization ? FocusAwareCellRendererComponent : undefined}
                     />
@@ -891,7 +907,10 @@ function BaseSelectionList<TItem extends ListItem>(
                 </>
             )}
             {showConfirmButton && (
-                <FixedFooter style={[styles.mtAuto]}>
+                <FixedFooter
+                    style={styles.mtAuto}
+                    addBottomSafeAreaPadding={addBottomSafeAreaPadding}
+                >
                     <Button
                         success={!shouldUseDefaultTheme}
                         large
@@ -904,7 +923,14 @@ function BaseSelectionList<TItem extends ListItem>(
                     />
                 </FixedFooter>
             )}
-            {!!footerContent && <FixedFooter style={[styles.mtAuto]}>{footerContent}</FixedFooter>}
+            {!!footerContent && (
+                <FixedFooter
+                    style={styles.mtAuto}
+                    addBottomSafeAreaPadding={addBottomSafeAreaPadding}
+                >
+                    {footerContent}
+                </FixedFooter>
+            )}
         </View>
     );
 }
diff --git a/src/components/SelectionList/BaseSelectionListItemRenderer.tsx b/src/components/SelectionList/BaseSelectionListItemRenderer.tsx
index 987a72e025c1..9f3623f75f43 100644
--- a/src/components/SelectionList/BaseSelectionListItemRenderer.tsx
+++ b/src/components/SelectionList/BaseSelectionListItemRenderer.tsx
@@ -4,10 +4,10 @@ import type useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager';
 import type useSingleExecution from '@hooks/useSingleExecution';
 import {isMobileChrome} from '@libs/Browser';
 import {isReportListItemType} from '@libs/SearchUIUtils';
-import type {BaseListItemProps, BaseSelectionListProps, ExtendedTargetedEvent, ListItem} from './types';
+import type {BaseListItemProps, ExtendedTargetedEvent, ListItem, SelectionListProps} from './types';
 
 type BaseSelectionListItemRendererProps<TItem extends ListItem> = Omit<BaseListItemProps<TItem>, 'onSelectRow'> &
-    Pick<BaseSelectionListProps<TItem>, 'ListItem' | 'shouldHighlightSelectedItem' | 'shouldIgnoreFocus' | 'shouldSingleExecuteRowSelect'> & {
+    Pick<SelectionListProps<TItem>, 'ListItem' | 'shouldHighlightSelectedItem' | 'shouldIgnoreFocus' | 'shouldSingleExecuteRowSelect'> & {
         index: number;
         selectRow: (item: TItem, indexToFocus?: number) => void;
         setFocusedIndex: ReturnType<typeof useArrowKeyFocusManager>[1];
diff --git a/src/components/SelectionList/index.native.tsx b/src/components/SelectionList/index.native.tsx
index baccdf7c6024..4207f65c639c 100644
--- a/src/components/SelectionList/index.native.tsx
+++ b/src/components/SelectionList/index.native.tsx
@@ -2,9 +2,9 @@ import React, {forwardRef} from 'react';
 import type {ForwardedRef} from 'react';
 import {Keyboard} from 'react-native';
 import BaseSelectionList from './BaseSelectionList';
-import type {BaseSelectionListProps, ListItem, SelectionListHandle} from './types';
+import type {ListItem, SelectionListHandle, SelectionListProps} from './types';
 
-function SelectionList<TItem extends ListItem>(props: BaseSelectionListProps<TItem>, ref: ForwardedRef<SelectionListHandle>) {
+function SelectionList<TItem extends ListItem>(props: SelectionListProps<TItem>, ref: ForwardedRef<SelectionListHandle>) {
     return (
         <BaseSelectionList
             // eslint-disable-next-line react/jsx-props-no-spreading
diff --git a/src/components/SelectionList/index.tsx b/src/components/SelectionList/index.tsx
index ecb63fc31e74..f5ee4d4c4e2d 100644
--- a/src/components/SelectionList/index.tsx
+++ b/src/components/SelectionList/index.tsx
@@ -1,20 +1,20 @@
 import React, {forwardRef, useEffect, useState} from 'react';
 import type {ForwardedRef} from 'react';
 import {Keyboard} from 'react-native';
-import * as Browser from '@libs/Browser';
-import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import {isMobileChrome} from '@libs/Browser';
+import {canUseTouchScreen} from '@libs/DeviceCapabilities';
 import CONST from '@src/CONST';
 import BaseSelectionList from './BaseSelectionList';
-import type {BaseSelectionListProps, ListItem, SelectionListHandle} from './types';
+import type {ListItem, SelectionListHandle, SelectionListProps} from './types';
 
-function SelectionList<TItem extends ListItem>({onScroll, ...props}: BaseSelectionListProps<TItem>, ref: ForwardedRef<SelectionListHandle>) {
+function SelectionList<TItem extends ListItem>({onScroll, ...props}: SelectionListProps<TItem>, ref: ForwardedRef<SelectionListHandle>) {
     const [isScreenTouched, setIsScreenTouched] = useState(false);
 
     const touchStart = () => setIsScreenTouched(true);
     const touchEnd = () => setIsScreenTouched(false);
 
     useEffect(() => {
-        if (!DeviceCapabilities.canUseTouchScreen()) {
+        if (!canUseTouchScreen()) {
             return;
         }
 
@@ -73,7 +73,7 @@ function SelectionList<TItem extends ListItem>({onScroll, ...props}: BaseSelecti
             onScroll={onScroll ?? defaultOnScroll}
             // Ignore the focus if it's caused by a touch event on mobile chrome.
             // For example, a long press will trigger a focus event on mobile chrome.
-            shouldIgnoreFocus={Browser.isMobileChrome() && isScreenTouched}
+            shouldIgnoreFocus={isMobileChrome() && isScreenTouched}
             shouldDebounceScrolling={shouldDebounceScrolling}
         />
     );
diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts
index 3eb63ae97242..c409c6a61d38 100644
--- a/src/components/SelectionList/types.ts
+++ b/src/components/SelectionList/types.ts
@@ -394,7 +394,7 @@ type SkeletonViewProps = {
     shouldAnimate: boolean;
 };
 
-type BaseSelectionListProps<TItem extends ListItem> = Partial<ChildrenProps> & {
+type SelectionListProps<TItem extends ListItem> = Partial<ChildrenProps> & {
     /** Sections for the section list */
     sections: Array<SectionListDataType<TItem>> | typeof CONST.EMPTY_ARRAY;
 
@@ -668,6 +668,9 @@ type BaseSelectionListProps<TItem extends ListItem> = Partial<ChildrenProps> & {
 
     /** Whether the screen is focused or not. (useIsFocused state does not work in tab screens, e.g. SearchPageBottomTab) */
     isScreenFocused?: boolean;
+
+    /** Whether to add bottom safe area padding to the content. */
+    addBottomSafeAreaPadding?: boolean;
 } & TRightHandSideComponent<TItem>;
 
 type SelectionListHandle = {
@@ -704,7 +707,7 @@ type SectionListDataType<TItem extends ListItem> = ExtendedSectionListData<TItem
 
 export type {
     BaseListItemProps,
-    BaseSelectionListProps,
+    SelectionListProps,
     ButtonOrCheckBoxRoles,
     CommonListItemProps,
     ExtendedTargetedEvent,
diff --git a/src/components/SelectionListWithModal/index.tsx b/src/components/SelectionListWithModal/index.tsx
index 412fc063a0af..647113f32617 100644
--- a/src/components/SelectionListWithModal/index.tsx
+++ b/src/components/SelectionListWithModal/index.tsx
@@ -5,14 +5,14 @@ import * as Expensicons from '@components/Icon/Expensicons';
 import MenuItem from '@components/MenuItem';
 import Modal from '@components/Modal';
 import SelectionList from '@components/SelectionList';
-import type {BaseSelectionListProps, ListItem, SelectionListHandle} from '@components/SelectionList/types';
+import type {ListItem, SelectionListHandle, SelectionListProps} from '@components/SelectionList/types';
 import useLocalize from '@hooks/useLocalize';
 import useMobileSelectionMode from '@hooks/useMobileSelectionMode';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
 import {turnOffMobileSelectionMode, turnOnMobileSelectionMode} from '@libs/actions/MobileSelectionMode';
 import CONST from '@src/CONST';
 
-type SelectionListWithModalProps<TItem extends ListItem> = BaseSelectionListProps<TItem> & {
+type SelectionListWithModalProps<TItem extends ListItem> = SelectionListProps<TItem> & {
     turnOnSelectionModeOnLongPress?: boolean;
     onTurnOnSelectionMode?: (item: TItem | null) => void;
     isSelected?: (item: TItem) => boolean;
diff --git a/src/components/SidePane/Help/HelpContent.tsx b/src/components/SidePane/Help/HelpContent.tsx
new file mode 100644
index 000000000000..9080dd84cc32
--- /dev/null
+++ b/src/components/SidePane/Help/HelpContent.tsx
@@ -0,0 +1,61 @@
+import {findFocusedRoute} from '@react-navigation/native';
+import React, {useEffect, useRef} from 'react';
+import HeaderGap from '@components/HeaderGap';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScrollView from '@components/ScrollView';
+import getHelpContent from '@components/SidePane/getHelpContent';
+import useEnvironment from '@hooks/useEnvironment';
+import useLocalize from '@hooks/useLocalize';
+import useResponsiveLayout from '@hooks/useResponsiveLayout';
+import useRootNavigationState from '@hooks/useRootNavigationState';
+import useSidePane from '@hooks/useSidePane';
+import useThemeStyles from '@hooks/useThemeStyles';
+import Navigation from '@libs/Navigation/Navigation';
+import {substituteRouteParameters} from '@libs/SidePaneUtils';
+
+function HelpContent() {
+    const styles = useThemeStyles();
+    const {translate} = useLocalize();
+    const {isProduction} = useEnvironment();
+    const {isExtraLargeScreenWidth} = useResponsiveLayout();
+    const {closeSidePane} = useSidePane();
+    const route = useRootNavigationState((state) => {
+        const params = (findFocusedRoute(state)?.params as Record<string, string>) ?? {};
+        const activeRoute = Navigation.getActiveRouteWithoutParams();
+        return substituteRouteParameters(activeRoute, params);
+    });
+
+    const wasPreviousNarrowScreen = useRef(!isExtraLargeScreenWidth);
+    useEffect(() => {
+        // Close the side pane when the screen size changes from large to small
+        if (!isExtraLargeScreenWidth && !wasPreviousNarrowScreen.current) {
+            closeSidePane(true);
+            wasPreviousNarrowScreen.current = true;
+        }
+
+        // Reset the trigger when the screen size changes back to large
+        if (isExtraLargeScreenWidth) {
+            wasPreviousNarrowScreen.current = false;
+        }
+    }, [isExtraLargeScreenWidth, closeSidePane]);
+
+    return (
+        <>
+            <HeaderGap />
+            <HeaderWithBackButton
+                title={translate('common.help')}
+                style={styles.headerBarDesktopHeight}
+                onBackButtonPress={() => closeSidePane(false)}
+                onCloseButtonPress={() => closeSidePane(false)}
+                shouldShowBackButton={!isExtraLargeScreenWidth}
+                shouldShowCloseButton={isExtraLargeScreenWidth}
+                shouldDisplayHelpButton={false}
+            />
+            <ScrollView style={[styles.ph5, styles.pb5]}>{getHelpContent(styles, route, isProduction)}</ScrollView>
+        </>
+    );
+}
+
+HelpContent.displayName = 'HelpContent';
+
+export default HelpContent;
diff --git a/src/components/SidePane/Help/index.android.tsx b/src/components/SidePane/Help/index.android.tsx
new file mode 100644
index 000000000000..8be21c35a535
--- /dev/null
+++ b/src/components/SidePane/Help/index.android.tsx
@@ -0,0 +1,38 @@
+import {useFocusEffect} from '@react-navigation/native';
+import React, {useCallback} from 'react';
+// eslint-disable-next-line no-restricted-imports
+import {Animated, BackHandler} from 'react-native';
+import useResponsiveLayout from '@hooks/useResponsiveLayout';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
+import useThemeStyles from '@hooks/useThemeStyles';
+import HelpContent from './HelpContent';
+import type HelpProps from './types';
+
+function Help({sidePaneTranslateX, closeSidePane}: HelpProps) {
+    const styles = useThemeStyles();
+    const {isExtraLargeScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout();
+    const {paddingTop, paddingBottom} = useSafeAreaPaddings();
+
+    // SidePane isn't a native screen, this handles the back button press on Android
+    useFocusEffect(
+        useCallback(() => {
+            const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {
+                closeSidePane();
+                // Return true to indicate that the back button press is handled here
+                return true;
+            });
+
+            return () => backHandler.remove();
+        }, [closeSidePane]),
+    );
+
+    return (
+        <Animated.View style={[styles.sidePaneContainer(shouldUseNarrowLayout, isExtraLargeScreenWidth), {transform: [{translateX: sidePaneTranslateX.current}], paddingTop, paddingBottom}]}>
+            <HelpContent />
+        </Animated.View>
+    );
+}
+
+Help.displayName = 'Help';
+
+export default Help;
diff --git a/src/components/SidePane/Help/index.ios.tsx b/src/components/SidePane/Help/index.ios.tsx
new file mode 100644
index 000000000000..171b98e2c14d
--- /dev/null
+++ b/src/components/SidePane/Help/index.ios.tsx
@@ -0,0 +1,58 @@
+import React from 'react';
+// eslint-disable-next-line no-restricted-imports
+import {Animated, Dimensions} from 'react-native';
+import {Gesture, GestureDetector} from 'react-native-gesture-handler';
+import useResponsiveLayout from '@hooks/useResponsiveLayout';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
+import useThemeStyles from '@hooks/useThemeStyles';
+import CONST from '@src/CONST';
+import HelpContent from './HelpContent';
+import type HelpProps from './types';
+
+const SCREEN_WIDTH = Dimensions.get('window').width;
+
+function Help({sidePaneTranslateX, closeSidePane}: HelpProps) {
+    const styles = useThemeStyles();
+    const {isExtraLargeScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout();
+    const {paddingTop, paddingBottom} = useSafeAreaPaddings();
+
+    // SidePane isn't a native screen, this simulates the 'close swipe gesture' on iOS
+    const panGesture = Gesture.Pan()
+        .runOnJS(true)
+        .hitSlop({left: 0, width: 20})
+        .onUpdate((event) => {
+            if (event.translationX <= 0) {
+                return;
+            }
+            sidePaneTranslateX.current.setValue(event.translationX);
+        })
+        .onEnd((event) => {
+            if (event.translationX > 100) {
+                // If swiped far enough, animate out and close
+                Animated.timing(sidePaneTranslateX.current, {
+                    toValue: SCREEN_WIDTH,
+                    duration: CONST.ANIMATED_TRANSITION,
+                    useNativeDriver: false,
+                }).start(() => closeSidePane());
+            } else {
+                // Otherwise, animate back to original position
+                Animated.spring(sidePaneTranslateX.current, {
+                    toValue: 0,
+                    useNativeDriver: false,
+                }).start();
+            }
+        });
+
+    return (
+        <GestureDetector gesture={panGesture}>
+            <Animated.View
+                style={[styles.sidePaneContainer(shouldUseNarrowLayout, isExtraLargeScreenWidth), {transform: [{translateX: sidePaneTranslateX.current}], paddingTop, paddingBottom}]}
+            >
+                <HelpContent />
+            </Animated.View>
+        </GestureDetector>
+    );
+}
+
+Help.displayName = 'Help';
+export default Help;
diff --git a/src/components/SidePane/Help/index.tsx b/src/components/SidePane/Help/index.tsx
new file mode 100644
index 000000000000..597bff5391ad
--- /dev/null
+++ b/src/components/SidePane/Help/index.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+// eslint-disable-next-line no-restricted-imports
+import {Animated} from 'react-native';
+import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
+import useResponsiveLayout from '@hooks/useResponsiveLayout';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
+import useThemeStyles from '@hooks/useThemeStyles';
+import CONST from '@src/CONST';
+import HelpContent from './HelpContent';
+import type HelpProps from './types';
+
+function Help({sidePaneTranslateX, closeSidePane}: HelpProps) {
+    const styles = useThemeStyles();
+    const {isExtraLargeScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout();
+    const {paddingTop, paddingBottom} = useSafeAreaPaddings();
+
+    useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ESCAPE, () => closeSidePane(), {isActive: !isExtraLargeScreenWidth});
+
+    return (
+        <Animated.View style={[styles.sidePaneContainer(shouldUseNarrowLayout, isExtraLargeScreenWidth), {transform: [{translateX: sidePaneTranslateX.current}], paddingTop, paddingBottom}]}>
+            <HelpContent />
+        </Animated.View>
+    );
+}
+
+Help.displayName = 'Help';
+
+export default Help;
diff --git a/src/components/SidePane/Help/types.ts b/src/components/SidePane/Help/types.ts
new file mode 100644
index 000000000000..8054cc6cd43d
--- /dev/null
+++ b/src/components/SidePane/Help/types.ts
@@ -0,0 +1,10 @@
+import type {MutableRefObject} from 'react';
+// eslint-disable-next-line no-restricted-imports
+import type {Animated} from 'react-native';
+
+type HelpProps = {
+    sidePaneTranslateX: MutableRefObject<Animated.Value>;
+    closeSidePane: (shouldUpdateNarrow?: boolean) => void;
+};
+
+export default HelpProps;
diff --git a/src/components/SidePane/HelpButton.tsx b/src/components/SidePane/HelpButton.tsx
index 3ad251797378..a7b305e7f616 100644
--- a/src/components/SidePane/HelpButton.tsx
+++ b/src/components/SidePane/HelpButton.tsx
@@ -10,6 +10,7 @@ import useSidePane from '@hooks/useSidePane';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
 import {triggerSidePane} from '@libs/actions/SidePane';
+import KeyboardUtils from '@src/utils/keyboard';
 
 type HelpButtonProps = {
     style?: StyleProp<ViewStyle>;
@@ -31,7 +32,13 @@ function HelpButton({style}: HelpButtonProps) {
             <PressableWithoutFeedback
                 accessibilityLabel={translate('common.help')}
                 style={[styles.flexRow, styles.touchableButtonImage, styles.mr2, style]}
-                onPress={() => triggerSidePane(isExtraLargeScreenWidth ? !sidePane?.open : !sidePane?.openNarrowScreen, {shouldUpdateNarrowLayout: !isExtraLargeScreenWidth})}
+                onPress={() => {
+                    KeyboardUtils.dismiss();
+                    triggerSidePane({
+                        isOpen: isExtraLargeScreenWidth ? !sidePane?.open : !sidePane?.openNarrowScreen,
+                        isOpenNarrowScreen: isExtraLargeScreenWidth ? undefined : !sidePane?.openNarrowScreen,
+                    });
+                }}
             >
                 <Icon
                     src={Expensicons.QuestionMark}
diff --git a/src/components/SidePane/getHelpContent.tsx b/src/components/SidePane/getHelpContent.tsx
index 06db2503dcc1..3541ef9fc072 100644
--- a/src/components/SidePane/getHelpContent.tsx
+++ b/src/components/SidePane/getHelpContent.tsx
@@ -1,9 +1,12 @@
+/* eslint-disable react/no-unescaped-entities */
+
 /* eslint-disable @typescript-eslint/naming-convention */
 import type {ReactNode} from 'react';
 import React from 'react';
 import {View} from 'react-native';
 import Text from '@components/Text';
 import type {ThemeStyles} from '@styles/index';
+import CONST from '@src/CONST';
 
 type HelpContent = {
     /** The content to display for this route */
@@ -20,26 +23,199 @@ const helpContentMap: Record<string, HelpContent> = {
     r: {
         content: (styles: ThemeStyles) => (
             <>
-                <Text style={[styles.textHeadlineH1, styles.mb4]}>Chat Reports</Text>
-                <Text style={styles.textNormal}>... general chat reports help ...</Text>
+                <Text style={[styles.textHeadlineH1, styles.mb4]}>Inbox</Text>
+                <Text style={styles.textNormal}>
+                    Chat is the foundation of New Expensify. Every expense, expense report, workspace, or member has an associated "chat", which you can use to record additional details, or
+                    collaborate with others. Every chat has the following components:
+                </Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>Header</Text>
+                <Text style={styles.textNormal}>
+                    This shows who you are chatting with (or what you are chatting about). You can press the header for more details on the chat, or additional actions to take upon it.
+                </Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>Comments</Text>
+                <Text style={styles.textNormal}>The core of the chat are its comments, which come in many forms:</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Text</Text> - Rich text messages stored securely and delivered via web, app, email, or SMS.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Images & Documents</Text> - Insert photos, screenshots, movies, PDFs, or more, using copy/paste, drag/drop, or the attach
+                    button
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Expenses</Text> - Share an expense in the chat, either to simply track and document it, or to submit for reimbursement.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Tasks</Text> - Record a task, and optionally assign it to someone (or yourself!)
+                </Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>Actions</Text>
+                <Text style={styles.textNormal}>Hover (or long press) on a comment to see additional options, including:</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>React</Text> - Throw a ♥️😂🔥 like on anything!
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Reply in thread</Text> - Go deeper by creating a new chat on any comment.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Mark unread</Text> - Flag it for reading later, at your convenience.
+                </Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>Composer</Text>
+                <Text style={styles.textNormal}>Use the composer at the bottom to write new messages:</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Markdown</Text> - Format text using <Text style={styles.textBold}>*bold*</Text>,{' '}
+                    <Text style={styles.textItalic}>_italics_</Text>, and more.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Mention</Text> - Invite or tag anyone in the world to any chat by putting an @ in front of their email address or phone
+                    number (eg,
+                    <Text style={styles.textBold}>@awong@marslink.web</Text>, or <Text style={styles.textBold}>@415-867-5309</Text>).
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Mention</Text> - Invite or tag anyone in the world to any chat by putting an @ in front of their email address or phone
+                    number (eg,
+                    <Text style={styles.textBold}> @awong@marslink.web</Text>, or <Text style={styles.textBold}>@415-867-5309</Text>).
+                </Text>
+            </>
+        ),
+    },
+    home: {
+        content: (styles: ThemeStyles) => (
+            <>
+                <Text style={[styles.textHeadlineH1, styles.mb4]}>Inbox</Text>
+                <Text style={styles.textNormal}>
+                    Chat is the foundation of New Expensify. Every expense, expense report, workspace, or member has an associated "chat", which you can use to record additional details, or
+                    collaborate with others. Every chat has the following components:
+                </Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>Header</Text>
+                <Text style={styles.textNormal}>
+                    This shows who you are chatting with (or what you are chatting about). You can press the header for more details on the chat, or additional actions to take upon it.
+                </Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>Comments</Text>
+                <Text style={styles.textNormal}>The core of the chat are its comments, which come in many forms:</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Text</Text> - Rich text messages stored securely and delivered via web, app, email, or SMS.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Images & Documents</Text> - Insert photos, screenshots, movies, PDFs, or more, using copy/paste, drag/drop, or the attach
+                    button
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Expenses</Text> - Share an expense in the chat, either to simply track and document it, or to submit for reimbursement.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Tasks</Text> - Record a task, and optionally assign it to someone (or yourself!)
+                </Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>Actions</Text>
+                <Text style={styles.textNormal}>Hover (or long press) on a comment to see additional options, including:</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>React</Text> - Throw a ❤️😂🔥 or anything you like on anything!
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Reply in thread</Text> - Go deeper by creating a new chat on any comment.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Mark unread</Text> - Flag it for reading later, at your convenience.
+                </Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>Composer</Text>
+                <Text style={styles.textNormal}>Use the composer at the bottom to write new messages:</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Markdown</Text> - Format text using <Text style={styles.textBold}>*bold*</Text>,{' '}
+                    <Text style={styles.textItalic}>_italics_</Text>, and more.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Mention</Text> - Invite or tag anyone in the world to any chat by putting an @ in front of their email address or phone
+                    number (eg,
+                    <Text style={styles.textBold}> @awong@marslink.web</Text>, or <Text style={styles.textBold}>@415-867-5309</Text>).
+                </Text>
             </>
         ),
-        children: {
-            ':reportID': {
-                content: (styles: ThemeStyles) => (
-                    <>
-                        <Text style={[styles.textHeadlineH1, styles.mb4]}>Chat Report</Text>
-                        <Text style={styles.textNormal}>... general chat report help ...</Text>
-                    </>
-                ),
-            },
-        },
     },
     search: {
         content: (styles: ThemeStyles) => (
             <>
-                <Text style={[styles.textHeadlineH1, styles.mb4]}>Searching Reports</Text>
-                <Text style={styles.textNormal}>... general search help ...</Text>
+                <Text style={[styles.textHeadlineH1, styles.mb4]}>Reports</Text>
+                <Text style={styles.textNormal}>Virtually all data can be analyzed and reported upon in the Reports page. The major elements of this page include:</Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>Data type</Text>
+                <Text style={styles.textNormal}>Start first by choosing the type of data you want to analyze, which can be:</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Expense</Text> - Individual standalone expenses.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Expense reports</Text> - Groups of expenses processed in a batch.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Chats</Text> - Comments written by you and others.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Invoices</Text> - Expenses submitted to clients for payment.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Trips</Text> - Travel expenses booked with Expensify Travel or scanned with SmartScan.
+                </Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>Search</Text>
+                <Text style={styles.textNormal}>A quick method of narrowing the results by keyword or more.</Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>State filter</Text>
+                <Text style={styles.textNormal}>Simple methods to filter the results by "state", including:</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>All</Text> - Everything in every state.
+                </Text>
+
+                <Text style={[styles.textLarge, styles.mt5]}>Expenses/Expense Reports/Invoices</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Draft</Text> - Only you can see that hasn't been shared yet.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Outstanding</Text> - Submitted to someone and awaiting action.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Approved</Text> - Approved, but awaiting payment.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Done</Text> - Fully processed, no further action needed.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Paid</Text> - Fully paid, no further action needed.
+                </Text>
+
+                <Text style={[styles.textLarge, styles.mt5]}>Chats</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Unread</Text> - Not seen yet by you.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Sent</Text> - Sent by you.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Attachments</Text> - Image, movie, or document.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Links</Text> - Hyperlinks.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Pinned</Text> - Highlighted by you as important.
+                </Text>
+
+                <Text style={[styles.textLarge, styles.mt5]}>Trips</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Current</Text> - Happening or in the future.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Past</Text> - Already happened.
+                </Text>
+
+                <Text style={[styles.textHeadlineH2, styles.mv4]}>Results</Text>
+                <Text style={styles.textNormal}>The core of the Reports page are the search results themselves.</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>{CONST.BULLET} Select a row to see additional options.</Text>
+                <Text style={[styles.textNormal, styles.mt2]}>{CONST.BULLET} Tap on a row to see more detail.</Text>
             </>
         ),
     },
@@ -47,23 +223,137 @@ const helpContentMap: Record<string, HelpContent> = {
         content: (styles: ThemeStyles) => (
             <>
                 <Text style={[styles.textHeadlineH1, styles.mb4]}>Settings</Text>
-                <Text style={styles.textNormal}>... general settings help ...</Text>
+                <Text style={styles.textNormal}>Here is where you configure Expensify exactly to your specifications:</Text>
+
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Profile</Text> - Configure how you appear to others.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Wallet</Text> - See and manage your credit cards and bank accounts.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Preferences</Text> - Adjust how the app works for you.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Security</Text> - Lock down how you and others access your account.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Workspaces</Text> - Organize expenses for yourself and share with others.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Subscriptions</Text> - Manage payment details and history.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Domains</Text> - Advanced security and corporate card configuration.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Switch to Expensify Classic</Text> - Battle-tested and reliable.
+                </Text>
+                <Text style={[styles.textNormal, styles.mt2]}>
+                    {CONST.BULLET} <Text style={styles.textBold}>Save the World</Text> - Let Expensify.org help your favorite teacher!
+                </Text>
             </>
         ),
         children: {
             workspaces: {
                 content: (styles: ThemeStyles) => (
                     <>
-                        <Text style={[styles.textHeadlineH1, styles.mb4]}>Workspaces</Text>
-                        <Text style={styles.textNormal}>... general workspaces help ...</Text>
+                        <Text style={[styles.textHeadlineH1, styles.mb4]}>Settings &gt; Workspaces</Text>
+                        <Text style={styles.textNormal}>Workspaces allow for a wide range of features, including:</Text>
+
+                        <Text style={[styles.textNormal, styles.mt2]}>
+                            {CONST.BULLET} <Text style={styles.textBold}>Categorize</Text> and <Text style={styles.textBold}>submit</Text> expenses.
+                        </Text>
+                        <Text style={[styles.textNormal, styles.mt2]}>
+                            {CONST.BULLET} <Text style={styles.textBold}>Approve</Text> and <Text style={styles.textBold}>reimburse</Text> expenses.
+                        </Text>
+                        <Text style={[styles.textNormal, styles.mt2]}>
+                            {CONST.BULLET} Sync with <Text style={styles.textBold}>accounting packages</Text>.
+                        </Text>
+                        <Text style={[styles.textNormal, styles.mt2]}>
+                            {CONST.BULLET} Connect to <Text style={styles.textBold}>company card feeds</Text>.
+                        </Text>
+                        <Text style={[styles.textNormal, styles.mt2]}>
+                            {CONST.BULLET} Manage <Text style={styles.textBold}>Expensify Cards</Text>.
+                        </Text>
+                        <Text style={[styles.textNormal, styles.mt2]}>
+                            {CONST.BULLET} <Text style={styles.textBold}>Chat</Text> with colleagues, partners, and clients.
+                        </Text>
+                        <Text style={[styles.textNormal, styles.mt2]}>{CONST.BULLET} … and lots more!</Text>
+
+                        <Text style={[styles.textHeadlineH2, styles.mv4]}>Workspace Variations</Text>
+                        <Text style={styles.textNormal}>Workspaces come in two variations:</Text>
+
+                        <Text style={[styles.textNormal, styles.mt2]}>
+                            {CONST.BULLET} <Text style={styles.textBold}>Collect</Text> workspaces start at $5/member, and include all the basics for running a small business.
+                        </Text>
+                        <Text style={[styles.textNormal, styles.mt2]}>
+                            {CONST.BULLET} <Text style={styles.textBold}>Control</Text> workspaces start at $9/member, and provide advanced capabilities, more powerful accounting sync, and
+                            more sophisticated approval flows.
+                        </Text>
+
+                        <Text style={[styles.textHeadlineH2, styles.mv4]}>Managing Workspaces</Text>
+                        <Text style={styles.textNormal}>In general, you would create one Workspace for each company you manage. You can create and join as many workspaces as you like.</Text>
                     </>
                 ),
                 children: {
                     ':policyID': {
                         content: (styles: ThemeStyles) => (
                             <>
-                                <Text style={[styles.textHeadlineH1, styles.mb4]}>Workspace Settings</Text>
-                                <Text style={styles.textNormal}>... general workspace settings help ...</Text>
+                                <Text style={[styles.textHeadlineH1, styles.mb4]}>Workspaces</Text>
+                                <Text style={styles.textNormal}>This is where you configure all the settings of the many features associated with your workspace.</Text>
+
+                                <Text style={[styles.textHeadlineH2, styles.mv4]}>Default Features</Text>
+                                <Text style={styles.textNormal}>Here are the features that are enabled by default:</Text>
+
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Overview</Text> - Configure how it appears to others.
+                                </Text>
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Members</Text> - Add/remove members and admins.
+                                </Text>
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Workflows</Text> - Configure submission, approval, and reimbursement.
+                                </Text>
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Categories</Text> - Group expenses into a chart of accounts.
+                                </Text>
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Expensify Card</Text> - Issue native Expensify Cards to employees.
+                                </Text>
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Accounting</Text> - Sync with external accounting systems.
+                                </Text>
+
+                                <Text style={[styles.textHeadlineH2, styles.mv4]}>Optional Features</Text>
+                                <Text style={styles.textNormal}>
+                                    These can be enabled via <Text style={styles.textBold}>More Features</Text>:
+                                </Text>
+
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Distance rates</Text> - Configure mileage reimbursement.
+                                </Text>
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Company card</Text> - Connect and manage third-party corporate card feeds.
+                                </Text>
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Per diem</Text> - Configure daily rates.
+                                </Text>
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Rules</Text> - Customize expense violations and set policy.
+                                </Text>
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Invoices</Text> - Collect revenue from customers.
+                                </Text>
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Tags</Text> - Group expenses by project or client.
+                                </Text>
+                                <Text style={[styles.textNormal, styles.mt2]}>
+                                    {CONST.BULLET} <Text style={styles.textBold}>Taxes</Text> - Track VAT and other taxes.
+                                </Text>
+
+                                <Text style={[styles.textHeadlineH2, styles.mv4]}>Report Fields</Text>
+                                <Text style={styles.textNormal}>Capture extra expense report information.</Text>
                             </>
                         ),
                     },
@@ -76,35 +366,44 @@ const helpContentMap: Record<string, HelpContent> = {
 type DiagnosticDataProps = {
     styles: ThemeStyles;
     route: string;
+    currentRoute?: string;
     isExactMatch?: boolean;
     children?: ReactNode;
 };
 
-function DiagnosticData({styles, route, children, isExactMatch}: DiagnosticDataProps) {
+function DiagnosticData({styles, route, currentRoute, children, isExactMatch}: DiagnosticDataProps) {
     const diagnosticTitle = isExactMatch ? 'Help content found for route:' : 'Missing help content for route:';
 
     return (
-        <View style={styles.ph5}>
-            <Text style={[styles.textHeadlineH1, styles.mb4]}>{diagnosticTitle}</Text>
-            <Text style={styles.textNormal}>{route}</Text>
+        <>
             {!!children && (
                 <>
-                    <View style={[styles.sectionDividerLine, styles.mv5]} />
                     {children}
+                    <View style={[styles.sectionDividerLine, styles.mv5]} />
+                </>
+            )}
+            <Text style={[styles.textHeadlineH1, styles.mb4]}>{diagnosticTitle}</Text>
+            <Text style={styles.textNormal}>{route}</Text>
+            {!isExactMatch && !!currentRoute && (
+                <>
+                    <Text style={[styles.textHeadlineH2, styles.pv4]}>Using content from:</Text>
+                    <Text style={styles.textNormal}>{currentRoute}</Text>
                 </>
             )}
-        </View>
+        </>
     );
 }
 
 function getHelpContent(styles: ThemeStyles, route: string, isProduction: boolean): ReactNode {
     const [firstPart, ...routeParts] = route.substring(1).split('/');
+    const currentRoute = [firstPart];
     let currentNode: HelpContent = helpContentMap[firstPart];
     let isExactMatch = true;
 
     for (const part of routeParts) {
         if (currentNode?.children?.[part]) {
             currentNode = currentNode.children[part];
+            currentRoute.push(part);
             isExactMatch = true;
         } else {
             isExactMatch = false;
@@ -114,7 +413,7 @@ function getHelpContent(styles: ThemeStyles, route: string, isProduction: boolea
 
     if (currentNode?.content) {
         if (isProduction) {
-            return <View style={styles.ph5}>{currentNode.content(styles)}</View>;
+            return currentNode.content(styles);
         }
 
         return (
@@ -122,6 +421,7 @@ function getHelpContent(styles: ThemeStyles, route: string, isProduction: boolea
                 styles={styles}
                 route={route}
                 isExactMatch={isExactMatch}
+                currentRoute={`/${currentRoute.join('/')}`}
             >
                 {currentNode.content(styles)}
             </DiagnosticData>
diff --git a/src/components/SidePane/index.tsx b/src/components/SidePane/index.tsx
index 1b7e6b59fe5e..4a2f7adba8d3 100644
--- a/src/components/SidePane/index.tsx
+++ b/src/components/SidePane/index.tsx
@@ -1,69 +1,14 @@
-import {findFocusedRoute} from '@react-navigation/native';
-import React, {useCallback, useEffect, useRef} from 'react';
-// eslint-disable-next-line no-restricted-imports
-import {Animated, View} from 'react-native';
-import HeaderGap from '@components/HeaderGap';
-import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import useEnvironment from '@hooks/useEnvironment';
-import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
-import useLocalize from '@hooks/useLocalize';
-import useResponsiveLayout from '@hooks/useResponsiveLayout';
+import React from 'react';
+import {View} from 'react-native';
 import useRootNavigationState from '@hooks/useRootNavigationState';
 import useSidePane from '@hooks/useSidePane';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
-import useThemeStyles from '@hooks/useThemeStyles';
-import {triggerSidePane} from '@libs/actions/SidePane';
-import Navigation from '@libs/Navigation/Navigation';
-import {substituteRouteParameters} from '@libs/SidePaneUtils';
-import CONST from '@src/CONST';
 import NAVIGATORS from '@src/NAVIGATORS';
-import getHelpContent from './getHelpContent';
+import Help from './Help';
 import SidePaneOverlay from './SidePaneOverlay';
 
 function SidePane() {
-    const styles = useThemeStyles();
-    const {translate} = useLocalize();
-    const {isProduction} = useEnvironment();
-    const {route, isInNarrowPaneModal} = useRootNavigationState((state) => {
-        const params = (findFocusedRoute(state)?.params as Record<string, string>) ?? {};
-        const activeRoute = Navigation.getActiveRouteWithoutParams();
-
-        return {
-            route: substituteRouteParameters(activeRoute, params),
-            isInNarrowPaneModal: state?.routes.at(-1)?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR,
-        };
-    });
-
-    const {isExtraLargeScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout();
-    const {sidePaneTranslateX, shouldHideSidePane, shouldHideSidePaneBackdrop, sidePane} = useSidePane();
-    const {paddingTop} = useStyledSafeAreaInsets();
-
-    const onClose = useCallback(
-        (shouldUpdateNarrow = false) => {
-            if (!sidePane) {
-                return;
-            }
-
-            triggerSidePane(false, {shouldOnlyUpdateNarrowLayout: !isExtraLargeScreenWidth || shouldUpdateNarrow});
-        },
-        [isExtraLargeScreenWidth, sidePane],
-    );
-
-    const sizeChangedFromLargeToNarrow = useRef(!isExtraLargeScreenWidth);
-    useEffect(() => {
-        // Close the side pane when the screen size changes from large to small
-        if (!isExtraLargeScreenWidth && !sizeChangedFromLargeToNarrow.current) {
-            onClose(true);
-            sizeChangedFromLargeToNarrow.current = true;
-        }
-
-        // Reset the trigger when the screen size changes back to large
-        if (isExtraLargeScreenWidth) {
-            sizeChangedFromLargeToNarrow.current = false;
-        }
-    }, [isExtraLargeScreenWidth, onClose]);
-
-    useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ESCAPE, () => onClose(), {shouldBubble: shouldHideSidePane, isActive: !isExtraLargeScreenWidth});
+    const {shouldHideSidePane, sidePaneTranslateX, shouldHideSidePaneBackdrop, closeSidePane} = useSidePane();
+    const isInNarrowPaneModal = useRootNavigationState((state) => state?.routes.at(-1)?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR);
 
     if (shouldHideSidePane) {
         return null;
@@ -74,24 +19,15 @@ function SidePane() {
             <View>
                 {!shouldHideSidePaneBackdrop && (
                     <SidePaneOverlay
-                        onBackdropPress={onClose}
+                        onBackdropPress={closeSidePane}
                         isInNarrowPaneModal={isInNarrowPaneModal}
                     />
                 )}
             </View>
-            <Animated.View style={[styles.sidePaneContainer(shouldUseNarrowLayout, isExtraLargeScreenWidth), {transform: [{translateX: sidePaneTranslateX.current}], paddingTop}]}>
-                <HeaderGap />
-                <HeaderWithBackButton
-                    title={translate('common.help')}
-                    style={styles.headerBarDesktopHeight}
-                    onBackButtonPress={() => onClose(false)}
-                    onCloseButtonPress={() => onClose(false)}
-                    shouldShowBackButton={!isExtraLargeScreenWidth}
-                    shouldShowCloseButton={isExtraLargeScreenWidth}
-                    shouldDisplayHelpButton={false}
-                />
-                {getHelpContent(styles, route, isProduction)}
-            </Animated.View>
+            <Help
+                sidePaneTranslateX={sidePaneTranslateX}
+                closeSidePane={closeSidePane}
+            />
         </>
     );
 }
diff --git a/src/components/SubStepForms/AddressStep.tsx b/src/components/SubStepForms/AddressStep.tsx
index 5dd5a164f25c..79ca63f9f829 100644
--- a/src/components/SubStepForms/AddressStep.tsx
+++ b/src/components/SubStepForms/AddressStep.tsx
@@ -9,6 +9,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
 import {getFieldRequiredErrors, isValidAddress, isValidZipCode, isValidZipCodeInternational} from '@libs/ValidationUtils';
 import AddressFormFields from '@pages/ReimbursementAccount/AddressFormFields';
 import HelpLinks from '@pages/ReimbursementAccount/USD/Requestor/PersonalInfo/HelpLinks';
+import type {TranslationPaths} from '@src/languages/types';
 import type {OnyxFormValuesMapping} from '@src/ONYXKEYS';
 
 type AddressValues = {
@@ -63,6 +64,9 @@ type AddressStepProps<TFormID extends keyof OnyxFormValuesMapping> = SubStepProp
 
     /** Callback to be called when the country is changed */
     onCountryChange?: (country: unknown) => void;
+
+    /** Translation key of street field */
+    streetTranslationKey?: TranslationPaths;
 };
 
 function AddressStep<TFormID extends keyof OnyxFormValuesMapping>({
@@ -82,6 +86,7 @@ function AddressStep<TFormID extends keyof OnyxFormValuesMapping>({
     stateSelectorModalHeaderTitle,
     stateSelectorSearchInputTitle,
     onCountryChange,
+    streetTranslationKey = 'common.streetAddress',
 }: AddressStepProps<TFormID>) {
     const {translate} = useLocalize();
     const styles = useThemeStyles();
@@ -128,7 +133,7 @@ function AddressStep<TFormID extends keyof OnyxFormValuesMapping>({
                 {!!formPOBoxDisclaimer && <Text style={[styles.textSupporting]}>{formPOBoxDisclaimer}</Text>}
                 <AddressFormFields
                     inputKeys={inputFieldsIDs}
-                    streetTranslationKey="common.streetAddress"
+                    streetTranslationKey={streetTranslationKey}
                     defaultValues={defaultValues}
                     shouldSaveDraft={!isEditing}
                     shouldDisplayStateSelector={shouldDisplayStateSelector}
diff --git a/src/components/SubStepForms/SingleFieldStep.tsx b/src/components/SubStepForms/SingleFieldStep.tsx
index f45cfa521282..ce7fd233c462 100644
--- a/src/components/SubStepForms/SingleFieldStep.tsx
+++ b/src/components/SubStepForms/SingleFieldStep.tsx
@@ -49,6 +49,15 @@ type SingleFieldStepProps<TFormID extends keyof OnyxFormValuesMapping> = SubStep
 
     /** Should the submit button be enabled when offline */
     enabledWhenOffline?: boolean;
+
+    /** Set the default value to the input if there is a valid saved value */
+    shouldUseDefaultValue?: boolean;
+
+    /** Should the input be disabled */
+    disabled?: boolean;
+
+    /** Placeholder displayed inside input */
+    placeholder?: string;
 };
 
 function SingleFieldStep<TFormID extends keyof OnyxFormValuesMapping>({
@@ -65,6 +74,9 @@ function SingleFieldStep<TFormID extends keyof OnyxFormValuesMapping>({
     shouldShowHelpLinks = true,
     maxLength,
     enabledWhenOffline,
+    shouldUseDefaultValue = true,
+    disabled = false,
+    placeholder,
 }: SingleFieldStepProps<TFormID>) {
     const {translate} = useLocalize();
     const styles = useThemeStyles();
@@ -94,6 +106,9 @@ function SingleFieldStep<TFormID extends keyof OnyxFormValuesMapping>({
                         defaultValue={defaultValue}
                         maxLength={maxLength}
                         shouldSaveDraft={!isEditing}
+                        shouldUseDefaultValue={shouldUseDefaultValue}
+                        disabled={disabled}
+                        placeholder={placeholder}
                         autoFocus
                     />
                 </View>
diff --git a/src/components/TestToolsModal.tsx b/src/components/TestToolsModal.tsx
index 7c2e161b2d11..dbfadbe72db9 100644
--- a/src/components/TestToolsModal.tsx
+++ b/src/components/TestToolsModal.tsx
@@ -1,10 +1,11 @@
-import React from 'react';
+import React, {useMemo} from 'react';
 import {View} from 'react-native';
 import {useOnyx} from 'react-native-onyx';
 import useLocalize from '@hooks/useLocalize';
 import useStyleUtils from '@hooks/useStyleUtils';
 import useThemeStyles from '@hooks/useThemeStyles';
 import useWindowDimensions from '@hooks/useWindowDimensions';
+import {getBrowser, isChromeIOS} from '@libs/Browser';
 import Navigation from '@navigation/Navigation';
 import toggleTestToolsModal from '@userActions/TestTool';
 import CONST from '@src/CONST';
@@ -26,6 +27,17 @@ function TestToolsModal() {
     const styles = useThemeStyles();
     const {translate} = useLocalize();
 
+    const shouldShowProfileTool = useMemo(() => {
+        const browser = getBrowser();
+        const isSafariOrFirefox = browser === CONST.BROWSER.SAFARI || browser === CONST.BROWSER.FIREFOX;
+
+        if (isSafariOrFirefox || isChromeIOS()) {
+            return false;
+        }
+
+        return true;
+    }, []);
+
     return (
         <Modal
             isVisible={!!isTestToolsModalOpen}
@@ -39,7 +51,7 @@ function TestToolsModal() {
                 >
                     {translate('initialSettingsPage.troubleshoot.releaseOptions')}
                 </Text>
-                <ProfilingToolMenu />
+                {shouldShowProfileTool && <ProfilingToolMenu />}
                 <ClientSideLoggingToolMenu />
                 {!!shouldStoreLogs && (
                     <TestToolRow title={translate('initialSettingsPage.troubleshoot.debugConsole')}>
diff --git a/src/components/TransactionItemRow/DataCells/CategoryCell.tsx b/src/components/TransactionItemRow/DataCells/CategoryCell.tsx
new file mode 100644
index 000000000000..b561e3e73cf3
--- /dev/null
+++ b/src/components/TransactionItemRow/DataCells/CategoryCell.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import * as Expensicons from '@components/Icon/Expensicons';
+import TextWithIconCell from '@components/SelectionList/Search/TextWithIconCell';
+import TextWithTooltip from '@components/TextWithTooltip';
+import useThemeStyles from '@hooks/useThemeStyles';
+import type TransactionDataCellProps from './TransactionDataCellProps';
+
+function CategoryCell({shouldUseNarrowLayout, shouldShowTooltip, transactionItem}: TransactionDataCellProps) {
+    const styles = useThemeStyles();
+    return shouldUseNarrowLayout ? (
+        <TextWithIconCell
+            icon={Expensicons.Folder}
+            showTooltip={shouldShowTooltip}
+            text={transactionItem?.category}
+            textStyle={[styles.textMicro, styles.mnh0]}
+        />
+    ) : (
+        <TextWithTooltip
+            shouldShowTooltip={shouldShowTooltip}
+            text={transactionItem?.category ?? ''}
+            style={[styles.optionDisplayName, styles.lineHeightLarge, styles.pre, styles.justifyContentCenter]}
+        />
+    );
+}
+
+CategoryCell.displayName = 'CategoryCell';
+export default CategoryCell;
diff --git a/src/components/TransactionItemRow/DataCells/DateCell.tsx b/src/components/TransactionItemRow/DataCells/DateCell.tsx
new file mode 100644
index 000000000000..25ae738fb29b
--- /dev/null
+++ b/src/components/TransactionItemRow/DataCells/DateCell.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import TextWithTooltip from '@components/TextWithTooltip';
+import useThemeStyles from '@hooks/useThemeStyles';
+import DateUtils from '@libs/DateUtils';
+import {getCreated as getTransactionCreated} from '@libs/TransactionUtils';
+import CONST from '@src/CONST';
+import type TransactionDataCellProps from './TransactionDataCellProps';
+
+function DateCell({transactionItem, shouldShowTooltip, shouldUseNarrowLayout}: TransactionDataCellProps) {
+    const styles = useThemeStyles();
+
+    const created = getTransactionCreated(transactionItem);
+    const date = DateUtils.formatWithUTCTimeZone(created, DateUtils.doesDateBelongToAPastYear(created) ? CONST.DATE.MONTH_DAY_YEAR_ABBR_FORMAT : CONST.DATE.MONTH_DAY_ABBR_FORMAT);
+
+    return (
+        <TextWithTooltip
+            shouldShowTooltip={shouldShowTooltip}
+            text={date}
+            style={[styles.pre, styles.justifyContentCenter, shouldUseNarrowLayout ? styles.textMicroSupporting : undefined]}
+        />
+    );
+}
+
+DateCell.displayName = 'DateCell';
+export default DateCell;
diff --git a/src/components/TransactionItemRow/DataCells/MerchantCell.tsx b/src/components/TransactionItemRow/DataCells/MerchantCell.tsx
new file mode 100644
index 000000000000..ec75a5828cf0
--- /dev/null
+++ b/src/components/TransactionItemRow/DataCells/MerchantCell.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import TextWithTooltip from '@components/TextWithTooltip';
+import useThemeStyles from '@hooks/useThemeStyles';
+import CONST from '@src/CONST';
+import type TransactionDataCellProps from './TransactionDataCellProps';
+
+function MerchantCell({transactionItem, shouldShowTooltip}: TransactionDataCellProps) {
+    const styles = useThemeStyles();
+
+    const merchantToDisplay = !transactionItem?.merchant || transactionItem?.merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT ? '' : transactionItem.merchant;
+    return (
+        <TextWithTooltip
+            shouldShowTooltip={shouldShowTooltip}
+            text={merchantToDisplay}
+            style={[styles.pre, styles.justifyContentCenter]}
+        />
+    );
+}
+
+MerchantCell.displayName = 'MerchantCell';
+export default MerchantCell;
diff --git a/src/components/TransactionItemRow/DataCells/ReceiptCell.tsx b/src/components/TransactionItemRow/DataCells/ReceiptCell.tsx
new file mode 100644
index 000000000000..7e6899b70940
--- /dev/null
+++ b/src/components/TransactionItemRow/DataCells/ReceiptCell.tsx
@@ -0,0 +1,56 @@
+import {Str} from 'expensify-common';
+import React from 'react';
+import {View} from 'react-native';
+import {Receipt} from '@components/Icon/Expensicons';
+import ReceiptImage from '@components/ReceiptImage';
+import useStyleUtils from '@hooks/useStyleUtils';
+import useTheme from '@hooks/useTheme';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {getFileName} from '@libs/fileDownload/FileUtils';
+import {getThumbnailAndImageURIs} from '@libs/ReceiptUtils';
+import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
+import variables from '@styles/variables';
+import type {Transaction} from '@src/types/onyx';
+
+function ReceiptCell({transactionItem, isSelected}: {transactionItem: Transaction; isSelected: boolean}) {
+    const theme = useTheme();
+    const styles = useThemeStyles();
+    const StyleUtils = useStyleUtils();
+    const backgroundStyles = isSelected ? StyleUtils.getBackgroundColorStyle(theme.buttonHoveredBG) : StyleUtils.getBackgroundColorStyle(theme.border);
+
+    let source = transactionItem?.receipt?.source ?? '';
+
+    if (source) {
+        const filename = getFileName(source);
+        const receiptURIs = getThumbnailAndImageURIs(transactionItem, null, filename);
+        const isReceiptPDF = Str.isPDF(filename);
+        source = tryResolveUrlFromApiRoot(isReceiptPDF && !receiptURIs.isLocalFile ? receiptURIs.thumbnail ?? '' : receiptURIs.image ?? '');
+    }
+
+    return (
+        <View
+            style={[
+                StyleUtils.getWidthAndHeightStyle(variables.h36, variables.w40),
+                StyleUtils.getBorderRadiusStyle(variables.componentBorderRadiusSmall),
+                styles.overflowHidden,
+                backgroundStyles,
+            ]}
+        >
+            <ReceiptImage
+                source={source}
+                isEReceipt={transactionItem.hasEReceipt}
+                transactionID={transactionItem.transactionID}
+                shouldUseThumbnailImage={!transactionItem?.receipt?.source}
+                isAuthTokenRequired
+                fallbackIcon={Receipt}
+                fallbackIconSize={20}
+                fallbackIconColor={theme.icon}
+                fallbackIconBackground={isSelected ? theme.buttonHoveredBG : undefined}
+                iconSize="x-small"
+            />
+        </View>
+    );
+}
+
+ReceiptCell.displayName = 'ReceiptCell';
+export default ReceiptCell;
diff --git a/src/components/TransactionItemRow/DataCells/TagCell.tsx b/src/components/TransactionItemRow/DataCells/TagCell.tsx
new file mode 100644
index 000000000000..b79e527ea217
--- /dev/null
+++ b/src/components/TransactionItemRow/DataCells/TagCell.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import * as Expensicons from '@components/Icon/Expensicons';
+import TextWithIconCell from '@components/SelectionList/Search/TextWithIconCell';
+import TextWithTooltip from '@components/TextWithTooltip';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {getTagForDisplay} from '@libs/TransactionUtils';
+import type TransactionDataCellProps from './TransactionDataCellProps';
+
+function TagCell({shouldUseNarrowLayout, shouldShowTooltip, transactionItem}: TransactionDataCellProps) {
+    const styles = useThemeStyles();
+    return shouldUseNarrowLayout ? (
+        <TextWithIconCell
+            icon={Expensicons.Tag}
+            showTooltip={shouldShowTooltip}
+            text={getTagForDisplay(transactionItem)}
+            textStyle={[styles.textMicro, styles.mnh0]}
+        />
+    ) : (
+        <TextWithTooltip
+            shouldShowTooltip={shouldShowTooltip}
+            text={getTagForDisplay(transactionItem)}
+            style={[styles.optionDisplayName, styles.lineHeightLarge, styles.pre, styles.justifyContentCenter]}
+        />
+    );
+}
+
+TagCell.displayName = 'TagCell';
+export default TagCell;
diff --git a/src/components/TransactionItemRow/DataCells/TotalCell.tsx b/src/components/TransactionItemRow/DataCells/TotalCell.tsx
new file mode 100644
index 000000000000..b9ecc4036476
--- /dev/null
+++ b/src/components/TransactionItemRow/DataCells/TotalCell.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import TextWithTooltip from '@components/TextWithTooltip';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {convertToDisplayString} from '@libs/CurrencyUtils';
+import {getCurrency as getTransactionCurrency, hasReceipt, isReceiptBeingScanned} from '@libs/TransactionUtils';
+import type TransactionDataCellProps from './TransactionDataCellProps';
+
+function TotalCell({shouldShowTooltip, transactionItem}: TransactionDataCellProps) {
+    const styles = useThemeStyles();
+    const {translate} = useLocalize();
+    const currency = getTransactionCurrency(transactionItem);
+
+    let amount = convertToDisplayString(Math.abs(transactionItem.amount), currency);
+
+    if (hasReceipt(transactionItem) && isReceiptBeingScanned(transactionItem)) {
+        amount = translate('iou.receiptStatusTitle');
+    }
+
+    return (
+        <TextWithTooltip
+            shouldShowTooltip={shouldShowTooltip}
+            text={amount}
+            style={[styles.optionDisplayName, styles.justifyContentCenter]}
+        />
+    );
+}
+
+TotalCell.displayName = 'TotalCell';
+export default TotalCell;
diff --git a/src/components/TransactionItemRow/DataCells/TransactionDataCellProps.ts b/src/components/TransactionItemRow/DataCells/TransactionDataCellProps.ts
new file mode 100644
index 000000000000..df905ea34fc2
--- /dev/null
+++ b/src/components/TransactionItemRow/DataCells/TransactionDataCellProps.ts
@@ -0,0 +1,9 @@
+import type Transaction from '@src/types/onyx/Transaction';
+
+type TransactionDataCellProps = {
+    transactionItem: Transaction;
+    shouldShowTooltip: boolean;
+    shouldUseNarrowLayout?: boolean;
+};
+
+export default TransactionDataCellProps;
diff --git a/src/components/TransactionItemRow/DataCells/TypeCell.tsx b/src/components/TransactionItemRow/DataCells/TypeCell.tsx
new file mode 100644
index 000000000000..6da5f339e0ee
--- /dev/null
+++ b/src/components/TransactionItemRow/DataCells/TypeCell.tsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import TextWithTooltip from '@components/TextWithTooltip';
+import useTheme from '@hooks/useTheme';
+import useThemeStyles from '@hooks/useThemeStyles';
+import CONST from '@src/CONST';
+import type TransactionDataCellProps from './TransactionDataCellProps';
+
+// If the transaction is cash, it has the type CONST.EXPENSE.TYPE.CASH_CARD_NAME.
+// If there is no credit card name, it means it couldn't be a card transaction,
+// so we assume it's cash. Any other type is treated as a card transaction.
+// same in getTypeText
+
+const getTypeIcon = (type?: string) => {
+    switch (type) {
+        case CONST.EXPENSE.TYPE.CASH_CARD_NAME:
+            return Expensicons.Cash;
+        case undefined:
+            return Expensicons.Cash;
+        default:
+            return Expensicons.CreditCard;
+    }
+};
+
+const getTypeText = (type?: string) => {
+    switch (type) {
+        case CONST.EXPENSE.TYPE.CASH_CARD_NAME:
+            return 'Cash';
+        case undefined:
+            return 'Cash';
+        default:
+            return 'CreditCard';
+    }
+};
+
+function TypeCell({transactionItem, shouldUseNarrowLayout, shouldShowTooltip}: TransactionDataCellProps) {
+    const theme = useTheme();
+    const typeIcon = getTypeIcon(transactionItem.cardName);
+    const typeText = getTypeText(transactionItem.cardName);
+    const styles = useThemeStyles();
+
+    return shouldUseNarrowLayout ? (
+        <TextWithTooltip
+            shouldShowTooltip={shouldShowTooltip}
+            text={typeText}
+            style={[styles.textMicroSupporting, styles.pre, styles.justifyContentCenter]}
+        />
+    ) : (
+        <Icon
+            src={typeIcon}
+            fill={theme.icon}
+            height={20}
+            width={20}
+        />
+    );
+}
+
+TypeCell.displayName = 'TypeCell';
+export default TypeCell;
diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
new file mode 100644
index 000000000000..14428f934dde
--- /dev/null
+++ b/src/components/TransactionItemRow/index.tsx
@@ -0,0 +1,153 @@
+import React from 'react';
+import {View} from 'react-native';
+import Hoverable from '@components/Hoverable';
+import Text from '@components/Text';
+import useStyleUtils from '@hooks/useStyleUtils';
+import useThemeStyles from '@hooks/useThemeStyles';
+import CONST from '@src/CONST';
+import type Transaction from '@src/types/onyx/Transaction';
+import CategoryCell from './DataCells/CategoryCell';
+import DateCell from './DataCells/DateCell';
+import MerchantCell from './DataCells/MerchantCell';
+import ReceiptCell from './DataCells/ReceiptCell';
+import TagCell from './DataCells/TagCell';
+import TotalCell from './DataCells/TotalCell';
+import TypeCell from './DataCells/TypeCell';
+
+function TransactionItemRow({
+    transactionItem,
+    shouldUseNarrowLayout,
+    isSelected,
+    shouldShowTooltip,
+}: {
+    transactionItem: Transaction;
+    shouldUseNarrowLayout: boolean;
+    isSelected: boolean;
+    shouldShowTooltip: boolean;
+}) {
+    const styles = useThemeStyles();
+    const StyleUtils = useStyleUtils();
+
+    const backgroundColor = isSelected ? styles.buttonDefaultBG : styles.highlightBG;
+
+    return (
+        <View style={styles.flex1}>
+            {shouldUseNarrowLayout ? (
+                <Hoverable>
+                    {(hovered) => (
+                        <View style={[hovered ? styles.hoveredComponentBG : backgroundColor, styles.expenseWidgetRadius, styles.justifyContentEvenly]}>
+                            <View style={[styles.flexRow, styles.mt3, styles.mr3, styles.mb3, styles.ml3]}>
+                                <View style={[styles.mr3]}>
+                                    <ReceiptCell
+                                        transactionItem={transactionItem}
+                                        isSelected
+                                    />
+                                </View>
+                                <View style={[styles.flex2, styles.flexColumn, styles.justifyContentEvenly]}>
+                                    <View style={[styles.flexRow, styles.alignItemsCenter, styles.minHeight5, styles.maxHeight5]}>
+                                        <DateCell
+                                            transactionItem={transactionItem}
+                                            shouldShowTooltip={shouldShowTooltip}
+                                            shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                        />
+                                        <Text style={[styles.textMicroSupporting]}> • </Text>
+                                        <TypeCell
+                                            transactionItem={transactionItem}
+                                            shouldShowTooltip={shouldShowTooltip}
+                                            shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                        />
+                                    </View>
+                                    <View style={[styles.flexRow, styles.alignItemsCenter, styles.justifyContentBetween, styles.gap2]}>
+                                        <MerchantCell
+                                            transactionItem={transactionItem}
+                                            shouldShowTooltip={shouldShowTooltip}
+                                            shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                        />
+                                        <TotalCell
+                                            transactionItem={transactionItem}
+                                            shouldShowTooltip={shouldShowTooltip}
+                                            shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                        />
+                                    </View>
+                                </View>
+                            </View>
+                            <View style={[styles.flexRow, styles.alignItemsCenter, styles.gap2, styles.ml3, styles.mt0, styles.mb3]}>
+                                <CategoryCell
+                                    transactionItem={transactionItem}
+                                    shouldShowTooltip={shouldShowTooltip}
+                                    shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                />
+                                <TagCell
+                                    transactionItem={transactionItem}
+                                    shouldShowTooltip={shouldShowTooltip}
+                                    shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                />
+                            </View>
+                        </View>
+                    )}
+                </Hoverable>
+            ) : (
+                <Hoverable>
+                    {(hovered) => (
+                        <View style={[hovered ? styles.hoveredComponentBG : backgroundColor, styles.p2, styles.expenseWidgetRadius]}>
+                            <View style={[styles.flex1, styles.flexRow, styles.alignItemsCenter, styles.gap3]}>
+                                <View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.RECEIPT)]}>
+                                    <ReceiptCell
+                                        transactionItem={transactionItem}
+                                        isSelected
+                                    />
+                                </View>
+                                <View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.TYPE)]}>
+                                    <TypeCell
+                                        transactionItem={transactionItem}
+                                        shouldShowTooltip={shouldShowTooltip}
+                                        shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                    />
+                                </View>
+                                <View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.DATE, false)]}>
+                                    <DateCell
+                                        transactionItem={transactionItem}
+                                        shouldShowTooltip={shouldShowTooltip}
+                                        shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                    />
+                                </View>
+                                <View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.MERCHANT)]}>
+                                    <MerchantCell
+                                        transactionItem={transactionItem}
+                                        shouldShowTooltip={shouldShowTooltip}
+                                        shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                    />
+                                </View>
+                                <View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.CATEGORY)]}>
+                                    <CategoryCell
+                                        transactionItem={transactionItem}
+                                        shouldShowTooltip={shouldShowTooltip}
+                                        shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                    />
+                                </View>
+                                <View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.TAG)]}>
+                                    <TagCell
+                                        transactionItem={transactionItem}
+                                        shouldShowTooltip={shouldShowTooltip}
+                                        shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                    />
+                                </View>
+                                <View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT)]}>
+                                    <TotalCell
+                                        transactionItem={transactionItem}
+                                        shouldShowTooltip={shouldShowTooltip}
+                                        shouldUseNarrowLayout={shouldUseNarrowLayout}
+                                    />
+                                </View>
+                            </View>
+                        </View>
+                    )}
+                </Hoverable>
+            )}
+        </View>
+    );
+}
+
+TransactionItemRow.displayName = 'TransactionItemRow';
+
+export default TransactionItemRow;
diff --git a/src/hooks/useBottomSafeSafeAreaPaddingStyle.ts b/src/hooks/useBottomSafeSafeAreaPaddingStyle.ts
new file mode 100644
index 000000000000..de56f88d8ec0
--- /dev/null
+++ b/src/hooks/useBottomSafeSafeAreaPaddingStyle.ts
@@ -0,0 +1,63 @@
+import {useMemo} from 'react';
+import {StyleSheet} from 'react-native';
+import type {StyleProp, ViewStyle} from 'react-native';
+import useSafeAreaPaddings from './useSafeAreaPaddings';
+
+/** The parameters for the useBottomSafeSafeAreaPaddingStyle hook. */
+type UseBottomSafeAreaPaddingStyleParams = {
+    /** Whether to add bottom safe area padding to the content. */
+    addBottomSafeAreaPadding?: boolean;
+
+    /** The style to adapt and add bottom safe area padding to. */
+    style?: StyleProp<ViewStyle>;
+
+    /** The additional padding to add to the bottom of the content. */
+    additionalPaddingBottom?: number;
+};
+
+/**
+ * useBottomSafeSafeAreaPaddingStyle is a hook that creates or adapts a given style and adds bottom safe area padding.
+ * It is useful for creating new styles or updating existing style props (e.g. contentContainerStyle).
+ * @param params - The parameters for the hook.
+ * @returns The style with bottom safe area padding applied.
+ */
+function useBottomSafeSafeAreaPaddingStyle(params?: UseBottomSafeAreaPaddingStyleParams) {
+    const {paddingBottom: safeAreaPaddingBottom} = useSafeAreaPaddings(true);
+
+    const {addBottomSafeAreaPadding, style, additionalPaddingBottom} = params ?? {};
+
+    return useMemo<StyleProp<ViewStyle>>(() => {
+        let totalPaddingBottom: number | string = additionalPaddingBottom ?? 0;
+
+        // Add the safe area padding to the total padding if the flag is enabled
+        if (addBottomSafeAreaPadding) {
+            totalPaddingBottom += safeAreaPaddingBottom;
+        }
+
+        // If there is no bottom safe area or additional padding, return the style as is
+        if (totalPaddingBottom === 0) {
+            return style;
+        }
+
+        // If a style is provided, flatten the style and add the padding to it
+        if (style) {
+            const contentContainerStyleFlattened = StyleSheet.flatten(style);
+            const stylePaddingBottom = contentContainerStyleFlattened?.paddingBottom;
+
+            if (typeof stylePaddingBottom === 'number') {
+                totalPaddingBottom += stylePaddingBottom;
+            } else if (typeof stylePaddingBottom === 'string') {
+                totalPaddingBottom = `calc(${totalPaddingBottom}px + ${stylePaddingBottom})`;
+            } else if (stylePaddingBottom !== undefined) {
+                return style;
+            }
+
+            return [style, {paddingBottom: totalPaddingBottom}];
+        }
+
+        // If no style is provided, return the padding as an object
+        return {paddingBottom: totalPaddingBottom};
+    }, [addBottomSafeAreaPadding, style, additionalPaddingBottom, safeAreaPaddingBottom]);
+}
+
+export default useBottomSafeSafeAreaPaddingStyle;
diff --git a/src/hooks/useSafeAreaInsets.ts b/src/hooks/useSafeAreaInsets.ts
index f954a6c99e94..33a76e3c0053 100644
--- a/src/hooks/useSafeAreaInsets.ts
+++ b/src/hooks/useSafeAreaInsets.ts
@@ -5,8 +5,8 @@ import useStyleUtils from './useStyleUtils';
 
 /**
  * Note: if you're looking for a hook to implement safe area padding in your screen, please either:
- * - use a <ScreenWrapper> component and set `includeSafeAreaPaddingBottom` to `true`. Or
- * - use the `useStyledSafeAreaInsets` hook.
+ * - add the `addBottomSafeAreaPadding` prop to generic components like ScrollView, SelectionList or FormProvider.
+ * - use the `useSafeAreaPaddings` hook.
  *
  * This hook is only meant for internal use cases where you need to access the raw safe area insets.
  */
diff --git a/src/hooks/useStyledSafeAreaInsets.ts b/src/hooks/useSafeAreaPaddings.ts
similarity index 71%
rename from src/hooks/useStyledSafeAreaInsets.ts
rename to src/hooks/useSafeAreaPaddings.ts
index b5a7bd2413c4..9087cd52a338 100644
--- a/src/hooks/useStyledSafeAreaInsets.ts
+++ b/src/hooks/useSafeAreaPaddings.ts
@@ -4,8 +4,7 @@ import useSafeAreaInsets from './useSafeAreaInsets';
 import useStyleUtils from './useStyleUtils';
 
 /**
- * Custom hook to get the styled safe area insets. The top and bottom padding values are adjusted
- * so that they will only ever be applied once per <ScreenWrapper>.
+ * Custom hook to get safe area padding values and styles.
  *
  * This hook utilizes the `SafeAreaInsetsContext` to retrieve the current safe area insets
  * and applies styling adjustments using the `useStyleUtils` hook.
@@ -26,28 +25,41 @@ import useStyleUtils from './useStyleUtils';
  * }
  *
  * function MyComponent() {
- *     const { paddingTop, paddingBottom, safeAreaPaddingBottomStyle } = useStyledSafeAreaInsets();
+ *     const { paddingTop, paddingBottom, safeAreaPaddingBottomStyle } = useSafeAreaPaddings();
  *
  *     // Use these values to style your component accordingly
  * }
  */
-function useStyledSafeAreaInsets() {
+function useSafeAreaPaddings(enableEdgeToEdgeBottomSafeAreaPadding = false) {
     const StyleUtils = useStyleUtils();
     const insets = useSafeAreaInsets();
-    const {paddingTop, paddingBottom} = StyleUtils.getSafeAreaPadding(insets);
+    const {paddingTop, paddingBottom} = useMemo(() => StyleUtils.getPlatformSafeAreaPadding(insets), [StyleUtils, insets]);
 
     const screenWrapperStatusContext = useContext(ScreenWrapperStatusContext);
     const isSafeAreaTopPaddingApplied = screenWrapperStatusContext?.isSafeAreaTopPaddingApplied ?? false;
     const isSafeAreaBottomPaddingApplied = screenWrapperStatusContext?.isSafeAreaBottomPaddingApplied ?? false;
 
+    const adaptedPaddingBottom = isSafeAreaBottomPaddingApplied ? 0 : paddingBottom;
+    const safeAreaPaddingBottomStyle = useMemo(
+        () => ({paddingBottom: enableEdgeToEdgeBottomSafeAreaPadding ? paddingBottom : adaptedPaddingBottom}),
+        [adaptedPaddingBottom, enableEdgeToEdgeBottomSafeAreaPadding, paddingBottom],
+    );
+
+    if (enableEdgeToEdgeBottomSafeAreaPadding) {
+        return {
+            paddingTop,
+            paddingBottom,
+            unmodifiedPaddings: {},
+            insets,
+            safeAreaPaddingBottomStyle,
+        };
+    }
+
     const adaptedInsets = {
         ...insets,
         top: isSafeAreaTopPaddingApplied ? 0 : insets?.top,
         bottom: isSafeAreaBottomPaddingApplied ? 0 : insets?.bottom,
     };
-    const adaptedPaddingBottom = isSafeAreaBottomPaddingApplied ? 0 : paddingBottom;
-
-    const safeAreaPaddingBottomStyle = useMemo(() => ({paddingBottom: adaptedPaddingBottom}), [adaptedPaddingBottom]);
 
     return {
         paddingTop: isSafeAreaTopPaddingApplied ? 0 : paddingTop,
@@ -61,4 +73,4 @@ function useStyledSafeAreaInsets() {
     };
 }
 
-export default useStyledSafeAreaInsets;
+export default useSafeAreaPaddings;
diff --git a/src/hooks/useSidePane.ts b/src/hooks/useSidePane.ts
index 73e1f24a16ca..a879696359fc 100644
--- a/src/hooks/useSidePane.ts
+++ b/src/hooks/useSidePane.ts
@@ -1,14 +1,14 @@
-import {useEffect, useRef, useState} from 'react';
+import {useCallback, useEffect, useRef, useState} from 'react';
 // Import Animated directly from 'react-native' as animations are used with navigation.
 // eslint-disable-next-line no-restricted-imports
 import {Animated} from 'react-native';
 import type {OnyxEntry} from 'react-native-onyx';
 import {useOnyx} from 'react-native-onyx';
+import {triggerSidePane} from '@libs/actions/SidePane';
 import variables from '@styles/variables';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import type * as OnyxTypes from '@src/types/onyx';
-import useEnvironment from './useEnvironment';
 import useResponsiveLayout from './useResponsiveLayout';
 import useWindowDimensions from './useWindowDimensions';
 
@@ -26,7 +26,6 @@ function isSidePaneHidden(sidePane: OnyxEntry<OnyxTypes.SidePane>, isExtraLargeS
 function useSidePane() {
     const {isExtraLargeScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout();
     const {windowWidth} = useWindowDimensions();
-    const {isProduction} = useEnvironment();
 
     const [sidePaneNVP] = useOnyx(ONYXKEYS.NVP_SIDE_PANE);
     const [language] = useOnyx(ONYXKEYS.NVP_PREFERRED_LOCALE);
@@ -37,13 +36,16 @@ function useSidePane() {
     const shouldApplySidePaneOffset = isExtraLargeScreenWidth && !isPaneHidden;
 
     const [shouldHideSidePane, setShouldHideSidePane] = useState(true);
-    const shouldHideSidePaneBackdrop = isPaneHidden || isExtraLargeScreenWidth || shouldUseNarrowLayout;
+    const [isAnimatingExtraLargeScree, setIsAnimatingExtraLargeScreen] = useState(false);
 
-    // The help button is hidden in production if the side pane nvp is not present or the language is unsupported.
-    const shouldHideOnProduction = isProduction && (!sidePaneNVP || isLanguageUnsupported);
+    const shouldHideSidePaneBackdrop = isPaneHidden || isExtraLargeScreenWidth || shouldUseNarrowLayout;
+    const shouldHideToolTip = isExtraLargeScreenWidth ? isAnimatingExtraLargeScree : !shouldHideSidePane;
 
-    // The help button is also hidden if the side pane is displayed currently.
-    const shouldHideHelpButton = shouldHideOnProduction || !isPaneHidden;
+    // The help button is hidden when:
+    // - side pane nvp is not set
+    // - side pane is displayed currently
+    // - language is unsupported
+    const shouldHideHelpButton = !sidePaneNVP || !isPaneHidden || isLanguageUnsupported;
 
     const sidePaneOffset = useRef(new Animated.Value(shouldApplySidePaneOffset ? variables.sideBarWidth : 0));
     const sidePaneTranslateX = useRef(new Animated.Value(isPaneHidden ? sidePaneWidth : 0));
@@ -52,6 +54,9 @@ function useSidePane() {
         if (!isPaneHidden) {
             setShouldHideSidePane(false);
         }
+        if (isExtraLargeScreenWidth) {
+            setIsAnimatingExtraLargeScreen(true);
+        }
 
         Animated.parallel([
             Animated.timing(sidePaneOffset.current, {
@@ -66,8 +71,24 @@ function useSidePane() {
             }),
         ]).start(() => {
             setShouldHideSidePane(isPaneHidden);
+            setIsAnimatingExtraLargeScreen(false);
         });
-    }, [isPaneHidden, shouldApplySidePaneOffset, shouldUseNarrowLayout, sidePaneWidth]);
+    }, [isPaneHidden, shouldApplySidePaneOffset, shouldUseNarrowLayout, sidePaneWidth, isExtraLargeScreenWidth]);
+
+    const closeSidePane = useCallback(
+        (shouldUpdateNarrow = false) => {
+            if (!sidePaneNVP) {
+                return;
+            }
+
+            const shouldOnlyUpdateNarrowLayout = !isExtraLargeScreenWidth || shouldUpdateNarrow;
+            triggerSidePane({
+                isOpen: shouldOnlyUpdateNarrowLayout ? undefined : false,
+                isOpenNarrowScreen: shouldOnlyUpdateNarrowLayout ? false : undefined,
+            });
+        },
+        [isExtraLargeScreenWidth, sidePaneNVP],
+    );
 
     return {
         sidePane: sidePaneNVP,
@@ -76,6 +97,8 @@ function useSidePane() {
         shouldHideHelpButton,
         sidePaneOffset,
         sidePaneTranslateX,
+        shouldHideToolTip,
+        closeSidePane,
     };
 }
 
diff --git a/src/hooks/useWorkspaceList.ts b/src/hooks/useWorkspaceList.ts
new file mode 100644
index 000000000000..ed7dbb2e6c82
--- /dev/null
+++ b/src/hooks/useWorkspaceList.ts
@@ -0,0 +1,113 @@
+import {useMemo} from 'react';
+import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
+import * as Expensicons from '@components/Icon/Expensicons';
+import type {ListItem, SectionListDataType} from '@components/SelectionList/types';
+import {isPolicyAdmin, shouldShowPolicy, sortWorkspacesBySelected} from '@libs/PolicyUtils';
+import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils';
+import type {BrickRoad} from '@libs/WorkspacesSettingsUtils';
+import CONST from '@src/CONST';
+import type {Policy} from '@src/types/onyx';
+import {isEmptyObject} from '@src/types/utils/EmptyObject';
+
+type WorkspaceListItem = {
+    text: string;
+    policyID?: string;
+    isPolicyAdmin?: boolean;
+    brickRoadIndicator?: BrickRoad;
+} & ListItem;
+
+type UseWorkspaceListParams = {
+    policies: OnyxCollection<Policy>;
+    currentUserLogin: string | undefined;
+    isOffline: boolean;
+    selectedPolicyID: string | undefined;
+    searchTerm: string;
+    additionalFilter?: (policy: OnyxEntry<Policy>) => boolean;
+} & (
+    | {
+          isWorkspaceSwitcher: true;
+          hasUnreadData: (policyID?: string) => boolean;
+          getIndicatorTypeForPolicy: (policyID?: string) => BrickRoad;
+      }
+    | {
+          isWorkspaceSwitcher?: false | undefined;
+          hasUnreadData?: never;
+          getIndicatorTypeForPolicy?: never;
+      }
+);
+
+function useWorkspaceList({
+    policies,
+    currentUserLogin,
+    selectedPolicyID,
+    searchTerm,
+    isOffline,
+    isWorkspaceSwitcher = false,
+    hasUnreadData,
+    getIndicatorTypeForPolicy,
+    additionalFilter,
+}: UseWorkspaceListParams) {
+    const usersWorkspaces = useMemo(() => {
+        if (!policies || isEmptyObject(policies)) {
+            return [];
+        }
+
+        return Object.values(policies)
+            .filter((policy) => !!policy && shouldShowPolicy(policy, !!isOffline, currentUserLogin) && !policy?.isJoinRequestPending && (additionalFilter ? additionalFilter(policy) : true))
+            .map((policy) => ({
+                text: policy?.name ?? '',
+                policyID: policy?.id,
+                icons: [
+                    {
+                        source: policy?.avatarURL ? policy.avatarURL : getDefaultWorkspaceAvatar(policy?.name),
+                        fallbackIcon: Expensicons.FallbackWorkspaceAvatar,
+                        name: policy?.name,
+                        type: CONST.ICON_TYPE_WORKSPACE,
+                        id: policy?.id,
+                    },
+                ],
+                keyForList: policy?.id,
+                isPolicyAdmin: isPolicyAdmin(policy),
+                isSelected: selectedPolicyID === policy?.id,
+                ...(isWorkspaceSwitcher &&
+                    hasUnreadData &&
+                    getIndicatorTypeForPolicy && {
+                        isBold: hasUnreadData(policy?.id),
+                        brickRoadIndicator: getIndicatorTypeForPolicy(policy?.id),
+                    }),
+            }));
+    }, [policies, isOffline, currentUserLogin, additionalFilter, selectedPolicyID, getIndicatorTypeForPolicy, hasUnreadData, isWorkspaceSwitcher]);
+
+    const filteredAndSortedUserWorkspaces = useMemo<WorkspaceListItem[]>(
+        () =>
+            usersWorkspaces
+                .filter((policy) => policy.text?.toLowerCase().includes(searchTerm?.toLowerCase() ?? ''))
+                .sort((policy1, policy2) => sortWorkspacesBySelected({policyID: policy1.policyID, name: policy1.text}, {policyID: policy2.policyID, name: policy2.text}, selectedPolicyID)),
+        [searchTerm, usersWorkspaces, selectedPolicyID],
+    );
+
+    const sections = useMemo(() => {
+        const options: Array<SectionListDataType<WorkspaceListItem>> = [
+            {
+                data: filteredAndSortedUserWorkspaces,
+                shouldShow: true,
+                indexOffset: 1,
+            },
+        ];
+        return options;
+    }, [filteredAndSortedUserWorkspaces]);
+
+    const shouldShowNoResultsFoundMessage = filteredAndSortedUserWorkspaces.length === 0 && usersWorkspaces.length;
+    const shouldShowSearchInput = usersWorkspaces.length >= CONST.STANDARD_LIST_ITEM_LIMIT;
+    const shouldShowCreateWorkspace = isWorkspaceSwitcher && usersWorkspaces.length === 0;
+
+    return {
+        sections,
+        shouldShowNoResultsFoundMessage,
+        shouldShowSearchInput,
+        shouldShowCreateWorkspace,
+    };
+}
+
+export default useWorkspaceList;
+export type {WorkspaceListItem};
diff --git a/src/languages/en.ts b/src/languages/en.ts
index dc55db4db924..5b9876e3cdf0 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -37,7 +37,7 @@ import type {
     ChangeOwnerDuplicateSubscriptionParams,
     ChangeOwnerHasFailedSettlementsParams,
     ChangeOwnerSubscriptionParams,
-    ChangePolicyParams,
+    ChangeReportPolicyParams,
     ChangeTypeParams,
     CharacterLengthLimitParams,
     CharacterLimitParams,
@@ -1099,6 +1099,13 @@ const translations = {
         whatIsHoldExplain: 'Hold is like hitting “pause” on an expense to ask for more details before approval or payment.',
         holdIsLeftBehind: 'Held expenses are left behind even if you approve an entire report.',
         unholdWhenReady: "Unhold expenses when you're ready to approve or pay.",
+        changePolicyEducational: {
+            title: 'You moved this report!',
+            description: 'Double-check these items, which tend to change when moving reports to a new workspace.',
+            reCategorize: '<strong>Re-categorize any expenses</strong> to comply with workspace rules.',
+            workflows: 'This report may now be subject to a different <strong>approval workflow.</strong>',
+        },
+        changeWorkspace: 'Change workspace',
         set: 'set',
         changed: 'changed',
         removed: 'removed',
@@ -1943,6 +1950,34 @@ const translations = {
             `We've been unable to deliver SMS messages to ${login}, so we've suspended it for 24 hours. Please try validating your number:`,
         validationFailed: 'Validation failed because it hasn’t been 24 hours since your last attempt.',
         validationSuccess: 'Your number has been validated! Click below to send a new magic sign-in code.',
+        pleaseWaitBeforeTryingAgain: ({timeData}: {timeData?: {days?: number; hours?: number; minutes?: number}}) => {
+            if (!timeData) {
+                return 'Please wait a moment before trying again.';
+            }
+
+            const parts = [];
+            if (timeData.days) {
+                parts.push(`${timeData.days} ${timeData.days === 1 ? 'day' : 'days'}`);
+            }
+            if (timeData.hours) {
+                parts.push(`${timeData.hours} ${timeData.hours === 1 ? 'hour' : 'hours'}`);
+            }
+            if (timeData.minutes) {
+                parts.push(`${timeData.minutes} ${timeData.minutes === 1 ? 'minute' : 'minutes'}`);
+            }
+
+            let timeText;
+            if (parts.length === 1) {
+                timeText = parts.at(0);
+            } else if (parts.length === 2) {
+                timeText = parts.join(' and ');
+            } else {
+                const lastPart = parts.pop();
+                timeText = `${parts.join(', ')} and ${lastPart}`;
+            }
+
+            return `Please wait ${timeText} before trying again.`;
+        },
     },
     welcomeSignUpForm: {
         join: 'Join',
@@ -2163,7 +2198,7 @@ const translations = {
         noOverdraftOrCredit: 'No overdraft/credit feature.',
         electronicFundsWithdrawal: 'Electronic funds withdrawal',
         standard: 'Standard',
-        reviewTheFees: 'Please review the fees below.',
+        reviewTheFees: 'Take a look at some fees.',
         checkTheBoxes: 'Please check the boxes below.',
         agreeToTerms: 'Agree to the terms and you’ll be good to go!',
         shortTermsForm: {
@@ -2178,7 +2213,7 @@ const translations = {
             customerService: 'Customer service',
             automatedOrLive: '(automated or live agent)',
             afterTwelveMonths: '(after 12 months with no transactions)',
-            weChargeOneFee: 'We charge one type of fee.',
+            weChargeOneFee: 'We charge 1 other type of fee. It is:',
             fdicInsurance: 'Your funds are eligible for FDIC insurance.',
             generalInfo: 'For general information about prepaid accounts, visit',
             conditionsDetails: 'For details and conditions for all fees and services, visit',
@@ -2188,9 +2223,9 @@ const translations = {
         },
         longTermsForm: {
             listOfAllFees: 'A list of all Expensify Wallet fees',
-            typeOfFeeHeader: 'Type of fee',
-            feeAmountHeader: 'Fee amount',
-            moreDetailsHeader: 'More details',
+            typeOfFeeHeader: 'All fees',
+            feeAmountHeader: 'Amount',
+            moreDetailsHeader: 'Details',
             openingAccountTitle: 'Opening an account',
             openingAccountDetails: "There's no fee to open an account.",
             monthlyFeeDetails: "There's no monthly fee.",
@@ -2210,7 +2245,8 @@ const translations = {
             fdicInsuranceBancorp: ({amount}: TermsParams) =>
                 'Your funds are eligible for FDIC insurance. Your funds will be held at or ' +
                 `transferred to ${CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK}, an FDIC-insured institution. Once there, your funds are insured up ` +
-                `to ${amount} by the FDIC in the event ${CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK} fails. See`,
+                `to ${amount} by the FDIC in the event ${CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK} fails, if specific deposit insurance requirements ` +
+                `are met and your card is registered. See`,
             fdicInsuranceBancorp2: 'for details.',
             contactExpensifyPayments: `Contact ${CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS} by calling +1 833-400-0904, by email at`,
             contactExpensifyPayments2: 'or sign in at',
@@ -2896,6 +2932,7 @@ const translations = {
             locations: 'Locations',
             customers: 'Customers/projects',
             accountsDescription: 'Your QuickBooks Online chart of accounts will import into Expensify as categories.',
+            autoSyncDescription: 'Sync QuickBooks Online and Expensify automatically, every day. Export finalized report in realtime',
             accountsSwitchTitle: 'Choose to import new accounts as enabled or disabled categories.',
             accountsSwitchDescription: 'Enabled categories will be available for members to select when creating their expenses.',
             classesDescription: 'Choose how to handle QuickBooks Online classes in Expensify.',
@@ -3230,18 +3267,6 @@ const translations = {
                         [CONST.NETSUITE_REPORTS_APPROVAL_LEVEL.REPORTS_APPROVED_BOTH]: 'Supervisor and accounting approved',
                     },
                 },
-                accountingMethods: {
-                    label: 'When to Export',
-                    description: 'Choose when to export the expenses:',
-                    values: {
-                        [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Accrual',
-                        [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Cash',
-                    },
-                    alternateText: {
-                        [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Out-of-pocket expenses will export when final approved',
-                        [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Out-of-pocket expenses will export when paid',
-                    },
-                },
                 exportVendorBillsTo: {
                     label: 'Vendor bill approval level',
                     description: 'Once a vendor bill is approved in Expensify and exported to NetSuite, you can set an additional level of approval in NetSuite prior to posting.',
@@ -3535,6 +3560,18 @@ const translations = {
                 }
             },
         },
+        accountingMethods: {
+            label: 'When to Export',
+            description: 'Choose when to export the expenses:',
+            values: {
+                [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Accrual',
+                [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Cash',
+            },
+            alternateText: {
+                [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Out-of-pocket expenses will export when final approved',
+                [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Out-of-pocket expenses will export when paid',
+            },
+        },
         multiConnectionSelector: {
             title: ({connectionName}: ConnectionNameParams) => `${CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionName]} setup`,
             description: ({connectionName}: ConnectionNameParams) => `Select your ${CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionName]} version to continue.`,
@@ -5145,6 +5182,10 @@ const translations = {
         },
     },
     report: {
+        newReport: {
+            createReport: 'Create report',
+            chooseWorkspace: 'Choose a workspace for this report.',
+        },
         genericCreateReportFailureMessage: 'Unexpected error creating this chat. Please try again later.',
         genericAddCommentFailureMessage: 'Unexpected error posting the comment. Please try again later.',
         genericUpdateReportFieldFailureMessage: 'Unexpected error updating the field. Please try again later.',
@@ -5154,7 +5195,8 @@ const translations = {
             type: {
                 changeField: ({oldValue, newValue, fieldName}: ChangeFieldParams) => `changed ${fieldName} from ${oldValue} to ${newValue}`,
                 changeFieldEmpty: ({newValue, fieldName}: ChangeFieldParams) => `changed ${fieldName} to ${newValue}`,
-                changePolicy: ({fromPolicy, toPolicy}: ChangePolicyParams) => `changed the workspace to ${toPolicy} (previously ${fromPolicy})`,
+                changeReportPolicy: ({fromPolicyName, toPolicyName}: ChangeReportPolicyParams) =>
+                    `changed the workspace to ${toPolicyName}${fromPolicyName ? ` (previously ${fromPolicyName})` : ''}`,
                 changeType: ({oldType, newType}: ChangeTypeParams) => `changed type from ${oldType} to ${newType}`,
                 delegateSubmit: ({delegateUser, originalManager}: DelegateSubmitParams) => `sent this report to ${delegateUser} since ${originalManager} is on vacation`,
                 exportedToCSV: `exported this report to CSV`,
@@ -5496,6 +5538,7 @@ const translations = {
         confirmDetails: `Confirm the details you're keeping`,
         confirmDuplicatesInfo: `The duplicate requests you don't keep will be held for the member to delete`,
         hold: 'Hold',
+        resolvedDuplicates: 'resolved the duplicate',
     },
     reportViolations: {
         [CONST.REPORT_VIOLATIONS.FIELD_REQUIRED]: ({fieldName}: RequiredFieldParams) => `${fieldName} is required`,
diff --git a/src/languages/es.ts b/src/languages/es.ts
index a88fd18f5024..e6d7a163f874 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -36,7 +36,7 @@ import type {
     ChangeOwnerDuplicateSubscriptionParams,
     ChangeOwnerHasFailedSettlementsParams,
     ChangeOwnerSubscriptionParams,
-    ChangePolicyParams,
+    ChangeReportPolicyParams,
     ChangeTypeParams,
     CharacterLengthLimitParams,
     CharacterLimitParams,
@@ -1096,6 +1096,13 @@ const translations = {
         whatIsHoldExplain: 'Retener es como "pausar" un gasto para solicitar más detalles antes de aprobarlo o pagarlo.',
         holdIsLeftBehind: 'Si apruebas un informe, los gastos retenidos se quedan fuera de esa aprobación.',
         unholdWhenReady: 'Desbloquea los gastos cuando estés listo para aprobarlos o pagarlos.',
+        changePolicyEducational: {
+            title: '¡Has movido este informe!',
+            description: 'Revisa cuidadosamente estos elementos, que tienden a cambiar al trasladar informes a un nuevo espacio de trabajo.',
+            reCategorize: '<strong>Vuelve a categorizar los gastos</strong> para cumplir con las reglas del espacio de trabajo.',
+            workflows: 'Este informe ahora puede estar sujeto a un <strong>flujo de aprobación</strong> diferente.',
+        },
+        changeWorkspace: 'Cambiar espacio de trabajo',
         set: 'estableció',
         changed: 'cambió',
         removed: 'eliminó',
@@ -1947,6 +1954,34 @@ const translations = {
             `No hemos podido entregar mensajes SMS a ${login}, así que lo hemos suspendido durante 24 horas. Por favor, intenta validar tu número:`,
         validationFailed: 'La validación falló porque no han pasado 24 horas desde tu último intento.',
         validationSuccess: '¡Tu número ha sido validado! Haz clic abajo para enviar un nuevo código mágico de inicio de sesión.',
+        pleaseWaitBeforeTryingAgain: ({timeData}: {timeData?: {days?: number; hours?: number; minutes?: number}}) => {
+            if (!timeData) {
+                return 'Por favor, espera un momento antes de intentarlo de nuevo.';
+            }
+
+            const parts = [];
+            if (timeData.days) {
+                parts.push(`${timeData.days} ${timeData.days === 1 ? 'día' : 'días'}`);
+            }
+            if (timeData.hours) {
+                parts.push(`${timeData.hours} ${timeData.hours === 1 ? 'hora' : 'horas'}`);
+            }
+            if (timeData.minutes) {
+                parts.push(`${timeData.minutes} ${timeData.minutes === 1 ? 'minuto' : 'minutos'}`);
+            }
+
+            let timeText;
+            if (parts.length === 1) {
+                timeText = parts.at(0);
+            } else if (parts.length === 2) {
+                timeText = parts.join(' y ');
+            } else {
+                const lastPart = parts.pop();
+                timeText = `${parts.join(', ')} y ${lastPart}`;
+            }
+
+            return `Por favor, espera ${timeText} antes de intentarlo de nuevo.`;
+        },
     },
     welcomeSignUpForm: {
         join: 'Unirse',
@@ -2185,7 +2220,7 @@ const translations = {
         noOverdraftOrCredit: 'Sin función de sobregiro/crédito',
         electronicFundsWithdrawal: 'Retiro electrónico de fondos',
         standard: 'Estándar',
-        reviewTheFees: 'Por favor, revisa las siguientes tarifas.',
+        reviewTheFees: 'Echa un vistazo a algunas de las tarifas.',
         checkTheBoxes: 'Por favor, marca las siguientes casillas.',
         agreeToTerms: 'Debes aceptar los términos y condiciones para continuar.',
         shortTermsForm: {
@@ -2200,7 +2235,7 @@ const translations = {
             customerService: 'Servicio al cliente',
             automatedOrLive: '(agente automatizado o en vivo)',
             afterTwelveMonths: '(después de 12 meses sin transacciones)',
-            weChargeOneFee: 'Cobramos un tipo de tarifa.',
+            weChargeOneFee: 'Cobramos otro tipo de tarifa. Es:',
             fdicInsurance: 'Tus fondos pueden acogerse al seguro de la FDIC.',
             generalInfo: 'Para obtener información general sobre cuentas de prepago, visite',
             conditionsDetails: 'Encuentra detalles y condiciones para todas las tarifas y servicios visitando',
@@ -2210,9 +2245,9 @@ const translations = {
         },
         longTermsForm: {
             listOfAllFees: 'Una lista de todas las tarifas de la Billetera Expensify',
-            typeOfFeeHeader: 'Tipo de tarifa',
-            feeAmountHeader: 'Importe de la tarifa',
-            moreDetailsHeader: 'Más detalles',
+            typeOfFeeHeader: 'Todas las tarifas',
+            feeAmountHeader: 'Cantidad',
+            moreDetailsHeader: 'Descripción',
             openingAccountTitle: 'Abrir una cuenta',
             openingAccountDetails: 'No hay tarifa para abrir una cuenta.',
             monthlyFeeDetails: 'No hay tarifa mensual.',
@@ -2233,7 +2268,8 @@ const translations = {
             fdicInsuranceBancorp: ({amount}: TermsParams) =>
                 'Tus fondos pueden acogerse al seguro de la FDIC. Tus fondos se mantendrán o serán ' +
                 `transferidos a ${CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK}, una institución asegurada por la FDIC. Una vez allí, tus fondos ` +
-                `están asegurados hasta ${amount} por la FDIC en caso de que ${CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK} quiebre. Ver`,
+                `están asegurados hasta ${amount} por la FDIC en caso de que ${CONST.WALLET.PROGRAM_ISSUERS.BANCORP_BANK} quiebre, si se cumplen ` +
+                `los requisitos específicos del seguro de depósitos y tu tarjeta está registrada. Ver`,
             fdicInsuranceBancorp2: 'para más detalles.',
             contactExpensifyPayments: `Comunícate con ${CONST.WALLET.PROGRAM_ISSUERS.EXPENSIFY_PAYMENTS} llamando al + 1833-400-0904, o por correo electrónico a`,
             contactExpensifyPayments2: 'o inicie sesión en',
@@ -2922,6 +2958,7 @@ const translations = {
             locations: 'Lugares',
             customers: 'Clientes/proyectos',
             accountsDescription: 'Tu plan de cuentas de QuickBooks Online se importará a Expensify como categorías.',
+            autoSyncDescription: 'Sincroniza QuickBooks Online y Expensify automáticamente, todos los días. Exporta el informe finalizado en tiempo real',
             accountsSwitchTitle: 'Elige importar cuentas nuevas como categorías activadas o desactivadas.',
             accountsSwitchDescription: 'Las categorías activas estarán disponibles para ser escogidas cuando se crea un gasto.',
             classesDescription: 'Elige cómo gestionar las clases de QuickBooks Online en Expensify.',
@@ -3268,18 +3305,6 @@ const translations = {
                         [CONST.NETSUITE_REPORTS_APPROVAL_LEVEL.REPORTS_APPROVED_BOTH]: 'Aprobado por supervisor y contabilidad',
                     },
                 },
-                accountingMethods: {
-                    label: 'Cuándo Exportar',
-                    description: 'Elige cuándo exportar los gastos:',
-                    values: {
-                        [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Devengo',
-                        [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Efectivo',
-                    },
-                    alternateText: {
-                        [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Los gastos por cuenta propia se exportarán cuando estén aprobados definitivamente',
-                        [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Los gastos por cuenta propia se exportarán cuando estén pagados',
-                    },
-                },
                 exportVendorBillsTo: {
                     label: 'Nivel de aprobación de facturas de proveedores',
                     description:
@@ -3574,6 +3599,18 @@ const translations = {
                 }
             },
         },
+        accountingMethods: {
+            label: 'Cuándo Exportar',
+            description: 'Elige cuándo exportar los gastos:',
+            values: {
+                [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Devengo',
+                [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Efectivo',
+            },
+            alternateText: {
+                [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL]: 'Los gastos por cuenta propia se exportarán cuando estén aprobados definitivamente',
+                [COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH]: 'Los gastos por cuenta propia se exportarán cuando estén pagados',
+            },
+        },
         multiConnectionSelector: {
             title: ({connectionName}: ConnectionNameParams) => `${CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionName]} configuración`,
             description: ({connectionName}: ConnectionNameParams) => `Selecciona tu versión de ${CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionName]} para continuar.`,
@@ -5200,6 +5237,10 @@ const translations = {
         },
     },
     report: {
+        newReport: {
+            createReport: 'Crear informe',
+            chooseWorkspace: 'Elige un espacio de trabajo para este informe.',
+        },
         genericCreateReportFailureMessage: 'Error inesperado al crear el chat. Por favor, inténtalo más tarde.',
         genericAddCommentFailureMessage: 'Error inesperado al añadir el comentario. Por favor, inténtalo más tarde.',
         genericUpdateReportFieldFailureMessage: 'Error inesperado al actualizar el campo. Por favor, inténtalo más tarde.',
@@ -5209,7 +5250,8 @@ const translations = {
             type: {
                 changeField: ({oldValue, newValue, fieldName}: ChangeFieldParams) => `cambió ${fieldName} de ${oldValue} a ${newValue}`,
                 changeFieldEmpty: ({newValue, fieldName}: ChangeFieldParams) => `cambió ${fieldName} a ${newValue}`,
-                changePolicy: ({fromPolicy, toPolicy}: ChangePolicyParams) => `cambió el espacio de trabajo a ${toPolicy} (previamente ${fromPolicy})`,
+                changeReportPolicy: ({fromPolicyName, toPolicyName}: ChangeReportPolicyParams) =>
+                    `cambió el espacio de trabajo a ${toPolicyName}${fromPolicyName ? ` (previamente ${fromPolicyName})` : ''}`,
                 changeType: ({oldType, newType}: ChangeTypeParams) => `cambió type de ${oldType} a ${newType}`,
                 delegateSubmit: ({delegateUser, originalManager}: DelegateSubmitParams) => `envié este informe a ${delegateUser} ya que ${originalManager} está de vacaciones`,
                 exportedToCSV: `exportó este informe a CSV`,
@@ -6013,6 +6055,7 @@ const translations = {
         confirmDetails: 'Confirma los detalles que conservas',
         confirmDuplicatesInfo: 'Los duplicados que no conserves se guardarán para que el usuario los elimine',
         hold: 'Retenido',
+        resolvedDuplicates: 'resolvió el duplicado',
     },
     reportViolations: {
         [CONST.REPORT_VIOLATIONS.FIELD_REQUIRED]: ({fieldName}: RequiredFieldParams) => `${fieldName} es obligatorio`,
diff --git a/src/languages/params.ts b/src/languages/params.ts
index b8f1f34ff3a0..d1c6751e123c 100644
--- a/src/languages/params.ts
+++ b/src/languages/params.ts
@@ -293,7 +293,7 @@ type HeldRequestParams = {comment: string};
 
 type ChangeFieldParams = {oldValue?: string; newValue: string; fieldName: string};
 
-type ChangePolicyParams = {fromPolicy: string; toPolicy: string};
+type ChangeReportPolicyParams = {fromPolicyName?: string; toPolicyName: string};
 
 type UpdatedPolicyDescriptionParams = {oldDescription: string; newDescription: string};
 
@@ -829,7 +829,7 @@ export type {
     WelcomeToRoomParams,
     ZipCodeExampleFormatParams,
     ChangeFieldParams,
-    ChangePolicyParams,
+    ChangeReportPolicyParams,
     ChangeTypeParams,
     ExportedToIntegrationParams,
     DelegateSubmitParams,
diff --git a/src/libs/API/index.ts b/src/libs/API/index.ts
index af029c862f07..5c87694c53ed 100644
--- a/src/libs/API/index.ts
+++ b/src/libs/API/index.ts
@@ -2,7 +2,7 @@ import type {OnyxUpdate} from 'react-native-onyx';
 import Onyx from 'react-native-onyx';
 import type {SetRequired} from 'type-fest';
 import Log from '@libs/Log';
-import {HandleUnusedOptimisticID, Logging, Pagination, Reauthentication, RecheckConnection, SaveResponseInOnyx} from '@libs/Middleware';
+import {handleDeletedAccount, HandleUnusedOptimisticID, Logging, Pagination, Reauthentication, RecheckConnection, SaveResponseInOnyx} from '@libs/Middleware';
 import {isOffline} from '@libs/Network/NetworkStore';
 import {push as pushToSequentialQueue, waitForIdle as waitForSequentialQueueIdle} from '@libs/Network/SequentialQueue';
 import Pusher from '@libs/Pusher';
@@ -28,6 +28,9 @@ use(RecheckConnection);
 // Reauthentication - Handles jsonCode 407 which indicates an expired authToken. We need to reauthenticate and get a new authToken with our stored credentials.
 use(Reauthentication);
 
+// Handles the case when the copilot has been deleted. The response contains jsonCode 408 and a message indicating account deletion
+use(handleDeletedAccount);
+
 // If an optimistic ID is not used by the server, this will update the remaining serialized requests using that optimistic ID to use the correct ID instead.
 use(HandleUnusedOptimisticID);
 
diff --git a/src/libs/API/parameters/ChangeReportPolicyParams.ts b/src/libs/API/parameters/ChangeReportPolicyParams.ts
new file mode 100644
index 000000000000..d91e3409b699
--- /dev/null
+++ b/src/libs/API/parameters/ChangeReportPolicyParams.ts
@@ -0,0 +1,7 @@
+type ChangeReportPolicyParams = {
+    reportID: string;
+    policyID: string;
+    reportPreviewReportActionID: string;
+    changePolicyReportActionID: string;
+};
+export default ChangeReportPolicyParams;
diff --git a/src/libs/API/parameters/CreateAppReportParams.ts b/src/libs/API/parameters/CreateAppReportParams.ts
new file mode 100644
index 000000000000..5fccf0e7a166
--- /dev/null
+++ b/src/libs/API/parameters/CreateAppReportParams.ts
@@ -0,0 +1,8 @@
+type CreateAppReportParams = {
+    reportName: string;
+    policyID?: string;
+    type: string;
+    reportID: string;
+    reportActionID: string;
+};
+export default CreateAppReportParams;
diff --git a/src/libs/API/parameters/TransactionMergeParams.ts b/src/libs/API/parameters/MergeDuplicatesParams.ts
similarity index 74%
rename from src/libs/API/parameters/TransactionMergeParams.ts
rename to src/libs/API/parameters/MergeDuplicatesParams.ts
index ad718d37e6c8..b5ef56a52502 100644
--- a/src/libs/API/parameters/TransactionMergeParams.ts
+++ b/src/libs/API/parameters/MergeDuplicatesParams.ts
@@ -1,4 +1,4 @@
-type TransactionMergeParams = {
+type MergeDuplicatesParams = {
     transactionID: string | undefined;
     transactionIDList: string[];
     created: string;
@@ -12,6 +12,7 @@ type TransactionMergeParams = {
     tag: string;
     receiptID: number;
     reportID: string | undefined;
+    reportActionID?: string | undefined;
 };
 
-export default TransactionMergeParams;
+export default MergeDuplicatesParams;
diff --git a/src/libs/API/parameters/UpdateQuickbooksOnlineAccountingMethodParams.ts b/src/libs/API/parameters/UpdateQuickbooksOnlineAccountingMethodParams.ts
new file mode 100644
index 000000000000..617570d5c365
--- /dev/null
+++ b/src/libs/API/parameters/UpdateQuickbooksOnlineAccountingMethodParams.ts
@@ -0,0 +1,9 @@
+import type {CONST as COMMON_CONST} from 'expensify-common';
+import type {ValueOf} from 'type-fest';
+
+type UpdateQuickbooksOnlineAccountingMethodParams = {
+    policyID: string;
+    accountingMethod: ValueOf<typeof COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD>;
+};
+
+export default UpdateQuickbooksOnlineAccountingMethodParams;
diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts
index 3a0d51a9dac5..3675620d8a6c 100644
--- a/src/libs/API/parameters/index.ts
+++ b/src/libs/API/parameters/index.ts
@@ -20,6 +20,7 @@ export type {default as SyncPolicyToQuickbooksOnlineParams} from './SyncPolicyTo
 export type {default as SyncPolicyToXeroParams} from './SyncPolicyToXeroParams';
 export type {default as SyncPolicyToNetSuiteParams} from './SyncPolicyToNetSuiteParams';
 export type {default as UpdateNetSuiteAccountingMethodParams} from './UpdateNetSuiteAccountingMethodParams';
+export type {default as UpdateQuickbooksOnlineAccountingMethodParams} from './UpdateQuickbooksOnlineAccountingMethodParams';
 export type {default as SyncPolicyToQuickbooksDesktopParams} from './SyncPolicyToQuickbooksDesktopParams';
 export type {default as DeleteContactMethodParams} from './DeleteContactMethodParams';
 export type {default as DeletePaymentBankAccountParams} from './DeletePaymentBankAccountParams';
@@ -32,6 +33,7 @@ export type {default as GetOlderActionsParams} from './GetOlderActionsParams';
 export type {default as GetPolicyCategoriesParams} from './GetPolicyCategories';
 export type {default as GetReportPrivateNoteParams} from './GetReportPrivateNoteParams';
 export type {default as GetRouteParams} from './GetRouteParams';
+export type {default as CreateAppReportParams} from './CreateAppReportParams';
 export type {default as GetStatementPDFParams} from './GetStatementPDFParams';
 export type {default as HandleRestrictedEventParams} from './HandleRestrictedEventParams';
 export type {default as LogOutParams} from './LogOutParams';
@@ -244,7 +246,7 @@ export type {default as SearchParams} from './Search';
 export type {default as SendInvoiceParams} from './SendInvoiceParams';
 export type {default as PayInvoiceParams} from './PayInvoiceParams';
 export type {default as MarkAsCashParams} from './MarkAsCashParams';
-export type {default as TransactionMergeParams} from './TransactionMergeParams';
+export type {default as MergeDuplicatesParams} from './MergeDuplicatesParams';
 export type {default as ResolveDuplicatesParams} from './ResolveDuplicatesParams';
 export type {default as UpdateSubscriptionTypeParams} from './UpdateSubscriptionTypeParams';
 export type {default as SignUpUserParams} from './SignUpUserParams';
@@ -379,3 +381,4 @@ export type {default as GetCorpayOnboardingFieldsParams} from './GetCorpayOnboar
 export type {SaveCorpayOnboardingCompanyDetailsParams} from './SaveCorpayOnboardingCompanyDetailsParams';
 export type {default as AcceptSpotnanaTermsParams} from './AcceptSpotnanaTermsParams';
 export type {default as SaveCorpayOnboardingBeneficialOwnerParams} from './SaveCorpayOnboardingBeneficialOwnerParams';
+export type {default as ChangeReportPolicyParams} from './ChangeReportPolicyParams';
diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts
index ad99f057b3c6..244748e8dce3 100644
--- a/src/libs/API/types.ts
+++ b/src/libs/API/types.ts
@@ -110,6 +110,7 @@ const WRITE_COMMANDS = {
     TOGGLE_PINNED_CHAT: 'TogglePinnedChat',
     DELETE_COMMENT: 'DeleteComment',
     UPDATE_COMMENT: 'UpdateComment',
+    CREATE_APP_REPORT: 'CreateAppReport',
     UPDATE_REPORT_NOTIFICATION_PREFERENCE: 'UpdateReportNotificationPreference',
     UPDATE_ROOM_VISIBILITY: 'UpdateRoomVisibility',
     UPDATE_ROOM_DESCRIPTION: 'UpdateRoomDescription',
@@ -267,6 +268,7 @@ const WRITE_COMMANDS = {
     UPDATE_QUICKBOOKS_ONLINE_SYNC_PEOPLE: 'UpdateQuickbooksOnlineSyncPeople',
     UPDATE_QUICKBOOKS_ONLINE_REIMBURSEMENT_ACCOUNT_ID: 'UpdateQuickbooksOnlineReimbursementAccountID',
     UPDATE_QUICKBOOKS_ONLINE_EXPORT: 'UpdateQuickbooksOnlineExport',
+    UPDATE_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD: 'UpdateQuickbooksOnlineAccountingMethod',
     UPDATE_QUICKBOOKS_DESKTOP_EXPORT_DATE: 'UpdateQuickbooksDesktopExportDate',
     UPDATE_MANY_POLICY_CONNECTION_CONFIGS: 'UpdateManyPolicyConnectionConfigurations',
     UPDATE_QUICKBOOKS_DESKTOP_NON_REIMBURSABLE_EXPENSES_EXPORT_DESTINATION: 'UpdateQuickbooksDesktopNonReimbursableExpensesExportDestination',
@@ -310,7 +312,7 @@ const WRITE_COMMANDS = {
     SEND_INVOICE: 'SendInvoice',
     PAY_INVOICE: 'PayInvoice',
     MARK_AS_CASH: 'MarkAsCash',
-    TRANSACTION_MERGE: 'Transaction_Merge',
+    MERGE_DUPLICATES: 'MergeDuplicates',
     RESOLVE_DUPLICATES: 'ResolveDuplicates',
     UPDATE_SUBSCRIPTION_TYPE: 'UpdateSubscriptionType',
     SIGN_UP_USER: 'SignUpUser',
@@ -461,6 +463,7 @@ const WRITE_COMMANDS = {
     RESET_SMS_DELIVERY_FAILURE_STATUS: 'ResetSMSDeliveryFailureStatus',
     SAVE_CORPAY_ONBOARDING_COMPANY_DETAILS: 'SaveCorpayOnboardingCompanyDetails',
     SAVE_CORPAY_ONBOARDING_BENEFICIAL_OWNER: 'SaveCorpayOnboardingBeneficialOwner',
+    CHANGE_REPORT_POLICY: 'ChangeReportPolicy',
 } as const;
 
 type WriteCommand = ValueOf<typeof WRITE_COMMANDS>;
@@ -545,6 +548,7 @@ type WriteCommandParameters = {
     [WRITE_COMMANDS.DISABLE_TWO_FACTOR_AUTH]: Parameters.DisableTwoFactorAuthParams;
     [WRITE_COMMANDS.ADD_COMMENT]: Parameters.AddCommentOrAttachementParams;
     [WRITE_COMMANDS.ADD_ATTACHMENT]: Parameters.AddCommentOrAttachementParams;
+    [WRITE_COMMANDS.CREATE_APP_REPORT]: Parameters.CreateAppReportParams;
     [WRITE_COMMANDS.ADD_TEXT_AND_ATTACHMENT]: Parameters.AddCommentOrAttachementParams;
     [WRITE_COMMANDS.CONNECT_BANK_ACCOUNT_WITH_PLAID]: Parameters.ConnectBankAccountParams;
     [WRITE_COMMANDS.ADD_PERSONAL_BANK_ACCOUNT]: Parameters.AddPersonalBankAccountParams;
@@ -747,6 +751,7 @@ type WriteCommandParameters = {
     [WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_EXPORT_DATE]: Parameters.UpdateQuickbooksOnlineGenericTypeParams;
     [WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_NON_REIMBURSABLE_EXPENSES_ACCOUNT]: Parameters.UpdateQuickbooksOnlineGenericTypeParams;
     [WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_COLLECTION_ACCOUNT_ID]: Parameters.UpdateQuickbooksOnlineGenericTypeParams;
+    [WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD]: Parameters.UpdateQuickbooksOnlineAccountingMethodParams;
     [WRITE_COMMANDS.UPDATE_QUICKBOOKS_DESKTOP_EXPORT_DATE]: Parameters.UpdateQuickbooksDesktopGenericTypeParams;
     [WRITE_COMMANDS.UPDATE_QUICKBOOKS_DESKTOP_MARK_CHECKS_TO_BE_PRINTED]: Parameters.UpdateQuickbooksDesktopGenericTypeParams;
     [WRITE_COMMANDS.UPDATE_QUICKBOOKS_DESKTOP_AUTO_CREATE_VENDOR]: Parameters.UpdateQuickbooksDesktopGenericTypeParams;
@@ -781,7 +786,7 @@ type WriteCommandParameters = {
     [WRITE_COMMANDS.SEND_INVOICE]: Parameters.SendInvoiceParams;
     [WRITE_COMMANDS.PAY_INVOICE]: Parameters.PayInvoiceParams;
     [WRITE_COMMANDS.MARK_AS_CASH]: Parameters.MarkAsCashParams;
-    [WRITE_COMMANDS.TRANSACTION_MERGE]: Parameters.TransactionMergeParams;
+    [WRITE_COMMANDS.MERGE_DUPLICATES]: Parameters.MergeDuplicatesParams;
     [WRITE_COMMANDS.RESOLVE_DUPLICATES]: Parameters.ResolveDuplicatesParams;
     [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_TYPE]: Parameters.UpdateSubscriptionTypeParams;
     [WRITE_COMMANDS.SIGN_UP_USER]: Parameters.SignUpUserParams;
@@ -933,6 +938,9 @@ type WriteCommandParameters = {
     [WRITE_COMMANDS.JOIN_ACCESSIBLE_POLICY]: Parameters.JoinAccessiblePolicyParams;
     // Dismis Product Training
     [WRITE_COMMANDS.DISMISS_PRODUCT_TRAINING]: Parameters.DismissProductTrainingParams;
+
+    // Change report policy
+    [WRITE_COMMANDS.CHANGE_REPORT_POLICY]: Parameters.ChangeReportPolicyParams;
 };
 
 const READ_COMMANDS = {
diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts
index 8e26bb0c8b7b..4cd7762d9ce5 100644
--- a/src/libs/CardUtils.ts
+++ b/src/libs/CardUtils.ts
@@ -531,7 +531,7 @@ function checkIfFeedConnectionIsBroken(feedCards: Record<string, Card> | undefin
         return false;
     }
 
-    return Object.values(feedCards).some((card) => card.bank !== feedToExclude && card.lastScrapeResult !== 200);
+    return Object.values(feedCards).some((card) => !isEmptyObject(card) && card.bank !== feedToExclude && card.lastScrapeResult !== 200);
 }
 
 /**
diff --git a/src/libs/Middleware/HandleDeletedAccount.ts b/src/libs/Middleware/HandleDeletedAccount.ts
new file mode 100644
index 000000000000..ec5532baa230
--- /dev/null
+++ b/src/libs/Middleware/HandleDeletedAccount.ts
@@ -0,0 +1,18 @@
+import {signOutAndRedirectToSignIn} from '@libs/actions/Session';
+import type {Middleware} from '@libs/Request';
+
+/**
+ * Handles the case when the user's copilot has been deleted.
+ * If the response contains jsonCode 408 and a message indicating copilot deletion,
+ * the function signs the user out and redirects them to the sign-in page.
+ */
+
+const handleDeletedAccount: Middleware = (requestResponse) =>
+    requestResponse.then((response) => {
+        if (response?.jsonCode !== 408 || !response?.message?.includes('The account you are trying to use is deleted.')) {
+            return response;
+        }
+        signOutAndRedirectToSignIn(true, false, true, true);
+    });
+
+export default handleDeletedAccount;
diff --git a/src/libs/Middleware/index.ts b/src/libs/Middleware/index.ts
index 7f02e23ad9b8..f64473afc0cf 100644
--- a/src/libs/Middleware/index.ts
+++ b/src/libs/Middleware/index.ts
@@ -1,3 +1,4 @@
+import handleDeletedAccount from './HandleDeletedAccount';
 import HandleUnusedOptimisticID from './HandleUnusedOptimisticID';
 import Logging from './Logging';
 import {Pagination} from './Pagination';
@@ -5,4 +6,4 @@ import Reauthentication from './Reauthentication';
 import RecheckConnection from './RecheckConnection';
 import SaveResponseInOnyx from './SaveResponseInOnyx';
 
-export {HandleUnusedOptimisticID, Logging, Reauthentication, RecheckConnection, SaveResponseInOnyx, Pagination};
+export {HandleUnusedOptimisticID, Logging, Reauthentication, RecheckConnection, SaveResponseInOnyx, Pagination, handleDeletedAccount};
diff --git a/src/libs/NavBarManager/index.android.ts b/src/libs/NavBarManager/index.android.ts
index 81a4626bfb08..1bcfd24507c0 100644
--- a/src/libs/NavBarManager/index.android.ts
+++ b/src/libs/NavBarManager/index.android.ts
@@ -1,11 +1,13 @@
 import {NativeModules} from 'react-native';
-import type StartupTimer from './types';
-import type {NavBarButtonStyle} from './types';
+import type NavBarManager from './types';
 
-const navBarManager: StartupTimer = {
-    setButtonStyle: (style: NavBarButtonStyle) => {
+const navBarManager: NavBarManager = {
+    setButtonStyle: (style) => {
         NativeModules.RNNavBarManager.setButtonStyle(style);
     },
+    getType: () => {
+        return NativeModules.RNNavBarManager.getType();
+    },
 };
 
 export default navBarManager;
diff --git a/src/libs/NavBarManager/index.ts b/src/libs/NavBarManager/index.ts
index 79c9ef85fdcd..a7378895a2fe 100644
--- a/src/libs/NavBarManager/index.ts
+++ b/src/libs/NavBarManager/index.ts
@@ -1,7 +1,10 @@
+import getPlatform from '@libs/getPlatform';
+import CONST from '@src/CONST';
 import type NavBarManager from './types';
 
 const navBarManager: NavBarManager = {
     setButtonStyle: () => {},
+    getType: () => (getPlatform() === CONST.PLATFORM.IOS ? CONST.NAVIGATION_BAR_TYPE.GESTURE_BAR : CONST.NAVIGATION_BAR_TYPE.NONE),
 };
 
 export default navBarManager;
diff --git a/src/libs/NavBarManager/types.ts b/src/libs/NavBarManager/types.ts
index 443db391da9d..f2003be8110c 100644
--- a/src/libs/NavBarManager/types.ts
+++ b/src/libs/NavBarManager/types.ts
@@ -1,8 +1,14 @@
+import type {ValueOf} from 'type-fest';
+import type CONST from '@src/CONST';
+
 type NavBarButtonStyle = 'light' | 'dark';
 
+type NavigationBarType = ValueOf<typeof CONST.NAVIGATION_BAR_TYPE>;
+
 type NavBarManager = {
     setButtonStyle: (style: NavBarButtonStyle) => void;
+    getType: () => NavigationBarType;
 };
 
 export default NavBarManager;
-export type {NavBarButtonStyle};
+export type {NavBarButtonStyle, NavigationBarType};
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
index dd09c5eb27c3..67fa614edb04 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
@@ -10,12 +10,14 @@ import type {
     MissingPersonalDetailsParamList,
     MoneyRequestNavigatorParamList,
     NewChatNavigatorParamList,
+    NewReportWorkspaceSelectionNavigatorParamList,
     NewTaskNavigatorParamList,
     ParticipantsNavigatorParamList,
     PrivateNotesNavigatorParamList,
     ProfileNavigatorParamList,
     ReferralDetailsNavigatorParamList,
     ReimbursementAccountNavigatorParamList,
+    ReportChangeWorkspaceNavigatorParamList,
     ReportDescriptionNavigatorParamList,
     ReportDetailsNavigatorParamList,
     ReportSettingsNavigatorParamList,
@@ -128,12 +130,20 @@ const ProfileModalStackNavigator = createModalStackNavigator<ProfileNavigatorPar
     [SCREENS.PROFILE_ROOT]: () => require<ReactComponentModule>('../../../../pages/ProfilePage').default,
 });
 
+const NewReportWorkspaceSelectionModalStackNavigator = createModalStackNavigator<NewReportWorkspaceSelectionNavigatorParamList>({
+    [SCREENS.NEW_REPORT_WORKSPACE_SELECTION.ROOT]: () => require<ReactComponentModule>('../../../../pages/NewReportWorkspaceSelectionPage').default,
+});
+
 const ReportDetailsModalStackNavigator = createModalStackNavigator<ReportDetailsNavigatorParamList>({
     [SCREENS.REPORT_DETAILS.ROOT]: () => require<ReactComponentModule>('../../../../pages/ReportDetailsPage').default,
     [SCREENS.REPORT_DETAILS.SHARE_CODE]: () => require<ReactComponentModule>('../../../../pages/home/report/ReportDetailsShareCodePage').default,
     [SCREENS.REPORT_DETAILS.EXPORT]: () => require<ReactComponentModule>('../../../../pages/home/report/ReportDetailsExportPage').default,
 });
 
+const ReportChangeWorkspaceModalStackNavigator = createModalStackNavigator<ReportChangeWorkspaceNavigatorParamList>({
+    [SCREENS.REPORT_CHANGE_WORKSPACE.ROOT]: () => require<ReactComponentModule>('../../../../pages/ReportChangeWorkspacePage').default,
+});
+
 const ReportSettingsModalStackNavigator = createModalStackNavigator<ReportSettingsNavigatorParamList>({
     [SCREENS.REPORT_SETTINGS.ROOT]: () => require<ReactComponentModule>('../../../../pages/settings/Report/ReportSettingsPage').default,
     [SCREENS.REPORT_SETTINGS.NAME]: () => require<ReactComponentModule>('../../../../pages/settings/Report/NamePage').default,
@@ -343,6 +353,9 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
         require<ReactComponentModule>('@pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectPage').default,
     [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_COMPANY_CARD_SELECT]: () =>
         require<ReactComponentModule>('../../../../pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectCardPage').default,
+    [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_AUTO_SYNC]: () => require<ReactComponentModule>('../../../../pages/workspace/accounting/qbo/advanced/QuickbooksAutoSyncPage').default,
+    [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNTING_METHOD]: () =>
+        require<ReactComponentModule>('../../../../pages/workspace/accounting/qbo/advanced/QuickbooksAccountingMethodPage').default,
     [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT]: () =>
         require<ReactComponentModule>('../../../../pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountPage').default,
     [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER]: () =>
@@ -658,6 +671,10 @@ const ProcessMoneyRequestHoldStackNavigator = createModalStackNavigator({
     [SCREENS.PROCESS_MONEY_REQUEST_HOLD_ROOT]: () => require<ReactComponentModule>('../../../../pages/ProcessMoneyRequestHoldPage').default,
 });
 
+const ChangePolicyEducationalStackNavigator = createModalStackNavigator({
+    [SCREENS.CHANGE_POLICY_EDUCATIONAL_ROOT]: () => require<ReactComponentModule>('../../../../pages/ChangePolicyEducationalModal').default,
+});
+
 const TransactionDuplicateStackNavigator = createModalStackNavigator<TransactionDuplicateNavigatorParamList>({
     [SCREENS.TRANSACTION_DUPLICATE.REVIEW]: () => require<ReactComponentModule>('../../../../pages/TransactionDuplicate/Review').default,
     [SCREENS.TRANSACTION_DUPLICATE.MERCHANT]: () => require<ReactComponentModule>('../../../../pages/TransactionDuplicate/ReviewMerchant').default,
@@ -733,12 +750,15 @@ export {
     NewTeachersUniteNavigator,
     PrivateNotesModalStackNavigator,
     ProcessMoneyRequestHoldStackNavigator,
+    ChangePolicyEducationalStackNavigator,
     ProfileModalStackNavigator,
     ReferralModalStackNavigator,
     TravelModalStackNavigator,
     ReimbursementAccountModalStackNavigator,
+    NewReportWorkspaceSelectionModalStackNavigator,
     ReportDescriptionModalStackNavigator,
     ReportDetailsModalStackNavigator,
+    ReportChangeWorkspaceModalStackNavigator,
     ReportParticipantsModalStackNavigator,
     ReportSettingsModalStackNavigator,
     RoomMembersModalStackNavigator,
diff --git a/src/libs/Navigation/AppNavigator/Navigators/FeatureTrainingModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/FeatureTrainingModalNavigator.tsx
index db110d53bc63..2041f7b0e4a5 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/FeatureTrainingModalNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/FeatureTrainingModalNavigator.tsx
@@ -4,6 +4,7 @@ import NoDropZone from '@components/DragAndDrop/NoDropZone';
 import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
 import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation';
 import type {FeatureTrainingNavigatorParamList} from '@libs/Navigation/types';
+import ChangePolicyEducationalModal from '@pages/ChangePolicyEducationalModal';
 import ProcessMoneyRequestHoldPage from '@pages/ProcessMoneyRequestHoldPage';
 import TrackTrainingPage from '@pages/TrackTrainingPage';
 import SCREENS from '@src/SCREENS';
@@ -23,6 +24,10 @@ function FeatureTrainingModalNavigator() {
                         name={SCREENS.PROCESS_MONEY_REQUEST_HOLD_ROOT}
                         component={ProcessMoneyRequestHoldPage}
                     />
+                    <Stack.Screen
+                        name={SCREENS.CHANGE_POLICY_EDUCATIONAL_ROOT}
+                        component={ChangePolicyEducationalModal}
+                    />
                 </Stack.Navigator>
             </View>
         </NoDropZone>
diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
index b1d923c69b29..ceb20d4cccb5 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
@@ -108,10 +108,18 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
                         name={SCREENS.RIGHT_MODAL.DEBUG}
                         component={ModalStackNavigators.DebugModalStackNavigator}
                     />
+                    <Stack.Screen
+                        name={SCREENS.RIGHT_MODAL.NEW_REPORT_WORKSPACE_SELECTION}
+                        component={ModalStackNavigators.NewReportWorkspaceSelectionModalStackNavigator}
+                    />
                     <Stack.Screen
                         name={SCREENS.RIGHT_MODAL.REPORT_DETAILS}
                         component={ModalStackNavigators.ReportDetailsModalStackNavigator}
                     />
+                    <Stack.Screen
+                        name={SCREENS.RIGHT_MODAL.REPORT_CHANGE_WORKSPACE}
+                        component={ModalStackNavigators.ReportChangeWorkspaceModalStackNavigator}
+                    />
                     <Stack.Screen
                         name={SCREENS.RIGHT_MODAL.REPORT_SETTINGS}
                         component={ModalStackNavigators.ReportSettingsModalStackNavigator}
diff --git a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts
index 12dc95c14194..617bced0c704 100644
--- a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts
+++ b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts
@@ -128,6 +128,7 @@ function getDefaultFullScreenRoute(route?: NavigationPartialRoute, policyID?: st
     // We will use it if the reportID is not defined. Router of this navigator has logic to fill it with a report.
     const fallbackRoute = {
         name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR,
+        params: policyID ? {policyID} : undefined,
     };
 
     if (route && isRouteWithReportID(route)) {
diff --git a/src/libs/Navigation/helpers/linkTo/index.ts b/src/libs/Navigation/helpers/linkTo/index.ts
index 549a507458b2..e7c2d0aa2814 100644
--- a/src/libs/Navigation/helpers/linkTo/index.ts
+++ b/src/libs/Navigation/helpers/linkTo/index.ts
@@ -62,7 +62,7 @@ function isNavigatingToReportWithSameReportID(currentRoute: NavigationPartialRou
     const currentParams = currentRoute.params as ReportsSplitNavigatorParamList[typeof SCREENS.REPORT];
     const newParams = newRoute?.params as ReportsSplitNavigatorParamList[typeof SCREENS.REPORT];
 
-    return currentParams.reportID === newParams.reportID;
+    return currentParams?.reportID === newParams?.reportID;
 }
 
 export default function linkTo(navigation: NavigationContainerRef<RootNavigatorParamList> | null, path: Route, options?: LinkToOptions) {
diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts
index a986641b3e5b..a68ef1ddf9b3 100755
--- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts
+++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts
@@ -55,6 +55,8 @@ const WORKSPACE_TO_RHP: Partial<Record<keyof WorkspaceSplitNavigatorParamList, s
         SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CLASSES_DISPLAYED_AS,
         SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CUSTOMERS_DISPLAYED_AS,
         SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_LOCATIONS_DISPLAYED_AS,
+        SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_AUTO_SYNC,
+        SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNTING_METHOD,
         SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT,
         SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_COMPANY_CARD_SELECT,
         SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT,
diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts
index 4c5401c12ad0..8bd52742c9ea 100644
--- a/src/libs/Navigation/linkingConfig/config.ts
+++ b/src/libs/Navigation/linkingConfig/config.ts
@@ -45,6 +45,7 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
                     exact: true,
                 },
                 [SCREENS.PROCESS_MONEY_REQUEST_HOLD_ROOT]: ROUTES.PROCESS_MONEY_REQUEST_HOLD.route,
+                [SCREENS.CHANGE_POLICY_EDUCATIONAL_ROOT]: ROUTES.CHANGE_POLICY_EDUCATIONAL.route,
             },
         },
         [NAVIGATORS.WELCOME_VIDEO_MODAL_NAVIGATOR]: {
@@ -357,6 +358,12 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
                         [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_LOCATIONS_DISPLAYED_AS]: {
                             path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_LOCATIONS_DISPLAYED_AS.route,
                         },
+                        [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_AUTO_SYNC]: {
+                            path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_AUTO_SYNC.route,
+                        },
+                        [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNTING_METHOD]: {
+                            path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD.route,
+                        },
                         [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT]: {
                             path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT.route,
                         },
@@ -998,6 +1005,11 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
                         [SCREENS.PRIVATE_NOTES.EDIT]: ROUTES.PRIVATE_NOTES_EDIT.route,
                     },
                 },
+                [SCREENS.RIGHT_MODAL.NEW_REPORT_WORKSPACE_SELECTION]: {
+                    screens: {
+                        [SCREENS.NEW_REPORT_WORKSPACE_SELECTION.ROOT]: ROUTES.NEW_REPORT_WORKSPACE_SELECTION,
+                    },
+                },
                 [SCREENS.RIGHT_MODAL.REPORT_DETAILS]: {
                     screens: {
                         [SCREENS.REPORT_DETAILS.ROOT]: ROUTES.REPORT_WITH_ID_DETAILS.route,
@@ -1005,6 +1017,11 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
                         [SCREENS.REPORT_DETAILS.EXPORT]: ROUTES.REPORT_WITH_ID_DETAILS_EXPORT.route,
                     },
                 },
+                [SCREENS.RIGHT_MODAL.REPORT_CHANGE_WORKSPACE]: {
+                    screens: {
+                        [SCREENS.REPORT_CHANGE_WORKSPACE.ROOT]: ROUTES.REPORT_WITH_ID_CHANGE_WORKSPACE.route,
+                    },
+                },
                 [SCREENS.RIGHT_MODAL.REPORT_SETTINGS]: {
                     screens: {
                         [SCREENS.REPORT_SETTINGS.ROOT]: {
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index e568582a3437..951af6f8e6ce 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -1038,6 +1038,10 @@ type ProfileNavigatorParamList = {
     };
 };
 
+type NewReportWorkspaceSelectionNavigatorParamList = {
+    [SCREENS.NEW_REPORT_WORKSPACE_SELECTION.ROOT]: undefined;
+};
+
 type ReportDetailsNavigatorParamList = {
     [SCREENS.REPORT_DETAILS.ROOT]: {
         reportID: string;
@@ -1055,6 +1059,13 @@ type ReportDetailsNavigatorParamList = {
     };
 };
 
+type ReportChangeWorkspaceNavigatorParamList = {
+    [SCREENS.REPORT_CHANGE_WORKSPACE.ROOT]: {
+        reportID: string;
+        backTo?: Routes;
+    };
+};
+
 type ReportSettingsNavigatorParamList = {
     [SCREENS.REPORT_SETTINGS.ROOT]: {
         reportID: string;
@@ -1460,6 +1471,7 @@ type SignInNavigatorParamList = {
 type FeatureTrainingNavigatorParamList = {
     [SCREENS.FEATURE_TRAINING_ROOT]: undefined;
     [SCREENS.PROCESS_MONEY_REQUEST_HOLD_ROOT]: undefined;
+    [SCREENS.CHANGE_POLICY_EDUCATIONAL_ROOT]: undefined;
 };
 
 type ReferralDetailsNavigatorParamList = {
@@ -1526,7 +1538,9 @@ type RightModalNavigatorParamList = {
     [SCREENS.RIGHT_MODAL.DETAILS]: NavigatorScreenParams<DetailsNavigatorParamList>;
     [SCREENS.RIGHT_MODAL.PROFILE]: NavigatorScreenParams<ProfileNavigatorParamList>;
     [SCREENS.SETTINGS.SHARE_CODE]: undefined;
+    [SCREENS.RIGHT_MODAL.NEW_REPORT_WORKSPACE_SELECTION]: NavigatorScreenParams<NewReportWorkspaceSelectionNavigatorParamList>;
     [SCREENS.RIGHT_MODAL.REPORT_DETAILS]: NavigatorScreenParams<ReportDetailsNavigatorParamList>;
+    [SCREENS.RIGHT_MODAL.REPORT_CHANGE_WORKSPACE]: NavigatorScreenParams<ReportChangeWorkspaceNavigatorParamList>;
     [SCREENS.RIGHT_MODAL.REPORT_SETTINGS]: NavigatorScreenParams<ReportSettingsNavigatorParamList>;
     [SCREENS.RIGHT_MODAL.SETTINGS_CATEGORIES]: NavigatorScreenParams<SettingsNavigatorParamList>;
     [SCREENS.RIGHT_MODAL.SETTINGS_TAGS]: NavigatorScreenParams<SettingsNavigatorParamList>;
@@ -1958,8 +1972,10 @@ export type {
     PublicScreensParamList,
     ReferralDetailsNavigatorParamList,
     ReimbursementAccountNavigatorParamList,
+    NewReportWorkspaceSelectionNavigatorParamList,
     ReportDescriptionNavigatorParamList,
     ReportDetailsNavigatorParamList,
+    ReportChangeWorkspaceNavigatorParamList,
     ReportSettingsNavigatorParamList,
     ReportsSplitNavigatorParamList,
     RestrictedActionParamList,
diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts
index 70a1179a8a72..635e996c322f 100644
--- a/src/libs/Permissions.ts
+++ b/src/libs/Permissions.ts
@@ -54,6 +54,10 @@ function canUseCustomRules(betas: OnyxEntry<Beta[]>): boolean {
     return !!betas?.includes(CONST.BETAS.CUSTOM_RULES) || canUseAllBetas(betas);
 }
 
+function canUseTableReportView(betas: OnyxEntry<Beta[]>): boolean {
+    return !!betas?.includes(CONST.BETAS.TABLE_REPORT_VIEW) || canUseAllBetas(betas);
+}
+
 export default {
     canUseDefaultRooms,
     canUseLinkPreviews,
@@ -66,4 +70,5 @@ export default {
     canUseInternationalBankAccount,
     canUseNSQS,
     canUseCustomRules,
+    canUseTableReportView,
 };
diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts
index dc35a2532727..2c413722e2eb 100644
--- a/src/libs/PersonalDetailsUtils.ts
+++ b/src/libs/PersonalDetailsUtils.ts
@@ -163,6 +163,16 @@ function getAccountIDsByLogins(logins: string[]): number[] {
     }, []);
 }
 
+/**
+ * Given an accountID, find the associated personal detail and return related login.
+ *
+ * @param accountID User accountID
+ * @returns Login according to passed accountID
+ */
+function getLoginByAccountID(accountID: number): string | undefined {
+    return allPersonalDetails?.[accountID]?.login;
+}
+
 /**
  * Given a list of accountIDs, find the associated personal detail and return related logins.
  *
@@ -171,9 +181,9 @@ function getAccountIDsByLogins(logins: string[]): number[] {
  */
 function getLoginsByAccountIDs(accountIDs: number[]): string[] {
     return accountIDs.reduce((foundLogins: string[], accountID) => {
-        const currentDetail: Partial<PersonalDetails> = allPersonalDetails?.[accountID] ?? {};
-        if (currentDetail.login) {
-            foundLogins.push(currentDetail.login);
+        const currentLogin = getLoginByAccountID(accountID);
+        if (currentLogin) {
+            foundLogins.push(currentLogin);
         }
         return foundLogins;
     }, []);
@@ -405,4 +415,5 @@ export {
     getPersonalDetailsLength,
     getUserNameByEmail,
     getDefaultCountry,
+    getLoginByAccountID,
 };
diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts
index 5cdb1c4601a7..54a43f360b77 100644
--- a/src/libs/PolicyUtils.ts
+++ b/src/libs/PolicyUtils.ts
@@ -38,7 +38,7 @@ import {getCategoryApproverRule} from './CategoryUtils';
 import {translateLocal} from './Localize';
 import Navigation from './Navigation/Navigation';
 import {isOffline as isOfflineNetworkStore} from './Network/NetworkStore';
-import {getAccountIDsByLogins, getLoginsByAccountIDs, getPersonalDetailByEmail} from './PersonalDetailsUtils';
+import {getAccountIDsByLogins, getLoginByAccountID, getLoginsByAccountIDs, getPersonalDetailByEmail} from './PersonalDetailsUtils';
 import {getAllSortedTransactions, getCategory, getTag} from './TransactionUtils';
 import {isPublicDomain} from './ValidationUtils';
 
@@ -1087,6 +1087,39 @@ const sortWorkspacesBySelected = (workspace1: WorkspaceDetails, workspace2: Work
     return workspace1.name?.toLowerCase().localeCompare(workspace2.name?.toLowerCase() ?? '') ?? 0;
 };
 
+/**
+ * Determines whether the report can be moved to the workspace.
+ */
+const isWorkspaceEligibleForReportChange = (newPolicy: OnyxEntry<Policy>, report: OnyxEntry<Report>, oldPolicy: OnyxEntry<Policy>, currentUserLogin: string | undefined): boolean => {
+    const currentUserAccountID = getCurrentUserAccountID();
+    const isCurrentUserMember = !!currentUserLogin && !!newPolicy?.employeeList?.[currentUserLogin];
+    if (!isCurrentUserMember) {
+        return false;
+    }
+
+    // Submitters: workspaces where the submitter is a member of
+    const isCurrentUserSubmitter = report?.ownerAccountID === currentUserAccountID;
+    if (isCurrentUserSubmitter) {
+        return true;
+    }
+
+    // Approvers: workspaces where both the approver AND submitter are members of
+    const reportApproverAccountID = getSubmitToAccountID(oldPolicy, report);
+    const isCurrentUserApprover = currentUserAccountID === reportApproverAccountID;
+    if (isCurrentUserApprover) {
+        const reportSubmitterLogin = report?.ownerAccountID ? getLoginByAccountID(report?.ownerAccountID) : undefined;
+        const isReportSubmitterMember = !!reportSubmitterLogin && !!newPolicy?.employeeList?.[reportSubmitterLogin];
+        return isCurrentUserApprover && isReportSubmitterMember;
+    }
+
+    // Admins: same as approvers OR workspaces where the admin is an admin of (note that the submitter is invited to the workspace in this case)
+    if (isPolicyOwner(newPolicy, currentUserAccountID) || isUserPolicyAdmin(newPolicy, currentUserLogin)) {
+        return true;
+    }
+
+    return false;
+};
+
 /**
  * Takes removes pendingFields and errorFields from a customUnit
  */
@@ -1221,6 +1254,13 @@ function areAllGroupPoliciesExpenseChatDisabled(policies = allPolicies) {
     return !groupPolicies.some((policy) => !!policy?.isPolicyExpenseChatEnabled);
 }
 
+function getGroupPaidPoliciesWithExpenseChatEnabled(policies: OnyxCollection<Policy> | null = allPolicies) {
+    if (isEmptyObject(policies)) {
+        return CONST.EMPTY_ARRAY;
+    }
+    return Object.values(policies).filter((policy) => isPaidGroupPolicy(policy) && policy?.isPolicyExpenseChatEnabled);
+}
+
 // eslint-disable-next-line rulesdir/no-negated-variables
 function shouldDisplayPolicyNotFoundPage(policyID: string): boolean {
     const policy = getPolicy(policyID);
@@ -1464,6 +1504,7 @@ export {
     getCurrentTaxID,
     areSettingsInErrorFields,
     settingsPendingAction,
+    getGroupPaidPoliciesWithExpenseChatEnabled,
     getForwardsToAccount,
     getSubmitToAccountID,
     getWorkspaceAccountID,
@@ -1478,7 +1519,6 @@ export {
     getActivePolicy,
     getUserFriendlyWorkspaceType,
     isPolicyAccessible,
-    areAllGroupPoliciesExpenseChatDisabled,
     shouldDisplayPolicyNotFoundPage,
     hasOtherControlWorkspaces,
     getManagerAccountEmail,
@@ -1488,9 +1528,11 @@ export {
     getPolicyNameByID,
     getMostFrequentEmailDomain,
     getDescriptionForPolicyDomainCard,
+    isWorkspaceEligibleForReportChange,
     getManagerAccountID,
     isPrefferedExporter,
     isAutoSyncEnabled,
+    areAllGroupPoliciesExpenseChatDisabled,
 };
 
 export type {MemberEmailsToAccountIDs};
diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index 592cae57daf3..1eb9e4d8859e 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -30,7 +30,7 @@ import Log from './Log';
 import type {MessageElementBase, MessageTextElement} from './MessageElement';
 import Parser from './Parser';
 import {getEffectiveDisplayName, getPersonalDetailsByIDs} from './PersonalDetailsUtils';
-import {getPolicy, getPolicyNameByID, isPolicyAdmin as isPolicyAdminPolicyUtils} from './PolicyUtils';
+import {getPolicy, isPolicyAdmin as isPolicyAdminPolicyUtils} from './PolicyUtils';
 import type {getReportName, OptimisticIOUReportAction, PartialReportAction} from './ReportUtils';
 import StringUtils from './StringUtils';
 import {isOnHoldByTransactionID} from './TransactionUtils';
@@ -1280,7 +1280,6 @@ function isOldDotReportAction(action: ReportAction | OldDotReportAction) {
     }
     return [
         CONST.REPORT.ACTIONS.TYPE.CHANGE_FIELD,
-        CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY,
         CONST.REPORT.ACTIONS.TYPE.CHANGE_TYPE,
         CONST.REPORT.ACTIONS.TYPE.DELEGATE_SUBMIT,
         CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_CSV,
@@ -1336,10 +1335,6 @@ function getMessageOfOldDotReportAction(oldDotAction: PartialReportAction | OldD
             }
             return translateLocal('report.actions.type.changeField', {oldValue, newValue, fieldName});
         }
-        case CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY: {
-            const {fromPolicy, toPolicy} = originalMessage;
-            return translateLocal('report.actions.type.changePolicy', {fromPolicy: getPolicyNameByID(fromPolicy), toPolicy: getPolicyNameByID(toPolicy)});
-        }
         case CONST.REPORT.ACTIONS.TYPE.DELEGATE_SUBMIT: {
             const {delegateUser, originalManager} = originalMessage;
             return translateLocal('report.actions.type.delegateSubmit', {delegateUser, originalManager});
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 6245df9f150f..1e3d5322010c 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -9,7 +9,7 @@ import lodashMaxBy from 'lodash/maxBy';
 import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx';
 import Onyx from 'react-native-onyx';
 import type {SvgProps} from 'react-native-svg';
-import type {OriginalMessageIOU, OriginalMessageModifiedExpense} from 'src/types/onyx/OriginalMessage';
+import type {OriginalMessageChangePolicy, OriginalMessageIOU, OriginalMessageModifiedExpense} from 'src/types/onyx/OriginalMessage';
 import type {SetRequired, TupleToUnion, ValueOf} from 'type-fest';
 import type {FileObject} from '@components/AttachmentModal';
 import {FallbackAvatar, IntacctSquare, NetSuiteSquare, NSQSSquare, QBOSquare, XeroSquare} from '@components/Icon/Expensicons';
@@ -91,6 +91,7 @@ import {
     getForwardsToAccount,
     getManagerAccountEmail,
     getPolicyEmployeeListByIdWithoutCurrentUser,
+    getPolicyNameByID,
     getRuleApprovers,
     getSubmitToAccountID,
     isExpensifyTeam,
@@ -283,6 +284,24 @@ type OptimisticExpenseReport = Pick<
     | 'fieldList'
 >;
 
+type OptimisticNewReport = Pick<
+    Report,
+    | 'reportID'
+    | 'policyID'
+    | 'type'
+    | 'ownerAccountID'
+    | 'reportName'
+    | 'stateNum'
+    | 'statusNum'
+    | 'total'
+    | 'nonReimbursableTotal'
+    | 'parentReportID'
+    | 'lastVisibleActionCreated'
+    | 'parentReportActionID'
+    | 'participants'
+    | 'managerID'
+>;
+
 type OptimisticIOUReportAction = Pick<
     ReportAction,
     | 'actionName'
@@ -3085,7 +3104,7 @@ function isWaitingForAssigneeToCompleteAction(report: OnyxEntry<Report>, parentR
         return true;
     }
 
-    if (!report?.hasParentAccess && isReportManager(report)) {
+    if (report?.hasParentAccess === false && isReportManager(report)) {
         if (isOpenTaskReport(report, parentReportAction)) {
             return true;
         }
@@ -3728,7 +3747,7 @@ function canHoldUnholdReportAction(reportAction: OnyxInputOrEntry<ReportAction>)
     const canModifyUnholdStatus = !isTrackExpenseMoneyReport && (isAdmin || (isActionOwner && isHoldActionCreator) || isApprover);
     const isDeletedParentActionLocal = isEmptyObject(parentReportAction) || isDeletedAction(parentReportAction);
 
-    const canHoldOrUnholdRequest = !isRequestSettled && !isApproved && !isDeletedParentActionLocal && !isClosed;
+    const canHoldOrUnholdRequest = !isRequestSettled && !isApproved && !isDeletedParentActionLocal && !isClosed && !isDeletedParentAction(reportAction);
     const canHoldRequest = canHoldOrUnholdRequest && !isOnHold && (isRequestIOU || canModifyStatus) && !isScanning;
     const canUnholdRequest = !!(canHoldOrUnholdRequest && isOnHold && !isDuplicate(transaction.transactionID, true) && (isRequestIOU ? isHoldActionCreator : canModifyUnholdStatus));
 
@@ -5419,6 +5438,16 @@ function getDeletedTransactionMessage(action: ReportAction) {
     return message;
 }
 
+function getPolicyChangeMessage(action: ReportAction) {
+    const PolicyChangeOriginalMessage = getOriginalMessage(action as ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY>) ?? {};
+    const {fromPolicyID, toPolicyID} = PolicyChangeOriginalMessage as OriginalMessageChangePolicy;
+    const message = translateLocal('report.actions.type.changeReportPolicy', {
+        fromPolicyName: fromPolicyID ? getPolicyNameByID(fromPolicyID) : undefined,
+        toPolicyName: getPolicyNameByID(toPolicyID),
+    });
+    return message;
+}
+
 /**
  * @param iouReportID - the report ID of the IOU report the action belongs to
  * @param type - IOUReportAction type. Can be oneOf(create, decline, cancel, pay, split)
@@ -5696,6 +5725,54 @@ function buildOptimisticMovedReportAction(fromPolicyID: string | undefined, toPo
     };
 }
 
+/**
+ * Builds an optimistic CHANGEPOLICY report action with a randomly generated reportActionID.
+ * This action is used when we change the workspace of a report.
+ */
+function buildOptimisticChangePolicyReportAction(fromPolicyID: string | undefined, toPolicyID: string): ReportAction {
+    const originalMessage = {
+        fromPolicyID,
+        toPolicyID,
+    };
+
+    const fromPolicy = getPolicy(fromPolicyID);
+    const toPolicy = getPolicy(toPolicyID);
+
+    const changePolicyReportActionMessage = [
+        {
+            type: CONST.REPORT.MESSAGE.TYPE.TEXT,
+            text: `changed the workspace to ${toPolicy?.name}`,
+        },
+        ...(fromPolicyID
+            ? [
+                  {
+                      type: CONST.REPORT.MESSAGE.TYPE.TEXT,
+                      text: ` (previously ${fromPolicy?.name})`,
+                  },
+              ]
+            : []),
+    ];
+
+    return {
+        actionName: CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY,
+        actorAccountID: currentUserAccountID,
+        avatar: getCurrentUserAvatar(),
+        created: DateUtils.getDBTime(),
+        originalMessage,
+        message: changePolicyReportActionMessage,
+        person: [
+            {
+                style: 'strong',
+                text: getCurrentUserDisplayNameOrEmail(),
+                type: 'TEXT',
+            },
+        ],
+        reportActionID: rand64(),
+        shouldShow: true,
+        pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
+    };
+}
+
 /**
  * Builds an optimistic SUBMITTED report action with a randomly generated reportActionID.
  *
@@ -6528,6 +6605,32 @@ function buildOptimisticDismissedViolationReportAction(
     };
 }
 
+function buildOptimisticResolvedDuplicatesReportAction(): OptimisticDismissedViolationReportAction {
+    return {
+        actionName: CONST.REPORT.ACTIONS.TYPE.RESOLVED_DUPLICATES,
+        actorAccountID: currentUserAccountID,
+        avatar: getCurrentUserAvatar(),
+        created: DateUtils.getDBTime(),
+        message: [
+            {
+                type: CONST.REPORT.MESSAGE.TYPE.TEXT,
+                style: 'normal',
+                text: translateLocal('violations.resolvedDuplicates'),
+            },
+        ],
+        pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
+        person: [
+            {
+                type: CONST.REPORT.MESSAGE.TYPE.TEXT,
+                style: 'strong',
+                text: getCurrentUserDisplayNameOrEmail(),
+            },
+        ],
+        reportActionID: rand64(),
+        shouldShow: true,
+    };
+}
+
 function buildOptimisticAnnounceChat(policyID: string, accountIDs: number[]): OptimisticAnnounceChat {
     const announceReport = getRoom(CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, policyID);
     const policy = getPolicy(policyID);
@@ -9589,7 +9692,11 @@ export {
     buildOptimisticSelfDMReport,
     isHiddenForCurrentUser,
     prepareOnboardingOnyxData,
+    buildOptimisticResolvedDuplicatesReportAction,
     getReportSubtitlePrefix,
+    buildOptimisticChangePolicyReportAction,
+    getPolicyChangeMessage,
+    getExpenseReportStateAndStatus,
 };
 
 export type {
@@ -9606,4 +9713,5 @@ export type {
     PartialReportAction,
     ParsingDetails,
     MissingPaymentMethod,
+    OptimisticNewReport,
 };
diff --git a/src/libs/SearchAutocompleteUtils.ts b/src/libs/SearchAutocompleteUtils.ts
index 8d81ce7da593..613e425b0725 100644
--- a/src/libs/SearchAutocompleteUtils.ts
+++ b/src/libs/SearchAutocompleteUtils.ts
@@ -148,6 +148,7 @@ function filterOutRangesWithCorrectValue(
     const typeList = Object.values(CONST.SEARCH.DATA_TYPES) as string[];
     const expenseTypeList = Object.values(CONST.SEARCH.TRANSACTION_TYPE) as string[];
     const statusList = Object.values({...CONST.SEARCH.STATUS.EXPENSE, ...CONST.SEARCH.STATUS.INVOICE, ...CONST.SEARCH.STATUS.CHAT, ...CONST.SEARCH.STATUS.TRIP}) as string[];
+    const groupByList = Object.values(CONST.SEARCH.GROUP_BY) as string[];
 
     switch (range.key) {
         case CONST.SEARCH.SYNTAX_FILTER_KEYS.IN:
@@ -172,6 +173,8 @@ function filterOutRangesWithCorrectValue(
             return categoryList.get().includes(range.value);
         case CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG:
             return tagList.get().includes(range.value);
+        case CONST.SEARCH.SYNTAX_ROOT_KEYS.GROUP_BY:
+            return groupByList.includes(range.value);
         default:
             return false;
     }
diff --git a/src/libs/SearchParser/autocompleteParser.js b/src/libs/SearchParser/autocompleteParser.js
index fae0339d4ac9..5ee9b3942896 100644
--- a/src/libs/SearchParser/autocompleteParser.js
+++ b/src/libs/SearchParser/autocompleteParser.js
@@ -215,12 +215,14 @@ function peg$parse(input, options) {
   var peg$c29 = "paid";
   var peg$c30 = "exported";
   var peg$c31 = "posted";
-  var peg$c32 = "feed";
-  var peg$c33 = "!=";
-  var peg$c34 = ">=";
-  var peg$c35 = ">";
-  var peg$c36 = "<=";
-  var peg$c37 = "<";
+  var peg$c32 = "groupby";
+  var peg$c33 = "group-by";
+  var peg$c34 = "feed";
+  var peg$c35 = "!=";
+  var peg$c36 = ">=";
+  var peg$c37 = ">";
+  var peg$c38 = "<=";
+  var peg$c39 = "<";
 
   var peg$r0 = /^[:=]/;
   var peg$r1 = /^[^ ,"\u201D\u201C\t\n\r\xA0]/;
@@ -262,22 +264,24 @@ function peg$parse(input, options) {
   var peg$e30 = peg$literalExpectation("paid", true);
   var peg$e31 = peg$literalExpectation("exported", true);
   var peg$e32 = peg$literalExpectation("posted", true);
-  var peg$e33 = peg$literalExpectation("feed", true);
-  var peg$e34 = peg$otherExpectation("operator");
-  var peg$e35 = peg$classExpectation([":", "="], false, false);
-  var peg$e36 = peg$literalExpectation("!=", false);
-  var peg$e37 = peg$literalExpectation(">=", false);
-  var peg$e38 = peg$literalExpectation(">", false);
-  var peg$e39 = peg$literalExpectation("<=", false);
-  var peg$e40 = peg$literalExpectation("<", false);
-  var peg$e41 = peg$otherExpectation("quote");
-  var peg$e42 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false);
-  var peg$e43 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false);
-  var peg$e44 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false);
-  var peg$e45 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false);
-  var peg$e46 = peg$otherExpectation("word");
-  var peg$e47 = peg$otherExpectation("whitespace");
-  var peg$e48 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false);
+  var peg$e33 = peg$literalExpectation("groupBy", true);
+  var peg$e34 = peg$literalExpectation("group-by", true);
+  var peg$e35 = peg$literalExpectation("feed", true);
+  var peg$e36 = peg$otherExpectation("operator");
+  var peg$e37 = peg$classExpectation([":", "="], false, false);
+  var peg$e38 = peg$literalExpectation("!=", false);
+  var peg$e39 = peg$literalExpectation(">=", false);
+  var peg$e40 = peg$literalExpectation(">", false);
+  var peg$e41 = peg$literalExpectation("<=", false);
+  var peg$e42 = peg$literalExpectation("<", false);
+  var peg$e43 = peg$otherExpectation("quote");
+  var peg$e44 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false);
+  var peg$e45 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false);
+  var peg$e46 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false);
+  var peg$e47 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false);
+  var peg$e48 = peg$otherExpectation("word");
+  var peg$e49 = peg$otherExpectation("whitespace");
+  var peg$e50 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false);
 
   var peg$f0 = function(ranges) { return { autocomplete, ranges }; };
   var peg$f1 = function(filters) { return filters.filter(Boolean).flat(); };
@@ -351,18 +355,19 @@ function peg$parse(input, options) {
   var peg$f27 = function() { return "paid"; };
   var peg$f28 = function() { return "exported"; };
   var peg$f29 = function() { return "posted"; };
-  var peg$f30 = function() { return "feed"; };
-  var peg$f31 = function() { return "eq"; };
-  var peg$f32 = function() { return "neq"; };
-  var peg$f33 = function() { return "gte"; };
-  var peg$f34 = function() { return "gt"; };
-  var peg$f35 = function() { return "lte"; };
-  var peg$f36 = function() { return "lt"; };
-  var peg$f37 = function(start, inner, end) { //handle no-breaking space
+  var peg$f30 = function() { return "groupBy"; };
+  var peg$f31 = function() { return "feed"; };
+  var peg$f32 = function() { return "eq"; };
+  var peg$f33 = function() { return "neq"; };
+  var peg$f34 = function() { return "gte"; };
+  var peg$f35 = function() { return "gt"; };
+  var peg$f36 = function() { return "lte"; };
+  var peg$f37 = function() { return "lt"; };
+  var peg$f38 = function(start, inner, end) { //handle no-breaking space
       return [...start, '"', ...inner, '"', ...end].join("");
     };
-  var peg$f38 = function(chars) { return chars.join("").trim(); };
-  var peg$f39 = function() { return "and"; };
+  var peg$f39 = function(chars) { return chars.join("").trim(); };
+  var peg$f40 = function() { return "and"; };
   var peg$currPos = options.peg$currPos | 0;
   var peg$savedPos = peg$currPos;
   var peg$posDetailsCache = [{ line: 1, column: 1 }];
@@ -665,6 +670,9 @@ function peg$parse(input, options) {
                         s1 = peg$parsecardID();
                         if (s1 === peg$FAILED) {
                           s1 = peg$parsefeed();
+                          if (s1 === peg$FAILED) {
+                            s1 = peg$parsegroupBy();
+                          }
                         }
                       }
                     }
@@ -1307,20 +1315,49 @@ function peg$parse(input, options) {
     return s0;
   }
 
+  function peg$parsegroupBy() {
+    var s0, s1;
+
+    s0 = input.substr(peg$currPos, 7);
+    if (s0.toLowerCase() === peg$c32) {
+      peg$currPos += 7;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e33); }
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = input.substr(peg$currPos, 8);
+      if (s1.toLowerCase() === peg$c33) {
+        peg$currPos += 8;
+      } else {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e34); }
+      }
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f30();
+      }
+      s0 = s1;
+    }
+
+    return s0;
+  }
+
   function peg$parsefeed() {
     var s0, s1;
 
     s0 = peg$currPos;
     s1 = input.substr(peg$currPos, 4);
-    if (s1.toLowerCase() === peg$c32) {
+    if (s1.toLowerCase() === peg$c34) {
       peg$currPos += 4;
     } else {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e33); }
+      if (peg$silentFails === 0) { peg$fail(peg$e35); }
     }
     if (s1 !== peg$FAILED) {
       peg$savedPos = s0;
-      s1 = peg$f30();
+      s1 = peg$f31();
     }
     s0 = s1;
 
@@ -1337,81 +1374,81 @@ function peg$parse(input, options) {
       peg$currPos++;
     } else {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e35); }
+      if (peg$silentFails === 0) { peg$fail(peg$e37); }
     }
     if (s1 !== peg$FAILED) {
       peg$savedPos = s0;
-      s1 = peg$f31();
+      s1 = peg$f32();
     }
     s0 = s1;
     if (s0 === peg$FAILED) {
       s0 = peg$currPos;
-      if (input.substr(peg$currPos, 2) === peg$c33) {
-        s1 = peg$c33;
+      if (input.substr(peg$currPos, 2) === peg$c35) {
+        s1 = peg$c35;
         peg$currPos += 2;
       } else {
         s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$e36); }
+        if (peg$silentFails === 0) { peg$fail(peg$e38); }
       }
       if (s1 !== peg$FAILED) {
         peg$savedPos = s0;
-        s1 = peg$f32();
+        s1 = peg$f33();
       }
       s0 = s1;
       if (s0 === peg$FAILED) {
         s0 = peg$currPos;
-        if (input.substr(peg$currPos, 2) === peg$c34) {
-          s1 = peg$c34;
+        if (input.substr(peg$currPos, 2) === peg$c36) {
+          s1 = peg$c36;
           peg$currPos += 2;
         } else {
           s1 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$e37); }
+          if (peg$silentFails === 0) { peg$fail(peg$e39); }
         }
         if (s1 !== peg$FAILED) {
           peg$savedPos = s0;
-          s1 = peg$f33();
+          s1 = peg$f34();
         }
         s0 = s1;
         if (s0 === peg$FAILED) {
           s0 = peg$currPos;
           if (input.charCodeAt(peg$currPos) === 62) {
-            s1 = peg$c35;
+            s1 = peg$c37;
             peg$currPos++;
           } else {
             s1 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$e38); }
+            if (peg$silentFails === 0) { peg$fail(peg$e40); }
           }
           if (s1 !== peg$FAILED) {
             peg$savedPos = s0;
-            s1 = peg$f34();
+            s1 = peg$f35();
           }
           s0 = s1;
           if (s0 === peg$FAILED) {
             s0 = peg$currPos;
-            if (input.substr(peg$currPos, 2) === peg$c36) {
-              s1 = peg$c36;
+            if (input.substr(peg$currPos, 2) === peg$c38) {
+              s1 = peg$c38;
               peg$currPos += 2;
             } else {
               s1 = peg$FAILED;
-              if (peg$silentFails === 0) { peg$fail(peg$e39); }
+              if (peg$silentFails === 0) { peg$fail(peg$e41); }
             }
             if (s1 !== peg$FAILED) {
               peg$savedPos = s0;
-              s1 = peg$f35();
+              s1 = peg$f36();
             }
             s0 = s1;
             if (s0 === peg$FAILED) {
               s0 = peg$currPos;
               if (input.charCodeAt(peg$currPos) === 60) {
-                s1 = peg$c37;
+                s1 = peg$c39;
                 peg$currPos++;
               } else {
                 s1 = peg$FAILED;
-                if (peg$silentFails === 0) { peg$fail(peg$e40); }
+                if (peg$silentFails === 0) { peg$fail(peg$e42); }
               }
               if (s1 !== peg$FAILED) {
                 peg$savedPos = s0;
-                s1 = peg$f36();
+                s1 = peg$f37();
               }
               s0 = s1;
             }
@@ -1422,7 +1459,7 @@ function peg$parse(input, options) {
     peg$silentFails--;
     if (s0 === peg$FAILED) {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e34); }
+      if (peg$silentFails === 0) { peg$fail(peg$e36); }
     }
 
     return s0;
@@ -1439,7 +1476,7 @@ function peg$parse(input, options) {
       peg$currPos++;
     } else {
       s2 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e42); }
+      if (peg$silentFails === 0) { peg$fail(peg$e44); }
     }
     while (s2 !== peg$FAILED) {
       s1.push(s2);
@@ -1448,7 +1485,7 @@ function peg$parse(input, options) {
         peg$currPos++;
       } else {
         s2 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$e42); }
+        if (peg$silentFails === 0) { peg$fail(peg$e44); }
       }
     }
     s2 = input.charAt(peg$currPos);
@@ -1456,7 +1493,7 @@ function peg$parse(input, options) {
       peg$currPos++;
     } else {
       s2 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e43); }
+      if (peg$silentFails === 0) { peg$fail(peg$e45); }
     }
     if (s2 !== peg$FAILED) {
       s3 = [];
@@ -1465,7 +1502,7 @@ function peg$parse(input, options) {
         peg$currPos++;
       } else {
         s4 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$e44); }
+        if (peg$silentFails === 0) { peg$fail(peg$e46); }
       }
       while (s4 !== peg$FAILED) {
         s3.push(s4);
@@ -1474,7 +1511,7 @@ function peg$parse(input, options) {
           peg$currPos++;
         } else {
           s4 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$e44); }
+          if (peg$silentFails === 0) { peg$fail(peg$e46); }
         }
       }
       s4 = input.charAt(peg$currPos);
@@ -1482,7 +1519,7 @@ function peg$parse(input, options) {
         peg$currPos++;
       } else {
         s4 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$e43); }
+        if (peg$silentFails === 0) { peg$fail(peg$e45); }
       }
       if (s4 !== peg$FAILED) {
         s5 = [];
@@ -1491,7 +1528,7 @@ function peg$parse(input, options) {
           peg$currPos++;
         } else {
           s6 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$e45); }
+          if (peg$silentFails === 0) { peg$fail(peg$e47); }
         }
         while (s6 !== peg$FAILED) {
           s5.push(s6);
@@ -1500,11 +1537,11 @@ function peg$parse(input, options) {
             peg$currPos++;
           } else {
             s6 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$e45); }
+            if (peg$silentFails === 0) { peg$fail(peg$e47); }
           }
         }
         peg$savedPos = s0;
-        s0 = peg$f37(s1, s3, s5);
+        s0 = peg$f38(s1, s3, s5);
       } else {
         peg$currPos = s0;
         s0 = peg$FAILED;
@@ -1516,7 +1553,7 @@ function peg$parse(input, options) {
     peg$silentFails--;
     if (s0 === peg$FAILED) {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e41); }
+      if (peg$silentFails === 0) { peg$fail(peg$e43); }
     }
 
     return s0;
@@ -1533,7 +1570,7 @@ function peg$parse(input, options) {
       peg$currPos++;
     } else {
       s2 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e45); }
+      if (peg$silentFails === 0) { peg$fail(peg$e47); }
     }
     if (s2 !== peg$FAILED) {
       while (s2 !== peg$FAILED) {
@@ -1543,7 +1580,7 @@ function peg$parse(input, options) {
           peg$currPos++;
         } else {
           s2 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$e45); }
+          if (peg$silentFails === 0) { peg$fail(peg$e47); }
         }
       }
     } else {
@@ -1551,13 +1588,13 @@ function peg$parse(input, options) {
     }
     if (s1 !== peg$FAILED) {
       peg$savedPos = s0;
-      s1 = peg$f38(s1);
+      s1 = peg$f39(s1);
     }
     s0 = s1;
     peg$silentFails--;
     if (s0 === peg$FAILED) {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e46); }
+      if (peg$silentFails === 0) { peg$fail(peg$e48); }
     }
 
     return s0;
@@ -1569,7 +1606,7 @@ function peg$parse(input, options) {
     s0 = peg$currPos;
     s1 = peg$parse_();
     peg$savedPos = s0;
-    s1 = peg$f39();
+    s1 = peg$f40();
     s0 = s1;
 
     return s0;
@@ -1585,7 +1622,7 @@ function peg$parse(input, options) {
       peg$currPos++;
     } else {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e48); }
+      if (peg$silentFails === 0) { peg$fail(peg$e50); }
     }
     while (s1 !== peg$FAILED) {
       s0.push(s1);
@@ -1594,12 +1631,12 @@ function peg$parse(input, options) {
         peg$currPos++;
       } else {
         s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$e48); }
+        if (peg$silentFails === 0) { peg$fail(peg$e50); }
       }
     }
     peg$silentFails--;
     s1 = peg$FAILED;
-    if (peg$silentFails === 0) { peg$fail(peg$e47); }
+    if (peg$silentFails === 0) { peg$fail(peg$e49); }
 
     return s0;
   }
diff --git a/src/libs/SearchParser/autocompleteParser.peggy b/src/libs/SearchParser/autocompleteParser.peggy
index ddb472d2e2cc..8ed9e00c6869 100644
--- a/src/libs/SearchParser/autocompleteParser.peggy
+++ b/src/libs/SearchParser/autocompleteParser.peggy
@@ -67,6 +67,7 @@ autocompleteKey "key"
       / status
       / cardID
       / feed
+      / groupBy
     )
 
 identifier
diff --git a/src/libs/SearchParser/baseRules.peggy b/src/libs/SearchParser/baseRules.peggy
index c6f9bdbebebd..d141746e7d19 100644
--- a/src/libs/SearchParser/baseRules.peggy
+++ b/src/libs/SearchParser/baseRules.peggy
@@ -46,6 +46,7 @@ approved = "approved"i { return "approved"; }
 paid = "paid"i { return "paid"; }
 exported = "exported"i { return "exported"; }
 posted = "posted"i { return "posted"; }
+groupBy = "groupBy"i / "group-by"i { return "groupBy"; }
 feed = "feed"i { return "feed"; }
 
 operator "operator"
diff --git a/src/libs/SearchParser/searchParser.js b/src/libs/SearchParser/searchParser.js
index cedcd1af5991..446554bb4bc9 100644
--- a/src/libs/SearchParser/searchParser.js
+++ b/src/libs/SearchParser/searchParser.js
@@ -216,12 +216,14 @@ function peg$parse(input, options) {
   var peg$c29 = "paid";
   var peg$c30 = "exported";
   var peg$c31 = "posted";
-  var peg$c32 = "feed";
-  var peg$c33 = "!=";
-  var peg$c34 = ">=";
-  var peg$c35 = ">";
-  var peg$c36 = "<=";
-  var peg$c37 = "<";
+  var peg$c32 = "groupby";
+  var peg$c33 = "group-by";
+  var peg$c34 = "feed";
+  var peg$c35 = "!=";
+  var peg$c36 = ">=";
+  var peg$c37 = ">";
+  var peg$c38 = "<=";
+  var peg$c39 = "<";
 
   var peg$r0 = /^[^ \t\r\n\xA0]/;
   var peg$r1 = /^[:=]/;
@@ -266,22 +268,24 @@ function peg$parse(input, options) {
   var peg$e32 = peg$literalExpectation("paid", true);
   var peg$e33 = peg$literalExpectation("exported", true);
   var peg$e34 = peg$literalExpectation("posted", true);
-  var peg$e35 = peg$literalExpectation("feed", true);
-  var peg$e36 = peg$otherExpectation("operator");
-  var peg$e37 = peg$classExpectation([":", "="], false, false);
-  var peg$e38 = peg$literalExpectation("!=", false);
-  var peg$e39 = peg$literalExpectation(">=", false);
-  var peg$e40 = peg$literalExpectation(">", false);
-  var peg$e41 = peg$literalExpectation("<=", false);
-  var peg$e42 = peg$literalExpectation("<", false);
-  var peg$e43 = peg$otherExpectation("quote");
-  var peg$e44 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false);
-  var peg$e45 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false);
-  var peg$e46 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false);
-  var peg$e47 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false);
-  var peg$e48 = peg$otherExpectation("word");
-  var peg$e49 = peg$otherExpectation("whitespace");
-  var peg$e50 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false);
+  var peg$e35 = peg$literalExpectation("groupBy", true);
+  var peg$e36 = peg$literalExpectation("group-by", true);
+  var peg$e37 = peg$literalExpectation("feed", true);
+  var peg$e38 = peg$otherExpectation("operator");
+  var peg$e39 = peg$classExpectation([":", "="], false, false);
+  var peg$e40 = peg$literalExpectation("!=", false);
+  var peg$e41 = peg$literalExpectation(">=", false);
+  var peg$e42 = peg$literalExpectation(">", false);
+  var peg$e43 = peg$literalExpectation("<=", false);
+  var peg$e44 = peg$literalExpectation("<", false);
+  var peg$e45 = peg$otherExpectation("quote");
+  var peg$e46 = peg$classExpectation([" ", ",", "\"", "\u201D", "\u201C", "\t", "\n", "\r", "\xA0"], true, false);
+  var peg$e47 = peg$classExpectation(["\"", ["\u201C", "\u201D"]], false, false);
+  var peg$e48 = peg$classExpectation(["\"", "\u201D", "\u201C", "\r", "\n"], true, false);
+  var peg$e49 = peg$classExpectation([" ", ",", "\t", "\n", "\r", "\xA0"], true, false);
+  var peg$e50 = peg$otherExpectation("word");
+  var peg$e51 = peg$otherExpectation("whitespace");
+  var peg$e52 = peg$classExpectation([" ", "\t", "\r", "\n", "\xA0"], false, false);
 
   var peg$f0 = function(filters) { return applyDefaults(filters); };
   var peg$f1 = function(head, tail) {
@@ -368,18 +372,19 @@ function peg$parse(input, options) {
   var peg$f28 = function() { return "paid"; };
   var peg$f29 = function() { return "exported"; };
   var peg$f30 = function() { return "posted"; };
-  var peg$f31 = function() { return "feed"; };
-  var peg$f32 = function() { return "eq"; };
-  var peg$f33 = function() { return "neq"; };
-  var peg$f34 = function() { return "gte"; };
-  var peg$f35 = function() { return "gt"; };
-  var peg$f36 = function() { return "lte"; };
-  var peg$f37 = function() { return "lt"; };
-  var peg$f38 = function(start, inner, end) { //handle no-breaking space
+  var peg$f31 = function() { return "groupBy"; };
+  var peg$f32 = function() { return "feed"; };
+  var peg$f33 = function() { return "eq"; };
+  var peg$f34 = function() { return "neq"; };
+  var peg$f35 = function() { return "gte"; };
+  var peg$f36 = function() { return "gt"; };
+  var peg$f37 = function() { return "lte"; };
+  var peg$f38 = function() { return "lt"; };
+  var peg$f39 = function(start, inner, end) { //handle no-breaking space
       return [...start, '"', ...inner, '"', ...end].join("");
     };
-  var peg$f39 = function(chars) { return chars.join("").trim(); };
-  var peg$f40 = function() { return "and"; };
+  var peg$f40 = function(chars) { return chars.join("").trim(); };
+  var peg$f41 = function() { return "and"; };
   var peg$currPos = options.peg$currPos | 0;
   var peg$savedPos = peg$currPos;
   var peg$posDetailsCache = [{ line: 1, column: 1 }];
@@ -818,6 +823,9 @@ function peg$parse(input, options) {
           s1 = peg$parsesortOrder();
           if (s1 === peg$FAILED) {
             s1 = peg$parsepolicyID();
+            if (s1 === peg$FAILED) {
+              s1 = peg$parsegroupBy();
+            }
           }
         }
       }
@@ -1508,20 +1516,49 @@ function peg$parse(input, options) {
     return s0;
   }
 
+  function peg$parsegroupBy() {
+    var s0, s1;
+
+    s0 = input.substr(peg$currPos, 7);
+    if (s0.toLowerCase() === peg$c32) {
+      peg$currPos += 7;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e35); }
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = input.substr(peg$currPos, 8);
+      if (s1.toLowerCase() === peg$c33) {
+        peg$currPos += 8;
+      } else {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e36); }
+      }
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f31();
+      }
+      s0 = s1;
+    }
+
+    return s0;
+  }
+
   function peg$parsefeed() {
     var s0, s1;
 
     s0 = peg$currPos;
     s1 = input.substr(peg$currPos, 4);
-    if (s1.toLowerCase() === peg$c32) {
+    if (s1.toLowerCase() === peg$c34) {
       peg$currPos += 4;
     } else {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e35); }
+      if (peg$silentFails === 0) { peg$fail(peg$e37); }
     }
     if (s1 !== peg$FAILED) {
       peg$savedPos = s0;
-      s1 = peg$f31();
+      s1 = peg$f32();
     }
     s0 = s1;
 
@@ -1538,81 +1575,81 @@ function peg$parse(input, options) {
       peg$currPos++;
     } else {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e37); }
+      if (peg$silentFails === 0) { peg$fail(peg$e39); }
     }
     if (s1 !== peg$FAILED) {
       peg$savedPos = s0;
-      s1 = peg$f32();
+      s1 = peg$f33();
     }
     s0 = s1;
     if (s0 === peg$FAILED) {
       s0 = peg$currPos;
-      if (input.substr(peg$currPos, 2) === peg$c33) {
-        s1 = peg$c33;
+      if (input.substr(peg$currPos, 2) === peg$c35) {
+        s1 = peg$c35;
         peg$currPos += 2;
       } else {
         s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$e38); }
+        if (peg$silentFails === 0) { peg$fail(peg$e40); }
       }
       if (s1 !== peg$FAILED) {
         peg$savedPos = s0;
-        s1 = peg$f33();
+        s1 = peg$f34();
       }
       s0 = s1;
       if (s0 === peg$FAILED) {
         s0 = peg$currPos;
-        if (input.substr(peg$currPos, 2) === peg$c34) {
-          s1 = peg$c34;
+        if (input.substr(peg$currPos, 2) === peg$c36) {
+          s1 = peg$c36;
           peg$currPos += 2;
         } else {
           s1 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$e39); }
+          if (peg$silentFails === 0) { peg$fail(peg$e41); }
         }
         if (s1 !== peg$FAILED) {
           peg$savedPos = s0;
-          s1 = peg$f34();
+          s1 = peg$f35();
         }
         s0 = s1;
         if (s0 === peg$FAILED) {
           s0 = peg$currPos;
           if (input.charCodeAt(peg$currPos) === 62) {
-            s1 = peg$c35;
+            s1 = peg$c37;
             peg$currPos++;
           } else {
             s1 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$e40); }
+            if (peg$silentFails === 0) { peg$fail(peg$e42); }
           }
           if (s1 !== peg$FAILED) {
             peg$savedPos = s0;
-            s1 = peg$f35();
+            s1 = peg$f36();
           }
           s0 = s1;
           if (s0 === peg$FAILED) {
             s0 = peg$currPos;
-            if (input.substr(peg$currPos, 2) === peg$c36) {
-              s1 = peg$c36;
+            if (input.substr(peg$currPos, 2) === peg$c38) {
+              s1 = peg$c38;
               peg$currPos += 2;
             } else {
               s1 = peg$FAILED;
-              if (peg$silentFails === 0) { peg$fail(peg$e41); }
+              if (peg$silentFails === 0) { peg$fail(peg$e43); }
             }
             if (s1 !== peg$FAILED) {
               peg$savedPos = s0;
-              s1 = peg$f36();
+              s1 = peg$f37();
             }
             s0 = s1;
             if (s0 === peg$FAILED) {
               s0 = peg$currPos;
               if (input.charCodeAt(peg$currPos) === 60) {
-                s1 = peg$c37;
+                s1 = peg$c39;
                 peg$currPos++;
               } else {
                 s1 = peg$FAILED;
-                if (peg$silentFails === 0) { peg$fail(peg$e42); }
+                if (peg$silentFails === 0) { peg$fail(peg$e44); }
               }
               if (s1 !== peg$FAILED) {
                 peg$savedPos = s0;
-                s1 = peg$f37();
+                s1 = peg$f38();
               }
               s0 = s1;
             }
@@ -1623,7 +1660,7 @@ function peg$parse(input, options) {
     peg$silentFails--;
     if (s0 === peg$FAILED) {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e36); }
+      if (peg$silentFails === 0) { peg$fail(peg$e38); }
     }
 
     return s0;
@@ -1640,7 +1677,7 @@ function peg$parse(input, options) {
       peg$currPos++;
     } else {
       s2 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e44); }
+      if (peg$silentFails === 0) { peg$fail(peg$e46); }
     }
     while (s2 !== peg$FAILED) {
       s1.push(s2);
@@ -1649,7 +1686,7 @@ function peg$parse(input, options) {
         peg$currPos++;
       } else {
         s2 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$e44); }
+        if (peg$silentFails === 0) { peg$fail(peg$e46); }
       }
     }
     s2 = input.charAt(peg$currPos);
@@ -1657,7 +1694,7 @@ function peg$parse(input, options) {
       peg$currPos++;
     } else {
       s2 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e45); }
+      if (peg$silentFails === 0) { peg$fail(peg$e47); }
     }
     if (s2 !== peg$FAILED) {
       s3 = [];
@@ -1666,7 +1703,7 @@ function peg$parse(input, options) {
         peg$currPos++;
       } else {
         s4 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$e46); }
+        if (peg$silentFails === 0) { peg$fail(peg$e48); }
       }
       while (s4 !== peg$FAILED) {
         s3.push(s4);
@@ -1675,7 +1712,7 @@ function peg$parse(input, options) {
           peg$currPos++;
         } else {
           s4 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$e46); }
+          if (peg$silentFails === 0) { peg$fail(peg$e48); }
         }
       }
       s4 = input.charAt(peg$currPos);
@@ -1683,7 +1720,7 @@ function peg$parse(input, options) {
         peg$currPos++;
       } else {
         s4 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$e45); }
+        if (peg$silentFails === 0) { peg$fail(peg$e47); }
       }
       if (s4 !== peg$FAILED) {
         s5 = [];
@@ -1692,7 +1729,7 @@ function peg$parse(input, options) {
           peg$currPos++;
         } else {
           s6 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$e47); }
+          if (peg$silentFails === 0) { peg$fail(peg$e49); }
         }
         while (s6 !== peg$FAILED) {
           s5.push(s6);
@@ -1701,11 +1738,11 @@ function peg$parse(input, options) {
             peg$currPos++;
           } else {
             s6 = peg$FAILED;
-            if (peg$silentFails === 0) { peg$fail(peg$e47); }
+            if (peg$silentFails === 0) { peg$fail(peg$e49); }
           }
         }
         peg$savedPos = s0;
-        s0 = peg$f38(s1, s3, s5);
+        s0 = peg$f39(s1, s3, s5);
       } else {
         peg$currPos = s0;
         s0 = peg$FAILED;
@@ -1717,7 +1754,7 @@ function peg$parse(input, options) {
     peg$silentFails--;
     if (s0 === peg$FAILED) {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e43); }
+      if (peg$silentFails === 0) { peg$fail(peg$e45); }
     }
 
     return s0;
@@ -1734,7 +1771,7 @@ function peg$parse(input, options) {
       peg$currPos++;
     } else {
       s2 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e47); }
+      if (peg$silentFails === 0) { peg$fail(peg$e49); }
     }
     if (s2 !== peg$FAILED) {
       while (s2 !== peg$FAILED) {
@@ -1744,7 +1781,7 @@ function peg$parse(input, options) {
           peg$currPos++;
         } else {
           s2 = peg$FAILED;
-          if (peg$silentFails === 0) { peg$fail(peg$e47); }
+          if (peg$silentFails === 0) { peg$fail(peg$e49); }
         }
       }
     } else {
@@ -1752,13 +1789,13 @@ function peg$parse(input, options) {
     }
     if (s1 !== peg$FAILED) {
       peg$savedPos = s0;
-      s1 = peg$f39(s1);
+      s1 = peg$f40(s1);
     }
     s0 = s1;
     peg$silentFails--;
     if (s0 === peg$FAILED) {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e48); }
+      if (peg$silentFails === 0) { peg$fail(peg$e50); }
     }
 
     return s0;
@@ -1770,7 +1807,7 @@ function peg$parse(input, options) {
     s0 = peg$currPos;
     s1 = peg$parse_();
     peg$savedPos = s0;
-    s1 = peg$f40();
+    s1 = peg$f41();
     s0 = s1;
 
     return s0;
@@ -1786,7 +1823,7 @@ function peg$parse(input, options) {
       peg$currPos++;
     } else {
       s1 = peg$FAILED;
-      if (peg$silentFails === 0) { peg$fail(peg$e50); }
+      if (peg$silentFails === 0) { peg$fail(peg$e52); }
     }
     while (s1 !== peg$FAILED) {
       s0.push(s1);
@@ -1795,12 +1832,12 @@ function peg$parse(input, options) {
         peg$currPos++;
       } else {
         s1 = peg$FAILED;
-        if (peg$silentFails === 0) { peg$fail(peg$e50); }
+        if (peg$silentFails === 0) { peg$fail(peg$e52); }
       }
     }
     peg$silentFails--;
     s1 = peg$FAILED;
-    if (peg$silentFails === 0) { peg$fail(peg$e49); }
+    if (peg$silentFails === 0) { peg$fail(peg$e51); }
 
     return s0;
   }
diff --git a/src/libs/SearchParser/searchParser.peggy b/src/libs/SearchParser/searchParser.peggy
index 987c31d38372..f8bf86d129e4 100644
--- a/src/libs/SearchParser/searchParser.peggy
+++ b/src/libs/SearchParser/searchParser.peggy
@@ -131,7 +131,7 @@ key "key"
       / feed
     )
 
-defaultKey "default key" = @(type / status / sortBy / sortOrder / policyID)
+defaultKey "default key" = @(type / status / sortBy / sortOrder / policyID / groupBy)
 
 identifier
   = (","+)? parts:(quotedString / alphanumeric)|1.., ","+| empty:(","+)? {
diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts
index b0a2e83bcfc9..a7a71d15eebc 100644
--- a/src/libs/SearchQueryUtils.ts
+++ b/src/libs/SearchQueryUtils.ts
@@ -66,6 +66,7 @@ const UserFriendlyKeyMap: Record<SearchFilterKey | typeof CONST.SEARCH.SYNTAX_RO
     paid: 'paid',
     exported: 'exported',
     posted: 'posted',
+    groupBy: 'group-by',
 };
 
 /**
@@ -601,11 +602,15 @@ function buildUserReadableQueryString(
     cardList: OnyxTypes.CardList,
     cardFeedNamesWithType: CardFeedNamesWithType,
 ) {
-    const {type, status} = queryJSON;
+    const {type, status, groupBy} = queryJSON;
     const filters = queryJSON.flatFilters;
 
     let title = `type:${type} status:${Array.isArray(status) ? status.join(',') : status}`;
 
+    if (groupBy) {
+        title += ` group-by:${groupBy}`;
+    }
+
     for (const filterObject of filters) {
         const key = filterObject.key;
         const queryFilter = filterObject.filters;
@@ -648,20 +653,26 @@ function buildCannedSearchQuery({
     status = CONST.SEARCH.STATUS.EXPENSE.ALL,
     policyID,
     cardID,
+    groupBy,
 }: {
     type?: SearchDataTypes;
     status?: SearchStatus;
     policyID?: string;
     cardID?: string;
+    groupBy?: string;
 } = {}): SearchQueryString {
     let queryString = `type:${type} status:${Array.isArray(status) ? status.join(',') : status}`;
 
+    if (groupBy) {
+        queryString += ` group-by:${groupBy}`;
+    }
+
     if (policyID) {
-        queryString = `type:${type} status:${Array.isArray(status) ? status.join(',') : status} policyID:${policyID}`;
+        queryString += ` policyID:${policyID}`;
     }
 
     if (cardID) {
-        queryString = `type:${type} status:${Array.isArray(status) ? status.join(',') : status} expense-type:card card:${cardID}`;
+        queryString += ` expense-type:card card:${cardID}`;
     }
 
     // Parse the query to fill all default query fields with values
@@ -681,7 +692,7 @@ function isCannedSearchQuery(queryJSON: SearchQueryJSON) {
 }
 
 function isDefaultExpensesQuery(queryJSON: SearchQueryJSON) {
-    return queryJSON.type === CONST.SEARCH.DATA_TYPES.EXPENSE && queryJSON.status === CONST.SEARCH.STATUS.EXPENSE.ALL && !queryJSON.filters;
+    return queryJSON.type === CONST.SEARCH.DATA_TYPES.EXPENSE && queryJSON.status === CONST.SEARCH.STATUS.EXPENSE.ALL && !queryJSON.filters && !queryJSON.groupBy;
 }
 
 /**
diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts
index ca071da885b6..3c466cf19180 100644
--- a/src/libs/SearchUIUtils.ts
+++ b/src/libs/SearchUIUtils.ts
@@ -731,8 +731,8 @@ function createTypeMenuItems(allPolicies: OnyxCollection<OnyxTypes.Policy> | nul
             type: CONST.SEARCH.DATA_TYPES.EXPENSE,
             icon: Expensicons.Document,
             getRoute: (policyID?: string) => {
-                const query = buildCannedSearchQuery({policyID});
-                return ROUTES.SEARCH_ROOT.getRoute({query, groupBy: 'reports'});
+                const query = buildCannedSearchQuery({groupBy: CONST.SEARCH.GROUP_BY.REPORTS, policyID});
+                return ROUTES.SEARCH_ROOT.getRoute({query});
             },
         },
         {
diff --git a/src/libs/SidePaneUtils.ts b/src/libs/SidePaneUtils.ts
index 3c59fc3940d8..1b9cd04cdc4c 100644
--- a/src/libs/SidePaneUtils.ts
+++ b/src/libs/SidePaneUtils.ts
@@ -6,7 +6,7 @@
  * params: {workspaceID: '123', ruleID: '456'}
  * result: /workspaces/:workspaceID/rules/:ruleID
  */
-function substituteRouteParameters(route: string, params: Record<string, unknown>) {
+function substituteRouteParameters(route: string, params: Record<string, unknown>): string {
     let updatedRoute = route;
 
     function searchAndReplace(obj: Record<string, unknown>) {
@@ -19,14 +19,14 @@ function substituteRouteParameters(route: string, params: Record<string, unknown
             const value = obj[key];
             if (typeof value === 'object' && value !== null) {
                 searchAndReplace(value as Record<string, unknown>);
-            } else if (typeof value === 'string' && route.includes(value)) {
-                updatedRoute = updatedRoute.replace(value, `:${key}`);
+            } else if (typeof value === 'string') {
+                const regex = new RegExp(`\\b${value}\\b`, 'g');
+                updatedRoute = updatedRoute.replace(regex, `:${key}`);
             }
         }
     }
 
     searchAndReplace(params);
-
     return updatedRoute;
 }
 
diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts
index f8374bfa358e..771309fc4195 100644
--- a/src/libs/TransactionUtils/index.ts
+++ b/src/libs/TransactionUtils/index.ts
@@ -8,7 +8,7 @@ import Onyx from 'react-native-onyx';
 import type {ValueOf} from 'type-fest';
 import {getPolicyCategoriesData} from '@libs/actions/Policy/Category';
 import {getPolicyTagsData} from '@libs/actions/Policy/Tag';
-import type {TransactionMergeParams} from '@libs/API/parameters';
+import type {MergeDuplicatesParams} from '@libs/API/parameters';
 import {getCategoryDefaultTaxRate} from '@libs/CategoryUtils';
 import {convertToBackendAmount, getCurrencyDecimals} from '@libs/CurrencyUtils';
 import DateUtils from '@libs/DateUtils';
@@ -1402,7 +1402,7 @@ function buildNewTransactionAfterReviewingDuplicates(reviewDuplicateTransaction:
     };
 }
 
-function buildTransactionsMergeParams(reviewDuplicates: OnyxEntry<ReviewDuplicates>, originalTransaction: Partial<Transaction>): TransactionMergeParams {
+function buildMergeDuplicatesParams(reviewDuplicates: OnyxEntry<ReviewDuplicates>, originalTransaction: Partial<Transaction>): MergeDuplicatesParams {
     return {
         amount: -getAmount(originalTransaction as OnyxEntry<Transaction>, true),
         reportID: originalTransaction?.reportID,
@@ -1535,7 +1535,7 @@ export {
     compareDuplicateTransactionFields,
     getTransactionID,
     buildNewTransactionAfterReviewingDuplicates,
-    buildTransactionsMergeParams,
+    buildMergeDuplicatesParams,
     getReimbursable,
     isPayAtEndExpense,
     removeSettledAndApprovedTransactions,
diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts
index b05b1b6e786e..bedaebe90564 100644
--- a/src/libs/actions/IOU.ts
+++ b/src/libs/actions/IOU.ts
@@ -15,6 +15,7 @@ import type {
     CreateWorkspaceParams,
     DeleteMoneyRequestParams,
     DetachReceiptParams,
+    MergeDuplicatesParams,
     PayInvoiceParams,
     PayMoneyRequestParams,
     ReplaceReceiptParams,
@@ -28,7 +29,6 @@ import type {
     StartSplitBillParams,
     SubmitReportParams,
     TrackExpenseParams,
-    TransactionMergeParams,
     UnapproveExpenseReportParams,
     UpdateMoneyRequestParams,
 } from '@libs/API/parameters';
@@ -95,6 +95,7 @@ import {
     buildOptimisticMoneyRequestEntities,
     buildOptimisticMovedTrackedExpenseModifiedReportAction,
     buildOptimisticReportPreview,
+    buildOptimisticResolvedDuplicatesReportAction,
     buildOptimisticSubmittedReportAction,
     buildOptimisticUnapprovedReportAction,
     buildOptimisticUnHoldReportAction,
@@ -197,6 +198,20 @@ type IOURequestType = ValueOf<typeof CONST.IOU.REQUEST_TYPE>;
 
 type OneOnOneIOUReport = OnyxTypes.Report | undefined | null;
 
+type BaseTransactionParams = {
+    amount: number;
+    currency: string;
+    created: string;
+    merchant: string;
+    comment: string;
+    category?: string;
+    tag?: string;
+    taxCode?: string;
+    taxAmount?: number;
+    billable?: boolean;
+    customUnitRateID?: string;
+};
+
 type MoneyRequestInformation = {
     payerAccountID: number;
     payerEmail: string;
@@ -227,22 +242,15 @@ type TrackExpenseInformation = {
     actionableWhisperReportActionIDParam?: string;
     onyxData: OnyxData;
 };
-type TrackedExpenseTransactionParams = {
+
+type TrackedExpenseTransactionParams = Omit<BaseTransactionParams, 'taxCode' | 'taxAmount'> & {
+    waypoints?: string;
     transactionID: string | undefined;
-    amount: number;
-    currency: string;
-    comment: string;
-    merchant: string;
-    created: string;
+    receipt?: Receipt;
     taxCode: string;
     taxAmount: number;
-    category?: string;
-    tag?: string;
-    billable?: boolean;
-    receipt?: Receipt;
-    waypoints?: string;
-    customUnitRateID?: string;
 };
+
 type TrackedExpensePolicyParams = {
     policyID: string | undefined;
     isDraftPolicy?: boolean;
@@ -319,34 +327,19 @@ type GPSPoint = {
     long: number;
 };
 
-type RequestMoneyTransactionParams = {
+type RequestMoneyTransactionParams = Omit<BaseTransactionParams, 'comment'> & {
     attendees?: Attendee[];
-    amount: number;
-    currency: string;
-    comment?: string;
-    receipt?: Receipt;
-    category?: string;
-    tag?: string;
-    taxCode?: string;
-    taxAmount?: number;
-    billable?: boolean;
-    merchant: string;
-    created: string;
     actionableWhisperReportActionID?: string;
     linkedTrackedExpenseReportAction?: OnyxTypes.ReportAction;
     linkedTrackedExpenseReportID?: string;
+    receipt?: Receipt;
     waypoints?: WaypointCollection;
-    customUnitRateID?: string;
+    comment?: string;
 };
 
-type PerDiemExpenseTransactionParams = {
-    currency: string;
-    comment?: string;
-    category?: string;
-    tag?: string;
-    created: string;
+type PerDiemExpenseTransactionParams = Omit<BaseTransactionParams, 'amount' | 'merchant' | 'customUnitRateID' | 'taxAmount' | 'taxCode' | 'comment'> & {
     customUnit: TransactionCustomUnit;
-    billable?: boolean;
+    comment?: string;
 };
 
 type BasePolicyParams = {
@@ -431,21 +424,11 @@ type BuildOnyxDataForMoneyRequestParams = {
     optimisticParams: MoneyRequestOptimisticParams;
 };
 
-type DistanceRequestTransactionParams = {
-    comment: string;
-    created: string;
-    category?: string;
-    tag?: string;
-    taxCode?: string;
-    taxAmount?: number;
-    amount: number;
-    currency: string;
-    merchant: string;
-    billable?: boolean;
+type DistanceRequestTransactionParams = BaseTransactionParams & {
     validWaypoints: WaypointCollection;
-    customUnitRateID?: string;
     splitShares?: SplitShares;
 };
+
 type CreateDistanceRequestInformation = {
     report: OnyxEntry<OnyxTypes.Report>;
     participants: Participant[];
@@ -457,19 +440,9 @@ type CreateDistanceRequestInformation = {
     policyParams?: BasePolicyParams;
 };
 
-type CreateSplitsTransactionParams = {
-    amount: number;
-    comment: string;
-    currency: string;
-    merchant: string;
-    created: string;
-    category: string;
-    tag: string;
+type CreateSplitsTransactionParams = Omit<BaseTransactionParams, 'customUnitRateID'> & {
     splitShares: SplitShares;
-    billable?: boolean;
     iouRequestType?: IOURequestType;
-    taxCode?: string;
-    taxAmount?: number;
 };
 
 type CreateSplitsAndOnyxDataParams = {
@@ -9766,7 +9739,7 @@ function getIOUActionForTransactions(transactionIDList: Array<string | undefined
 }
 
 /** Merge several transactions into one by updating the fields of the one we want to keep and deleting the rest */
-function mergeDuplicates(params: TransactionMergeParams) {
+function mergeDuplicates(params: MergeDuplicatesParams) {
     const originalSelectedTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${params.transactionID}`];
 
     const optimisticTransactionData: OnyxUpdate = {
@@ -9895,6 +9868,25 @@ function mergeDuplicates(params: TransactionMergeParams) {
         }, {}),
     };
 
+    const optimisticReportAction = buildOptimisticResolvedDuplicatesReportAction();
+
+    const transactionThreadReportID = params.reportID ? getIOUActionForTransactions([params.transactionID], params.reportID).at(0)?.childReportID : undefined;
+    const optimisticReportActionData: OnyxUpdate = {
+        onyxMethod: Onyx.METHOD.MERGE,
+        key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`,
+        value: {
+            [optimisticReportAction.reportActionID]: optimisticReportAction,
+        },
+    };
+
+    const failureReportActionData: OnyxUpdate = {
+        onyxMethod: Onyx.METHOD.MERGE,
+        key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`,
+        value: {
+            [optimisticReportAction.reportActionID]: null,
+        },
+    };
+
     const optimisticData: OnyxUpdate[] = [];
     const failureData: OnyxUpdate[] = [];
 
@@ -9904,10 +9896,18 @@ function mergeDuplicates(params: TransactionMergeParams) {
         ...optimisticTransactionViolations,
         expenseReportOptimisticData,
         expenseReportActionsOptimisticData,
+        optimisticReportActionData,
+    );
+    failureData.push(
+        failureTransactionData,
+        ...failureTransactionDuplicatesData,
+        ...failureTransactionViolations,
+        expenseReportFailureData,
+        expenseReportActionsFailureData,
+        failureReportActionData,
     );
-    failureData.push(failureTransactionData, ...failureTransactionDuplicatesData, ...failureTransactionViolations, expenseReportFailureData, expenseReportActionsFailureData);
 
-    API.write(WRITE_COMMANDS.TRANSACTION_MERGE, params, {optimisticData, failureData});
+    API.write(WRITE_COMMANDS.MERGE_DUPLICATES, {...params, reportActionID: optimisticReportAction.reportActionID}, {optimisticData, failureData});
 }
 
 function updateLastLocationPermissionPrompt() {
@@ -9915,7 +9915,7 @@ function updateLastLocationPermissionPrompt() {
 }
 
 /** Instead of merging the duplicates, it updates the transaction we want to keep and puts the others on hold without deleting them */
-function resolveDuplicates(params: TransactionMergeParams) {
+function resolveDuplicates(params: MergeDuplicatesParams) {
     if (!params.transactionID) {
         return;
     }
diff --git a/src/libs/actions/PaymentMethods.ts b/src/libs/actions/PaymentMethods.ts
index 6c3d17b8236b..d70c0af6294e 100644
--- a/src/libs/actions/PaymentMethods.ts
+++ b/src/libs/actions/PaymentMethods.ts
@@ -398,7 +398,7 @@ function resetWalletTransferData() {
     });
 }
 
-function saveWalletTransferAccountTypeAndID(selectedAccountType: string, selectedAccountID: string) {
+function saveWalletTransferAccountTypeAndID(selectedAccountType: string | undefined, selectedAccountID: string | undefined) {
     Onyx.merge(ONYXKEYS.WALLET_TRANSFER, {selectedAccountType, selectedAccountID});
 }
 
diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts
index f130e29d4512..d0ca05c3620e 100644
--- a/src/libs/actions/Policy/Policy.ts
+++ b/src/libs/actions/Policy/Policy.ts
@@ -723,10 +723,14 @@ function clearSageIntacctErrorField(policyID: string | undefined, fieldName: str
     Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {connections: {intacct: {config: {errorFields: {[fieldName]: null}}}}});
 }
 
-function clearNetSuiteAutoSyncErrorField(policyID: string) {
+function clearNetSuiteAutoSyncErrorField(policyID: string | undefined) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {connections: {netsuite: {config: {errorFields: {autoSync: null}}}}});
 }
 
+function clearQuickbooksOnlineAutoSyncErrorField(policyID: string | undefined) {
+    Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {connections: {quickbooksOnline: {config: {errorFields: {autoSync: null}}}}});
+}
+
 function clearNSQSErrorField(policyID: string, fieldName: string) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {connections: {netsuiteQuickStart: {config: {errorFields: {[fieldName]: null}}}}});
 }
@@ -5026,6 +5030,7 @@ export {
     clearNetSuiteErrorField,
     clearNetSuitePendingField,
     clearNetSuiteAutoSyncErrorField,
+    clearQuickbooksOnlineAutoSyncErrorField,
     removeNetSuiteCustomFieldByIndex,
     clearWorkspaceReimbursementErrors,
     setWorkspaceCurrencyDefault,
diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts
index 754eb7f77eb8..4af279b0a637 100644
--- a/src/libs/actions/Report.ts
+++ b/src/libs/actions/Report.ts
@@ -64,6 +64,7 @@ import {getOldDotURLFromEnvironment} from '@libs/Environment/Environment';
 import getEnvironment from '@libs/Environment/getEnvironment';
 import type EnvironmentType from '@libs/Environment/getEnvironment/types';
 import * as ErrorUtils from '@libs/ErrorUtils';
+import {getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils';
 import fileDownload from '@libs/fileDownload';
 import HttpUtils from '@libs/HttpUtils';
 import isPublicScreenRoute from '@libs/isPublicScreenRoute';
@@ -77,6 +78,7 @@ import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
 import enhanceParameters from '@libs/Network/enhanceParameters';
 import type {NetworkStatus} from '@libs/NetworkConnection';
 import LocalNotification from '@libs/Notification/LocalNotification';
+import {rand64} from '@libs/NumberUtils';
 import Parser from '@libs/Parser';
 import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
 import * as PhoneNumber from '@libs/PhoneNumber';
@@ -85,15 +87,17 @@ import processReportIDDeeplink from '@libs/processReportIDDeeplink';
 import Pusher from '@libs/Pusher';
 import type {UserIsLeavingRoomEvent, UserIsTypingEvent} from '@libs/Pusher/types';
 import * as ReportActionsUtils from '@libs/ReportActionsUtils';
-import type {OptimisticAddCommentReportAction, OptimisticChatReport} from '@libs/ReportUtils';
+import type {OptimisticAddCommentReportAction, OptimisticChatReport, OptimisticNewReport} from '@libs/ReportUtils';
 import {
     buildOptimisticAddCommentReportAction,
     buildOptimisticChangeFieldAction,
+    buildOptimisticChangePolicyReportAction,
     buildOptimisticChatReport,
     buildOptimisticCreatedReportAction,
     buildOptimisticExportIntegrationAction,
     buildOptimisticGroupChatReport,
     buildOptimisticRenamedRoomReportAction,
+    buildOptimisticReportPreview,
     buildOptimisticRoomDescriptionUpdatedReportAction,
     buildOptimisticSelfDMReport,
     buildOptimisticTaskCommentReportAction,
@@ -104,15 +108,18 @@ import {
     findLastAccessedReport,
     findSelfDMReportID,
     formatReportLastMessageText,
+    generateReportID,
     getChatByParticipants,
     getChildReportNotificationPreference,
     getDefaultNotificationPreferenceForReport,
+    getExpenseReportStateAndStatus,
     getFieldViolation,
     getLastVisibleMessage,
     getOptimisticDataForParentReportAction,
     getOriginalReportID,
     getParsedComment,
     getPendingChatMembers,
+    getPolicyExpenseChat,
     getReportFieldKey,
     getReportIDFromLink,
     getReportLastMessage,
@@ -123,6 +130,7 @@ import {
     getRouteFromLink,
     isChatThread as isChatThreadReportUtils,
     isConciergeChatReport,
+    isExpenseReport,
     isGroupChat as isGroupChatReportUtils,
     isHiddenForCurrentUser,
     isMoneyRequestReport,
@@ -142,12 +150,15 @@ import type {Route} from '@src/ROUTES';
 import ROUTES from '@src/ROUTES';
 import INPUT_IDS from '@src/types/form/NewRoomForm';
 import type {
+    DismissedProductTraining,
     IntroSelected,
     InvitedEmailsToAccountIDs,
     NewGroupChatDraft,
     Onboarding,
     OnboardingPurpose,
+    PersonalDetails,
     PersonalDetailsList,
+    Policy,
     PolicyReportField,
     QuickAction,
     RecentlyUsedReportFields,
@@ -359,6 +370,12 @@ Onyx.connect({
     callback: (value) => (allReportDraftComments = value),
 });
 
+let nvpDismissedProductTraining: OnyxEntry<DismissedProductTraining>;
+Onyx.connect({
+    key: ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING,
+    callback: (value) => (nvpDismissedProductTraining = value),
+});
+
 let environmentURL: string;
 Environment.getEnvironmentURL().then((url: string) => (environmentURL = url));
 
@@ -2404,6 +2421,153 @@ function navigateToConciergeChat(shouldDismissModal = false, checkIfCurrentPageA
     }
 }
 
+function buildNewReportOptimisticData(policy: OnyxEntry<Policy>, reportID: string, reportActionID: string, reportName: string, creatorPersonalDetails: PersonalDetails) {
+    const {accountID, login} = creatorPersonalDetails;
+    const parentReport = getPolicyExpenseChat(accountID, policy?.id);
+    const {stateNum, statusNum} = getExpenseReportStateAndStatus(policy);
+    const timeOfCreation = DateUtils.getDBTime();
+    const reportPreviewActionID = rand64();
+
+    const optimisticDataValue: OptimisticNewReport = {
+        reportID,
+        policyID: policy?.id,
+        type: CONST.REPORT.TYPE.EXPENSE,
+        ownerAccountID: accountID,
+        reportName,
+        stateNum,
+        statusNum,
+        total: 0,
+        nonReimbursableTotal: 0,
+        participants: {},
+        lastVisibleActionCreated: timeOfCreation,
+    };
+
+    if (accountID) {
+        optimisticDataValue.participants = {
+            [accountID]: {
+                notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN,
+            },
+        };
+        optimisticDataValue.ownerAccountID = accountID;
+    }
+
+    const optimisticCreateAction = {
+        action: CONST.REPORT.ACTIONS.TYPE.CREATED,
+        accountEmail: login,
+        accountID,
+        created: timeOfCreation,
+        message: {
+            isNewDot: true,
+            lastModified: timeOfCreation,
+        },
+        reportActionID,
+        reportID,
+        sequenceNumber: 0,
+        pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
+    };
+
+    const createReportActionMessage = [
+        {
+            html: `${policy?.name} owes ${policy?.outputCurrency} 0.00`,
+            text: `${policy?.name} owes ${policy?.outputCurrency} 0.00`,
+            type: CONST.REPORT.MESSAGE.TYPE.COMMENT,
+        },
+    ];
+
+    const optimisticReportPreview = {
+        action: CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW,
+        actionName: CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW,
+        childReportName: reportName,
+        childReportID: reportID,
+        childType: CONST.REPORT.TYPE.EXPENSE,
+        created: timeOfCreation,
+        shouldShow: true,
+        actorAccountID: accountID,
+        automatic: false,
+        avatar: creatorPersonalDetails.avatar,
+        isAttachmentOnly: false,
+        reportActionID: reportPreviewActionID,
+        message: createReportActionMessage,
+        pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
+    };
+
+    const optimisticData: OnyxUpdate[] = [
+        {
+            onyxMethod: Onyx.METHOD.SET,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
+            value: optimisticDataValue,
+        },
+        {
+            onyxMethod: Onyx.METHOD.SET,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
+            value: {[reportActionID]: optimisticCreateAction},
+        },
+        {
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReport?.reportID}`,
+            value: {[reportActionID]: optimisticReportPreview},
+        },
+    ];
+
+    const failureData: OnyxUpdate[] = [
+        {
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
+            value: {errorFields: {create: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage')}},
+        },
+        {
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
+            value: {[reportActionID]: {errorFields: {create: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage')}}},
+        },
+    ];
+
+    const successData: OnyxUpdate[] = [
+        {
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
+            value: {
+                pendingAction: null,
+                errorFields: null,
+            },
+        },
+        {
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
+            value: {
+                [reportActionID]: {
+                    pendingAction: null,
+                    errorFields: null,
+                },
+            },
+        },
+        {
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReport?.reportID}`,
+            value: {[reportActionID]: {pendingAction: null}},
+        },
+    ];
+
+    return {optimisticData, successData, failureData};
+}
+
+function createNewReport(creatorPersonalDetails: PersonalDetails, policyID?: string) {
+    const policy = getPolicy(policyID);
+    const optimisticReportID = generateReportID();
+    const reportActionID = rand64();
+    // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+    const reportName = `${creatorPersonalDetails.firstName || 'User'}'s report`;
+
+    const {optimisticData, successData, failureData} = buildNewReportOptimisticData(policy, optimisticReportID, reportActionID, reportName, creatorPersonalDetails);
+
+    API.write(
+        WRITE_COMMANDS.CREATE_APP_REPORT,
+        {reportName, type: CONST.REPORT.TYPE.EXPENSE, policyID, reportID: optimisticReportID, reportActionID},
+        {optimisticData, successData, failureData},
+    );
+    return optimisticReportID;
+}
+
 /** Add a policy report (workspace room) optimistically and navigate to it. */
 function addPolicyReport(policyReport: OptimisticChatReport) {
     const createdReportAction = buildOptimisticCreatedReportAction(CONST.POLICY.OWNER_EMAIL_FAKE);
@@ -2961,7 +3125,7 @@ function openReportFromDeepLink(url: string) {
                             // Check if the report exists in the collection
                             const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
                             // If the report does not exist, navigate to the last accessed report or Concierge chat
-                            if (!report) {
+                            if (reportID && !report) {
                                 const lastAccessedReportID = findLastAccessedReport(false, shouldOpenOnAdminRoom(), undefined, reportID)?.reportID;
                                 if (lastAccessedReportID) {
                                     const lastAccessedReportRoute = ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID);
@@ -4698,6 +4862,228 @@ function clearDeleteTransactionNavigateBackUrl() {
     Onyx.merge(ONYXKEYS.NVP_DELETE_TRANSACTION_NAVIGATE_BACK_URL, null);
 }
 
+/**
+ * Dismisses the change report policy educational modal so that it doesn't show up again.
+ */
+function dismissChangePolicyModal() {
+    const date = new Date();
+    const optimisticData = [
+        {
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING,
+            value: {
+                [CONST.CHANGE_POLICY_TRAINING_MODAL]: DateUtils.getDBTime(date.valueOf()),
+            },
+        },
+    ];
+    API.write(WRITE_COMMANDS.DISMISS_PRODUCT_TRAINING, {name: CONST.CHANGE_POLICY_TRAINING_MODAL}, {optimisticData});
+}
+
+/**
+ * @private
+ * Builds a map of parentReportID to child report IDs for efficient traversal.
+ */
+function buildReportIDToThreadsReportIDsMap(): Record<string, string[]> {
+    const reportIDToThreadsReportIDsMap: Record<string, string[]> = {};
+    Object.values(allReports ?? {}).forEach((report) => {
+        if (!report?.parentReportID) {
+            return;
+        }
+        if (!reportIDToThreadsReportIDsMap[report.parentReportID]) {
+            reportIDToThreadsReportIDsMap[report.parentReportID] = [];
+        }
+        reportIDToThreadsReportIDsMap[report.parentReportID].push(report.reportID);
+    });
+    return reportIDToThreadsReportIDsMap;
+}
+
+/**
+ * @private
+ * Recursively updates the policyID for a report and all its child reports.
+ */
+function updatePolicyIdForReportAndThreads(
+    currentReportID: string,
+    policyID: string,
+    reportIDToThreadsReportIDsMap: Record<string, string[]>,
+    optimisticData: OnyxUpdate[],
+    failureData: OnyxUpdate[],
+) {
+    const currentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${currentReportID}`];
+    const originalPolicyID = currentReport?.policyID;
+
+    if (originalPolicyID) {
+        optimisticData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${currentReportID}`,
+            value: {policyID},
+        });
+        failureData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${currentReportID}`,
+            value: {policyID: originalPolicyID},
+        });
+    }
+
+    // Recursively process child reports for the current report
+    const childReportIDs = reportIDToThreadsReportIDsMap[currentReportID] || [];
+    childReportIDs.forEach((childReportID) => {
+        updatePolicyIdForReportAndThreads(childReportID, policyID, reportIDToThreadsReportIDsMap, optimisticData, failureData);
+    });
+}
+
+/**
+ * Changes the policy of a report and all its child reports, and moves the report to the new policy's workspace chat.
+ */
+function changeReportPolicy(reportID: string, policyID: string) {
+    if (!reportID || !policyID) {
+        return;
+    }
+    const reportToMove = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
+    if (!reportToMove || reportToMove?.policyID === policyID || !isExpenseReport(reportToMove)) {
+        return;
+    }
+
+    const optimisticData: OnyxUpdate[] = [];
+    const successData: OnyxUpdate[] = [];
+    const failureData: OnyxUpdate[] = [];
+
+    // 1. Optimistically set the policyID on the report (and all its threads)
+
+    // Preprocess reports to create a map of parentReportID to child reports list of reportIDs
+    const reportIDToThreadsReportIDsMap = buildReportIDToThreadsReportIDsMap();
+
+    // Recursively update the policyID of the report and all its child reports
+    updatePolicyIdForReportAndThreads(reportID, policyID, reportIDToThreadsReportIDsMap, optimisticData, failureData);
+
+    // 2. If the old workspace had a workspace chat, mark the report preview action as deleted
+    if (reportToMove?.parentReportID && reportToMove?.parentReportActionID) {
+        const oldReportPreviewAction = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportToMove?.parentReportID}`]?.[reportToMove?.parentReportActionID];
+        const deletedTime = DateUtils.getDBTime();
+        const firstMessage = Array.isArray(oldReportPreviewAction?.message) ? oldReportPreviewAction.message.at(0) : null;
+        const updatedReportPreviewAction = {
+            ...oldReportPreviewAction,
+            originalMessage: {
+                deleted: deletedTime,
+            },
+            ...(firstMessage && {
+                message: [
+                    {
+                        ...firstMessage,
+                        deleted: deletedTime,
+                    },
+                    ...(Array.isArray(oldReportPreviewAction?.message) ? oldReportPreviewAction.message.slice(1) : []),
+                ],
+            }),
+            ...(!Array.isArray(oldReportPreviewAction?.message) && {
+                message: {
+                    deleted: deletedTime,
+                },
+            }),
+        };
+
+        optimisticData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportToMove?.parentReportID}`,
+            value: {[reportToMove?.parentReportActionID]: updatedReportPreviewAction},
+        });
+        failureData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportToMove?.parentReportID}`,
+            value: {[reportToMove?.parentReportActionID]: oldReportPreviewAction},
+        });
+    }
+
+    // 3. Optimistically create a new REPORTPREVIEW reportAction with the newReportPreviewActionID
+    // and set it as a parent of the moved report
+    const policyExpenseChat = getPolicyExpenseChat(currentUserAccountID, policyID);
+    const optimisticReportPreviewAction = buildOptimisticReportPreview(policyExpenseChat, reportToMove);
+
+    if (policyExpenseChat) {
+        optimisticData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${policyExpenseChat.reportID}`,
+            value: {[optimisticReportPreviewAction.reportActionID]: optimisticReportPreviewAction},
+        });
+        successData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${policyExpenseChat.reportID}`,
+            value: {
+                [optimisticReportPreviewAction.reportActionID]: {
+                    pendingAction: null,
+                },
+            },
+        });
+        failureData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${policyExpenseChat.reportID}`,
+            value: {[optimisticReportPreviewAction.reportActionID]: null},
+        });
+
+        // Set the new report preview action as a parent of the moved report,
+        // and set the parentReportID on the moved report as the workspace chat reportID
+        optimisticData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
+            value: {parentReportActionID: optimisticReportPreviewAction.reportActionID, parentReportID: policyExpenseChat.reportID},
+        });
+        failureData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
+            value: {parentReportActionID: reportToMove.parentReportActionID, parentReportID: reportToMove.parentReportID},
+        });
+
+        // Set lastVisibleActionCreated
+        optimisticData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${policyExpenseChat.reportID}`,
+            value: {lastVisibleActionCreated: optimisticReportPreviewAction?.created},
+        });
+        failureData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${policyExpenseChat.reportID}`,
+            value: {lastVisibleActionCreated: policyExpenseChat.lastVisibleActionCreated},
+        });
+    }
+
+    // 4. Optimistically create a CHANGEPOLICY reportAction on the report using the reportActionID
+    const optimisticMovedReportAction = buildOptimisticChangePolicyReportAction(reportToMove.policyID, policyID);
+    optimisticData.push({
+        onyxMethod: Onyx.METHOD.MERGE,
+        key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportToMove.reportID}`,
+        value: {[optimisticMovedReportAction.reportActionID]: optimisticMovedReportAction},
+    });
+    successData.push({
+        onyxMethod: Onyx.METHOD.MERGE,
+        key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportToMove.reportID}`,
+        value: {
+            [optimisticMovedReportAction.reportActionID]: {
+                ...optimisticMovedReportAction,
+                pendingAction: null,
+            },
+        },
+    });
+    failureData.push({
+        onyxMethod: Onyx.METHOD.MERGE,
+        key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportToMove.reportID}`,
+        value: {[optimisticMovedReportAction.reportActionID]: null},
+    });
+
+    // Call the ChangeReportPolicy API endpoint
+    const params = {
+        reportID: reportToMove.reportID,
+        policyID,
+        reportPreviewReportActionID: optimisticReportPreviewAction.reportActionID,
+        changePolicyReportActionID: optimisticMovedReportAction.reportActionID,
+    };
+    API.write(WRITE_COMMANDS.CHANGE_REPORT_POLICY, params, {optimisticData, successData, failureData});
+
+    // 5. If the dismissedProductTraining.changeReportModal is not set,
+    // navigate to CHANGE_POLICY_EDUCATIONAL and a backTo param for the report page.
+    if (!nvpDismissedProductTraining?.[CONST.CHANGE_POLICY_TRAINING_MODAL]) {
+        Navigation.navigate(ROUTES.CHANGE_POLICY_EDUCATIONAL.getRoute(ROUTES.REPORT_WITH_ID.getRoute(reportToMove.reportID)));
+    }
+}
+
 export type {Video};
 
 export {
@@ -4716,6 +5102,7 @@ export {
     clearPrivateNotesError,
     clearReportFieldKeyErrors,
     completeOnboarding,
+    createNewReport,
     deleteReport,
     deleteReportActionDraft,
     deleteReportComment,
@@ -4793,4 +5180,6 @@ export {
     updateRoomVisibility,
     updateWriteCapability,
     prepareOnboardingOnyxData,
+    dismissChangePolicyModal,
+    changeReportPolicy,
 };
diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts
index 13a5876b381f..d193d786baee 100644
--- a/src/libs/actions/Session/index.ts
+++ b/src/libs/actions/Session/index.ts
@@ -223,7 +223,7 @@ function isExpiredSession(sessionCreationDate: number): boolean {
     return new Date().getTime() - sessionCreationDate >= CONST.SESSION_EXPIRATION_TIME_MS;
 }
 
-function signOutAndRedirectToSignIn(shouldResetToHome?: boolean, shouldStashSession?: boolean, killHybridApp = true) {
+function signOutAndRedirectToSignIn(shouldResetToHome?: boolean, shouldStashSession?: boolean, killHybridApp = true, shouldForceUseStashedSession?: boolean) {
     Log.info('Redirecting to Sign In because signOut() was called');
     hideContextMenu(false);
 
@@ -276,9 +276,10 @@ function signOutAndRedirectToSignIn(shouldResetToHome?: boolean, shouldStashSess
             [ONYXKEYS.STASHED_SESSION]: stashedSession,
         };
     }
-    // Now if this is a supportal access, we do not want to stash the current session and we have a
+
+    // Now if this is a supportal access or force use stashed session, we do not want to stash the current session and we have a
     // stashed session, then we need to restore the stashed session instead of completely logging out
-    if (isSupportal && !shouldStashSession && hasStashedSession()) {
+    if ((isSupportal || shouldForceUseStashedSession) && !shouldStashSession && hasStashedSession()) {
         onyxSetParams = {
             [ONYXKEYS.CREDENTIALS]: stashedCredentials,
             [ONYXKEYS.SESSION]: stashedSession,
@@ -291,13 +292,20 @@ function signOutAndRedirectToSignIn(shouldResetToHome?: boolean, shouldStashSess
     // Wait for signOut (if called), then redirect and update Onyx.
     signOutPromise
         .then((response) => {
-            Onyx.multiSet(onyxSetParams);
-
             if (response?.hasOldDotAuthCookies) {
                 Log.info('Redirecting to OldDot sign out');
-                asyncOpenURL(redirectToSignIn(), `${CONFIG.EXPENSIFY.EXPENSIFY_URL}${CONST.OLDDOT_URLS.SIGN_OUT}`, true, true);
+                asyncOpenURL(
+                    redirectToSignIn().then(() => {
+                        Onyx.multiSet(onyxSetParams);
+                    }),
+                    `${CONFIG.EXPENSIFY.EXPENSIFY_URL}${CONST.OLDDOT_URLS.SIGN_OUT}`,
+                    true,
+                    true,
+                );
             } else {
-                redirectToSignIn();
+                redirectToSignIn().then(() => {
+                    Onyx.multiSet(onyxSetParams);
+                });
             }
         })
         .catch((error: string) => Log.warn('Error during sign out process:', error));
diff --git a/src/libs/actions/SidePane.ts b/src/libs/actions/SidePane.ts
index bda6a27a0b74..21331116b310 100644
--- a/src/libs/actions/SidePane.ts
+++ b/src/libs/actions/SidePane.ts
@@ -3,27 +3,22 @@ import Onyx from 'react-native-onyx';
 import ONYXKEYS from '@src/ONYXKEYS';
 
 type Options = {
-    /** Whether to update the narrow layout along with the large screen layout */
-    shouldUpdateNarrowLayout?: boolean;
+    /** Determines whether the side pane should be open or closed */
+    isOpen?: boolean;
 
-    /** Whether to update only the narrow layout without affecting the large screen layout */
-    shouldOnlyUpdateNarrowLayout?: boolean;
+    /** Determines whether the side pane should be open or closed on narrow screens */
+    isOpenNarrowScreen?: boolean;
 };
 
-/**
- * Updates the side pane state in Onyx.
- *
- * @param isOpen - Determines whether the side pane should be open or closed.
- * @param [options] - Additional options for updating the layout.
- */
-function triggerSidePane(isOpen: boolean, {shouldUpdateNarrowLayout = false, shouldOnlyUpdateNarrowLayout = false}: Options = {}) {
+/** Updates the side pane state in Onyx */
+function triggerSidePane({isOpen, isOpenNarrowScreen}: Options) {
     const value: OnyxMergeInput<typeof ONYXKEYS.NVP_SIDE_PANE> = {};
 
-    if (!shouldOnlyUpdateNarrowLayout) {
+    if (isOpen !== undefined) {
         value.open = isOpen;
     }
-    if (shouldUpdateNarrowLayout || shouldOnlyUpdateNarrowLayout) {
-        value.openNarrowScreen = isOpen;
+    if (isOpenNarrowScreen !== undefined) {
+        value.openNarrowScreen = isOpenNarrowScreen;
     }
 
     Onyx.merge(ONYXKEYS.NVP_SIDE_PANE, value);
diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts
index 0c3fc2b251a2..d3282dc3a923 100644
--- a/src/libs/actions/Task.ts
+++ b/src/libs/actions/Task.ts
@@ -127,6 +127,7 @@ function createTaskAndNavigate(
     if (!parentReportID) {
         return;
     }
+
     const optimisticTaskReport = ReportUtils.buildOptimisticTaskReport(currentUserAccountID, parentReportID, assigneeAccountID, title, description, policyID);
 
     const assigneeChatReportID = assigneeChatReport?.reportID;
@@ -931,7 +932,11 @@ function startOutCreateTaskQuickAction(reportID: string, targetAccountID: number
 /**
  * Get the assignee data
  */
-function getAssignee(assigneeAccountID: number, personalDetails: OnyxEntry<OnyxTypes.PersonalDetailsList>): Assignee {
+function getAssignee(assigneeAccountID: number | undefined, personalDetails: OnyxEntry<OnyxTypes.PersonalDetailsList>): Assignee | undefined {
+    if (!assigneeAccountID) {
+        return;
+    }
+
     const details = personalDetails?.[assigneeAccountID];
 
     if (!details) {
diff --git a/src/libs/actions/connections/NetSuiteCommands.ts b/src/libs/actions/connections/NetSuiteCommands.ts
index bf5b2be4b4a0..f26885945d55 100644
--- a/src/libs/actions/connections/NetSuiteCommands.ts
+++ b/src/libs/actions/connections/NetSuiteCommands.ts
@@ -766,7 +766,10 @@ function updateNetSuiteExportToNextOpenPeriod(policyID: string, value: boolean,
     API.write(WRITE_COMMANDS.UPDATE_NETSUITE_EXPORT_TO_NEXT_OPEN_PERIOD, parameters, onyxData);
 }
 
-function updateNetSuiteAutoSync(policyID: string, value: boolean) {
+function updateNetSuiteAutoSync(policyID: string | undefined, value: boolean) {
+    if (!policyID) {
+        return;
+    }
     const optimisticData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
@@ -937,10 +940,13 @@ function updateNetSuiteExportReportsTo(
 }
 
 function updateNetSuiteAccountingMethod(
-    policyID: string,
+    policyID: string | undefined,
     accountingMethod: ValueOf<typeof COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD>,
     oldAccountingMethod: ValueOf<typeof COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD>,
 ) {
+    if (!policyID) {
+        return;
+    }
     const onyxData = updateNetSuiteOnyxData(policyID, CONST.NETSUITE_CONFIG.ACCOUNTING_METHOD, accountingMethod, oldAccountingMethod);
 
     const parameters = {
diff --git a/src/libs/actions/connections/QuickbooksOnline.ts b/src/libs/actions/connections/QuickbooksOnline.ts
index 05b6bb730069..1d32887daf99 100644
--- a/src/libs/actions/connections/QuickbooksOnline.ts
+++ b/src/libs/actions/connections/QuickbooksOnline.ts
@@ -1,7 +1,9 @@
+import type {CONST as COMMON_CONST} from 'expensify-common';
 import type {OnyxUpdate} from 'react-native-onyx';
 import Onyx from 'react-native-onyx';
+import type {ValueOf} from 'type-fest';
 import * as API from '@libs/API';
-import type {ConnectPolicyToAccountingIntegrationParams} from '@libs/API/parameters';
+import type {ConnectPolicyToAccountingIntegrationParams, UpdateQuickbooksOnlineAccountingMethodParams} from '@libs/API/parameters';
 import type UpdateQuickbooksOnlineAutoCreateVendorParams from '@libs/API/parameters/UpdateQuickbooksOnlineAutoCreateVendorParams';
 import type UpdateQuickbooksOnlineGenericTypeParams from '@libs/API/parameters/UpdateQuickbooksOnlineGenericTypeParams';
 import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
@@ -164,7 +166,10 @@ function buildOnyxDataForQuickbooksConfiguration<TSettingName extends keyof Conn
     };
 }
 
-function updateQuickbooksOnlineAutoSync<TSettingValue extends Connections['quickbooksOnline']['config']['autoSync']['enabled']>(policyID: string, settingValue: TSettingValue) {
+function updateQuickbooksOnlineAutoSync<TSettingValue extends Connections['quickbooksOnline']['config']['autoSync']['enabled']>(policyID: string | undefined, settingValue: TSettingValue) {
+    if (!policyID) {
+        return;
+    }
     const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.AUTO_SYNC, {enabled: settingValue}, {enabled: !settingValue});
 
     const parameters: UpdateQuickbooksOnlineGenericTypeParams = {
@@ -187,10 +192,13 @@ function updateQuickbooksOnlineEnableNewCategories<TSettingValue extends Connect
 }
 
 function updateQuickbooksOnlineAutoCreateVendor<TConfigUpdate extends Partial<Connections['quickbooksOnline']['config']>>(
-    policyID: string,
+    policyID: string | undefined,
     configUpdate: TConfigUpdate,
     configCurrentData: TConfigUpdate,
 ) {
+    if (!policyID) {
+        return;
+    }
     const onyxData = buildOnyxDataForMultipleQuickbooksConfigurations(policyID, configUpdate, configCurrentData);
 
     const parameters: UpdateQuickbooksOnlineAutoCreateVendorParams = {
@@ -203,7 +211,10 @@ function updateQuickbooksOnlineAutoCreateVendor<TConfigUpdate extends Partial<Co
     API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_AUTO_CREATE_VENDOR, parameters, onyxData);
 }
 
-function updateQuickbooksOnlineSyncPeople<TSettingValue extends Connections['quickbooksOnline']['config']['syncPeople']>(policyID: string, settingValue: TSettingValue) {
+function updateQuickbooksOnlineSyncPeople<TSettingValue extends Connections['quickbooksOnline']['config']['syncPeople']>(policyID: string | undefined, settingValue: TSettingValue) {
+    if (!policyID) {
+        return;
+    }
     const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE, settingValue, !settingValue);
 
     const parameters: UpdateQuickbooksOnlineGenericTypeParams = {
@@ -338,11 +349,11 @@ function updateQuickbooksOnlineNonReimbursableExpensesAccount<TSettingValue exte
 }
 
 function updateQuickbooksOnlineCollectionAccountID<TSettingValue extends QBOConnectionConfig['collectionAccountID']>(
-    policyID: string,
+    policyID: string | undefined,
     settingValue: TSettingValue,
     oldSettingValue?: TSettingValue,
 ) {
-    if (settingValue === oldSettingValue) {
+    if (settingValue === oldSettingValue || !policyID) {
         return;
     }
 
@@ -403,6 +414,24 @@ function updateQuickbooksOnlinePreferredExporter<TSettingValue extends Connectio
     API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_EXPORT, parameters, onyxData);
 }
 
+function updateQuickbooksOnlineAccountingMethod(
+    policyID: string | undefined,
+    accountingMethod: ValueOf<typeof COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD>,
+    oldAccountingMethod: ValueOf<typeof COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD>,
+) {
+    if (!policyID) {
+        return;
+    }
+    const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.ACCOUNTING_METHOD, accountingMethod, oldAccountingMethod);
+
+    const parameters: UpdateQuickbooksOnlineAccountingMethodParams = {
+        policyID,
+        accountingMethod,
+    };
+
+    API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD, parameters, onyxData);
+}
+
 export {
     getQuickbooksOnlineSetupLink,
     updateQuickbooksOnlineEnableNewCategories,
@@ -421,4 +450,5 @@ export {
     updateQuickbooksOnlineSyncClasses,
     updateQuickbooksOnlineSyncLocations,
     updateQuickbooksOnlineSyncCustomers,
+    updateQuickbooksOnlineAccountingMethod,
 };
diff --git a/src/libs/fileDownload/FileUtils.ts b/src/libs/fileDownload/FileUtils.ts
index 59deb4645ddb..12ca79edb09b 100644
--- a/src/libs/fileDownload/FileUtils.ts
+++ b/src/libs/fileDownload/FileUtils.ts
@@ -1,13 +1,15 @@
 import {Str} from 'expensify-common';
 import {Alert, Linking, Platform} from 'react-native';
 import ImageSize from 'react-native-image-size';
+import type {TupleToUnion} from 'type-fest';
 import type {FileObject} from '@components/AttachmentModal';
 import DateUtils from '@libs/DateUtils';
 import getPlatform from '@libs/getPlatform';
-import * as Localize from '@libs/Localize';
+import {translateLocal} from '@libs/Localize';
 import Log from '@libs/Log';
 import saveLastRoute from '@libs/saveLastRoute';
 import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
 import getImageManipulator from './getImageManipulator';
 import getImageResolution from './getImageResolution';
 import type {ReadFileAsync, SplitExtensionFromFileName} from './types';
@@ -18,13 +20,13 @@ import type {ReadFileAsync, SplitExtensionFromFileName} from './types';
  */
 function showSuccessAlert(successMessage?: string) {
     Alert.alert(
-        Localize.translateLocal('fileDownload.success.title'),
+        translateLocal('fileDownload.success.title'),
         // successMessage can be an empty string and we want to default to `Localize.translateLocal('fileDownload.success.message')`
         // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
-        successMessage || Localize.translateLocal('fileDownload.success.message'),
+        successMessage || translateLocal('fileDownload.success.message'),
         [
             {
-                text: Localize.translateLocal('common.ok'),
+                text: translateLocal('common.ok'),
                 style: 'cancel',
             },
         ],
@@ -36,9 +38,9 @@ function showSuccessAlert(successMessage?: string) {
  * Show alert on attachment download error
  */
 function showGeneralErrorAlert() {
-    Alert.alert(Localize.translateLocal('fileDownload.generalError.title'), Localize.translateLocal('fileDownload.generalError.message'), [
+    Alert.alert(translateLocal('fileDownload.generalError.title'), translateLocal('fileDownload.generalError.message'), [
         {
-            text: Localize.translateLocal('common.cancel'),
+            text: translateLocal('common.cancel'),
             style: 'cancel',
         },
     ]);
@@ -48,13 +50,13 @@ function showGeneralErrorAlert() {
  * Show alert on attachment download permissions error
  */
 function showPermissionErrorAlert() {
-    Alert.alert(Localize.translateLocal('fileDownload.permissionError.title'), Localize.translateLocal('fileDownload.permissionError.message'), [
+    Alert.alert(translateLocal('fileDownload.permissionError.title'), translateLocal('fileDownload.permissionError.message'), [
         {
-            text: Localize.translateLocal('common.cancel'),
+            text: translateLocal('common.cancel'),
             style: 'cancel',
         },
         {
-            text: Localize.translateLocal('common.settings'),
+            text: translateLocal('common.settings'),
             onPress: () => {
                 Linking.openSettings();
             },
@@ -67,15 +69,15 @@ function showPermissionErrorAlert() {
  */
 function showCameraPermissionsAlert() {
     Alert.alert(
-        Localize.translateLocal('attachmentPicker.cameraPermissionRequired'),
-        Localize.translateLocal('attachmentPicker.expensifyDoesntHaveAccessToCamera'),
+        translateLocal('attachmentPicker.cameraPermissionRequired'),
+        translateLocal('attachmentPicker.expensifyDoesntHaveAccessToCamera'),
         [
             {
-                text: Localize.translateLocal('common.cancel'),
+                text: translateLocal('common.cancel'),
                 style: 'cancel',
             },
             {
-                text: Localize.translateLocal('common.settings'),
+                text: translateLocal('common.settings'),
                 onPress: () => {
                     Linking.openSettings();
                     // In the case of ios, the App reloads when we update camera permission from settings
@@ -346,6 +348,36 @@ const createFile = (file: File): FileObject => {
     });
 };
 
+const validateReceipt = (file: FileObject, setUploadReceiptError: (isInvalid: boolean, title: TranslationPaths, reason: TranslationPaths) => void) => {
+    return validateImageForCorruption(file)
+        .then(() => {
+            const {fileExtension} = splitExtensionFromFileName(file?.name ?? '');
+            if (
+                !CONST.API_ATTACHMENT_VALIDATIONS.ALLOWED_RECEIPT_EXTENSIONS.includes(
+                    fileExtension.toLowerCase() as TupleToUnion<typeof CONST.API_ATTACHMENT_VALIDATIONS.ALLOWED_RECEIPT_EXTENSIONS>,
+                )
+            ) {
+                setUploadReceiptError(true, 'attachmentPicker.wrongFileType', 'attachmentPicker.notAllowedExtension');
+                return false;
+            }
+
+            if (!Str.isImage(file.name ?? '') && (file?.size ?? 0) > CONST.API_ATTACHMENT_VALIDATIONS.RECEIPT_MAX_SIZE) {
+                setUploadReceiptError(true, 'attachmentPicker.attachmentTooLarge', 'attachmentPicker.sizeExceededWithLimit');
+                return false;
+            }
+
+            if ((file?.size ?? 0) < CONST.API_ATTACHMENT_VALIDATIONS.MIN_SIZE) {
+                setUploadReceiptError(true, 'attachmentPicker.attachmentTooSmall', 'attachmentPicker.sizeNotMet');
+                return false;
+            }
+            return true;
+        })
+        .catch(() => {
+            setUploadReceiptError(true, 'attachmentPicker.attachmentError', 'attachmentPicker.errorWhileSelectingCorruptedAttachment');
+            return false;
+        });
+};
+
 export {
     showGeneralErrorAlert,
     showSuccessAlert,
@@ -367,4 +399,5 @@ export {
     getImageDimensionsAfterResize,
     resizeImageIfNeeded,
     createFile,
+    validateReceipt,
 };
diff --git a/src/pages/ChangePolicyEducationalModal.tsx b/src/pages/ChangePolicyEducationalModal.tsx
new file mode 100644
index 000000000000..ecc8d1fd4a76
--- /dev/null
+++ b/src/pages/ChangePolicyEducationalModal.tsx
@@ -0,0 +1,50 @@
+import React, {useCallback} from 'react';
+import ChangeWorkspaceMenuSectionList from '@components/ChangeWorkspaceMenuSectionList';
+import FeatureTrainingModal from '@components/FeatureTrainingModal';
+import * as Illustrations from '@components/Icon/Illustrations';
+import useBeforeRemove from '@hooks/useBeforeRemove';
+import useLocalize from '@hooks/useLocalize';
+import useStyleUtils from '@hooks/useStyleUtils';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {dismissChangePolicyModal} from '@libs/actions/Report';
+import colors from '@styles/theme/colors';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
+
+function ChangePolicyEducationalModal() {
+    const {translate} = useLocalize();
+    const styles = useThemeStyles();
+    const StyleUtils = useStyleUtils();
+
+    const onConfirm = useCallback(() => {
+        dismissChangePolicyModal();
+    }, []);
+
+    useBeforeRemove(onConfirm);
+
+    return (
+        <FeatureTrainingModal
+            title={translate('iou.changePolicyEducational.title')}
+            description={translate('iou.changePolicyEducational.description')}
+            confirmText={translate('common.buttonConfirm')}
+            image={Illustrations.ReceiptFairy}
+            imageWidth={variables.changePolicyEducationModalIconWidth}
+            imageHeight={variables.changePolicyEducationModalIconHeight}
+            contentFitImage="cover"
+            width={variables.changePolicyEducationModalWidth}
+            illustrationAspectRatio={CONST.ILLUSTRATION_ASPECT_RATIO}
+            illustrationInnerContainerStyle={[styles.alignItemsCenter, styles.justifyContentCenter, StyleUtils.getBackgroundColorStyle(colors.blue700)]}
+            modalInnerContainerStyle={styles.pt0}
+            illustrationOuterContainerStyle={styles.p0}
+            contentInnerContainerStyles={[styles.mb5, styles.gap2]}
+            onClose={onConfirm}
+            onConfirm={onConfirm}
+        >
+            <ChangeWorkspaceMenuSectionList />
+        </FeatureTrainingModal>
+    );
+}
+
+ChangePolicyEducationalModal.displayName = 'ChangePolicyEducationalModal';
+
+export default ChangePolicyEducationalModal;
diff --git a/src/pages/Debug/Report/DebugReportActions.tsx b/src/pages/Debug/Report/DebugReportActions.tsx
index e86befd81217..792df8bfd561 100644
--- a/src/pages/Debug/Report/DebugReportActions.tsx
+++ b/src/pages/Debug/Report/DebugReportActions.tsx
@@ -8,6 +8,7 @@ import useDebouncedState from '@hooks/useDebouncedState';
 import useLocalize from '@hooks/useLocalize';
 import useThemeStyles from '@hooks/useThemeStyles';
 import Navigation from '@libs/Navigation/Navigation';
+import {getHeaderMessageForNonUserList} from '@libs/OptionsListUtils';
 import Parser from '@libs/Parser';
 import {getOriginalMessage, getReportActionMessage, getReportActionMessageText, getSortedReportActionsForDisplay, isCreatedAction} from '@libs/ReportActionsUtils';
 import {canUserPerformWriteAction, formatReportLastMessageText} from '@libs/ReportUtils';
@@ -85,6 +86,7 @@ function DebugReportActions({reportID}: DebugReportActionsProps) {
                 listItemTitleStyles={styles.fontWeightNormal}
                 textInputValue={searchValue}
                 textInputLabel={translate('common.search')}
+                headerMessage={getHeaderMessageForNonUserList(searchedReportActions.length > 0, debouncedSearchValue)}
                 onChangeText={setSearchValue}
                 onSelectRow={(item) => Navigation.navigate(ROUTES.DEBUG_REPORT_ACTION.getRoute(reportID, item.reportActionID))}
                 ListItem={RadioListItem}
diff --git a/src/pages/ErrorPage/UpdateRequiredView.tsx b/src/pages/ErrorPage/UpdateRequiredView.tsx
index c2d447da63e7..ac7a7237b0c8 100644
--- a/src/pages/ErrorPage/UpdateRequiredView.tsx
+++ b/src/pages/ErrorPage/UpdateRequiredView.tsx
@@ -26,7 +26,7 @@ function UpdateRequiredView() {
     const isStandaloneNewAppProduction = isProduction && !CONFIG.IS_HYBRID_APP;
 
     return (
-        <View style={[styles.appBG, styles.h100, StyleUtils.getSafeAreaPadding(insets)]}>
+        <View style={[styles.appBG, styles.h100, StyleUtils.getPlatformSafeAreaPadding(insets)]}>
             <HeaderGap />
             <View style={[styles.pt5, styles.ph5, styles.updateRequiredViewHeader]}>
                 <Header title={translate('updateRequiredView.updateRequired')} />
diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx
index f49b50da3c6a..6c14fcc0d237 100755
--- a/src/pages/NewChatPage.tsx
+++ b/src/pages/NewChatPage.tsx
@@ -22,8 +22,8 @@ import useLocalize from '@hooks/useLocalize';
 import useNetwork from '@hooks/useNetwork';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
 import useSafeAreaInsets from '@hooks/useSafeAreaInsets';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
 import useThemeStyles from '@hooks/useThemeStyles';
 import {navigateToAndOpenReport, searchInServer, setGroupDraft} from '@libs/actions/Report';
 import {canUseTouchScreen} from '@libs/DeviceCapabilities';
@@ -148,7 +148,7 @@ function NewChatPage() {
     const styles = useThemeStyles();
     const personalData = useCurrentUserPersonalDetails();
     const {top} = useSafeAreaInsets();
-    const {insets, safeAreaPaddingBottomStyle} = useStyledSafeAreaInsets();
+    const {insets, safeAreaPaddingBottomStyle} = useSafeAreaPaddings();
     const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false});
     const selectionListRef = useRef<SelectionListHandle>(null);
 
diff --git a/src/pages/NewReportWorkspaceSelectionPage.tsx b/src/pages/NewReportWorkspaceSelectionPage.tsx
new file mode 100644
index 000000000000..554a3a378893
--- /dev/null
+++ b/src/pages/NewReportWorkspaceSelectionPage.tsx
@@ -0,0 +1,135 @@
+import React, {useCallback, useMemo} from 'react';
+import {useOnyx} from 'react-native-onyx';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import type {ListItem, SectionListDataType} from '@components/SelectionList/types';
+import UserListItem from '@components/SelectionList/UserListItem';
+import Text from '@components/Text';
+import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
+import useDebouncedState from '@hooks/useDebouncedState';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {createNewReport} from '@libs/actions/Report';
+import Navigation from '@libs/Navigation/Navigation';
+import {getHeaderMessageForNonUserList} from '@libs/OptionsListUtils';
+import {isPolicyAdmin, shouldShowPolicy} from '@libs/PolicyUtils';
+import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import {isEmptyObject} from '@src/types/utils/EmptyObject';
+
+type WorkspaceListItem = {
+    text: string;
+    policyID?: string;
+    isPolicyAdmin?: boolean;
+} & ListItem;
+
+function NewReportWorkspaceSelectionPage() {
+    const {isOffline} = useNetwork();
+    const styles = useThemeStyles();
+    const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
+    const {translate} = useLocalize();
+
+    const [policies, fetchStatus] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
+    const currentUserPersonalDetails = useCurrentUserPersonalDetails();
+    const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP);
+    const shouldShowLoadingIndicator = isLoadingApp && !isOffline;
+
+    const selectPolicy = useCallback(
+        (policyID?: string) => {
+            if (!policyID) {
+                return;
+            }
+            const createdReportID = createNewReport(currentUserPersonalDetails, policyID);
+            Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: createdReportID, backTo: Navigation.getActiveRoute()}), {forceReplace: true});
+        },
+        [currentUserPersonalDetails],
+    );
+
+    const usersWorkspaces = useMemo<WorkspaceListItem[]>(() => {
+        if (!policies || isEmptyObject(policies)) {
+            return [];
+        }
+
+        return Object.values(policies)
+            .filter((policy) => shouldShowPolicy(policy, !!isOffline, currentUserPersonalDetails?.login) && !policy?.isJoinRequestPending && policy?.isPolicyExpenseChatEnabled)
+            .map((policy) => ({
+                text: policy?.name ?? '',
+                policyID: policy?.id,
+                icons: [
+                    {
+                        source: policy?.avatarURL ? policy.avatarURL : getDefaultWorkspaceAvatar(policy?.name),
+                        fallbackIcon: Expensicons.FallbackWorkspaceAvatar,
+                        name: policy?.name,
+                        type: CONST.ICON_TYPE_WORKSPACE,
+                        id: policy?.id,
+                    },
+                ],
+                keyForList: policy?.id,
+                isPolicyAdmin: isPolicyAdmin(policy),
+                shouldSyncFocus: true,
+            }))
+            .sort((a, b) => a.text.localeCompare(b.text.toLowerCase()));
+    }, [policies, isOffline, currentUserPersonalDetails?.login]);
+
+    const filteredAndSortedUserWorkspaces = useMemo<WorkspaceListItem[]>(
+        () => usersWorkspaces.filter((policy) => policy.text?.toLowerCase().includes(debouncedSearchTerm?.toLowerCase() ?? '')),
+        [debouncedSearchTerm, usersWorkspaces],
+    );
+
+    const sections = useMemo(() => {
+        const options: Array<SectionListDataType<WorkspaceListItem>> = [
+            {
+                data: filteredAndSortedUserWorkspaces,
+                shouldShow: true,
+            },
+        ];
+        return options;
+    }, [filteredAndSortedUserWorkspaces]);
+
+    const areResultsFound = filteredAndSortedUserWorkspaces.length > 0;
+    const headerMessage = getHeaderMessageForNonUserList(areResultsFound, debouncedSearchTerm);
+
+    return (
+        <ScreenWrapper
+            testID={NewReportWorkspaceSelectionPage.displayName}
+            includeSafeAreaPaddingBottom
+            shouldEnableMaxHeight
+        >
+            {({didScreenTransitionEnd}) => (
+                <>
+                    <HeaderWithBackButton
+                        title={translate('report.newReport.createReport')}
+                        onBackButtonPress={Navigation.goBack}
+                    />
+                    {shouldShowLoadingIndicator ? (
+                        <FullScreenLoadingIndicator style={[styles.flex1, styles.pRelative]} />
+                    ) : (
+                        <>
+                            <Text style={[styles.ph5, styles.mb3]}>{translate('report.newReport.chooseWorkspace')}</Text>
+                            <SelectionList<WorkspaceListItem>
+                                ListItem={UserListItem}
+                                sections={sections}
+                                onSelectRow={(option) => selectPolicy(option.policyID)}
+                                textInputLabel={usersWorkspaces.length >= CONST.STANDARD_LIST_ITEM_LIMIT ? translate('common.search') : undefined}
+                                textInputValue={searchTerm}
+                                onChangeText={setSearchTerm}
+                                headerMessage={headerMessage}
+                                showLoadingPlaceholder={fetchStatus.status === 'loading' || !didScreenTransitionEnd}
+                            />
+                        </>
+                    )}
+                </>
+            )}
+        </ScreenWrapper>
+    );
+}
+
+NewReportWorkspaceSelectionPage.displayName = 'NewReportWorkspaceSelectionPage';
+
+export default NewReportWorkspaceSelectionPage;
diff --git a/src/pages/ReimbursementAccount/NonUSD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormSubSteps/Confirmation.tsx b/src/pages/ReimbursementAccount/NonUSD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormSubSteps/Confirmation.tsx
index 2c1467ec5b69..696ebe4fc489 100644
--- a/src/pages/ReimbursementAccount/NonUSD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormSubSteps/Confirmation.tsx
+++ b/src/pages/ReimbursementAccount/NonUSD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormSubSteps/Confirmation.tsx
@@ -1,14 +1,8 @@
-import React from 'react';
-import {View} from 'react-native';
+import React, {useMemo} from 'react';
 import {useOnyx} from 'react-native-onyx';
-import Button from '@components/Button';
-import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
-import SafeAreaConsumer from '@components/SafeAreaConsumer';
-import ScrollView from '@components/ScrollView';
-import Text from '@components/Text';
+import ConfirmationStep from '@components/SubStepForms/ConfirmationStep';
 import useLocalize from '@hooks/useLocalize';
 import type {SubStepProps} from '@hooks/useSubStep/types';
-import useThemeStyles from '@hooks/useThemeStyles';
 import getNeededDocumentsStatusForBeneficialOwner from '@pages/ReimbursementAccount/NonUSD/utils/getNeededDocumentsStatusForBeneficialOwner';
 import getValuesForBeneficialOwner from '@pages/ReimbursementAccount/NonUSD/utils/getValuesForBeneficialOwner';
 import CONST from '@src/CONST';
@@ -19,12 +13,11 @@ type ConfirmationProps = SubStepProps & {ownerBeingModifiedID: string};
 
 const {PREFIX, COUNTRY} = CONST.NON_USD_BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.BENEFICIAL_OWNER_DATA;
 
-function Confirmation({onNext, onMove, ownerBeingModifiedID}: ConfirmationProps) {
+function Confirmation({onNext, onMove, isEditing, ownerBeingModifiedID}: ConfirmationProps) {
     const {translate} = useLocalize();
-    const styles = useThemeStyles();
     const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
     const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT);
-    const values = getValuesForBeneficialOwner(ownerBeingModifiedID, reimbursementAccountDraft);
+    const values = useMemo(() => getValuesForBeneficialOwner(ownerBeingModifiedID, reimbursementAccountDraft), [ownerBeingModifiedID, reimbursementAccountDraft]);
     const beneficialOwnerCountryInputID = `${PREFIX}_${ownerBeingModifiedID}_${COUNTRY}` as const;
     const beneficialOwnerCountry = String(reimbursementAccountDraft?.[beneficialOwnerCountryInputID] ?? '');
     const policyID = reimbursementAccount?.achData?.policyID;
@@ -33,108 +26,134 @@ function Confirmation({onNext, onMove, ownerBeingModifiedID}: ConfirmationProps)
     const countryStepCountryValue = reimbursementAccountDraft?.[INPUT_IDS.ADDITIONAL_DATA.COUNTRY] ?? '';
     const isDocumentNeededStatus = getNeededDocumentsStatusForBeneficialOwner(currency, countryStepCountryValue, beneficialOwnerCountry);
 
+    const summaryItems = useMemo(
+        () => [
+            {
+                title: `${values.firstName} ${values.lastName}`,
+                description: translate('ownershipInfoStep.legalName'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(0);
+                },
+            },
+            {
+                title: values.ownershipPercentage,
+                description: translate('ownershipInfoStep.ownershipPercentage'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(1);
+                },
+            },
+            {
+                title: values.dob,
+                description: translate('common.dob'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(2);
+                },
+            },
+            ...(beneficialOwnerCountry === CONST.COUNTRY.US
+                ? [
+                      {
+                          title: values.ssnLast4,
+                          description: translate('ownershipInfoStep.last4'),
+                          shouldShowRightIcon: true,
+                          onPress: () => {
+                              onMove(4);
+                          },
+                      },
+                  ]
+                : []),
+            {
+                title: `${values.street}, ${values.city}, ${values.state} ${values.zipCode}`,
+                description: translate('ownershipInfoStep.address'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(3);
+                },
+            },
+            ...(isDocumentNeededStatus.isProofOfOwnershipNeeded
+                ? [
+                      {
+                          title: values.proofOfOwnership.map((file) => file.name).join(', '),
+                          description: translate('ownershipInfoStep.proofOfBeneficialOwner'),
+                          shouldShowRightIcon: true,
+                          onPress: () => {
+                              onMove(5);
+                          },
+                      },
+                  ]
+                : []),
+            ...(isDocumentNeededStatus.isCopyOfIDNeeded
+                ? [
+                      {
+                          title: values.copyOfID.map((file) => file.name).join(', '),
+                          description: translate('ownershipInfoStep.copyOfID'),
+                          shouldShowRightIcon: true,
+                          onPress: () => {
+                              onMove(5);
+                          },
+                      },
+                  ]
+                : []),
+            ...(isDocumentNeededStatus.isProofOfAddressNeeded
+                ? [
+                      {
+                          title: values.addressProof.map((file) => file.name).join(', '),
+                          description: translate('ownershipInfoStep.proofOfAddress'),
+                          shouldShowRightIcon: true,
+                          onPress: () => {
+                              onMove(5);
+                          },
+                      },
+                  ]
+                : []),
+            ...(isDocumentNeededStatus.isCodiceFiscaleNeeded
+                ? [
+                      {
+                          title: values.codiceFisacle.map((file) => file.name).join(', '),
+                          description: translate('ownershipInfoStep.codiceFiscale'),
+                          shouldShowRightIcon: true,
+                          onPress: () => {
+                              onMove(5);
+                          },
+                      },
+                  ]
+                : []),
+        ],
+        [
+            beneficialOwnerCountry,
+            isDocumentNeededStatus.isCodiceFiscaleNeeded,
+            isDocumentNeededStatus.isCopyOfIDNeeded,
+            isDocumentNeededStatus.isProofOfAddressNeeded,
+            isDocumentNeededStatus.isProofOfOwnershipNeeded,
+            onMove,
+            translate,
+            values.addressProof,
+            values.city,
+            values.codiceFisacle,
+            values.copyOfID,
+            values.dob,
+            values.firstName,
+            values.lastName,
+            values.ownershipPercentage,
+            values.proofOfOwnership,
+            values.ssnLast4,
+            values.state,
+            values.street,
+            values.zipCode,
+        ],
+    );
+
     return (
-        <SafeAreaConsumer>
-            {({safeAreaPaddingBottomStyle}) => (
-                <ScrollView
-                    style={styles.pt0}
-                    contentContainerStyle={[styles.flexGrow1, safeAreaPaddingBottomStyle]}
-                >
-                    <Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mb3]}>{translate('ownershipInfoStep.letsDoubleCheck')}</Text>
-                    <MenuItemWithTopDescription
-                        description={translate('ownershipInfoStep.legalName')}
-                        title={`${values.firstName} ${values.lastName}`}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(0);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('ownershipInfoStep.ownershipPercentage')}
-                        title={values.ownershipPercentage}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(1);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('common.dob')}
-                        title={values.dob}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(2);
-                        }}
-                    />
-                    {beneficialOwnerCountry === CONST.COUNTRY.US && (
-                        <MenuItemWithTopDescription
-                            description={translate('ownershipInfoStep.last4')}
-                            title={values.ssnLast4}
-                            shouldShowRightIcon
-                            onPress={() => {
-                                onMove(4);
-                            }}
-                        />
-                    )}
-                    <MenuItemWithTopDescription
-                        description={translate('ownershipInfoStep.address')}
-                        title={`${values.street}, ${values.city}, ${values.state} ${values.zipCode}`}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(3);
-                        }}
-                    />
-                    {isDocumentNeededStatus.isProofOfOwnershipNeeded && values.proofOfOwnership.length > 0 && (
-                        <MenuItemWithTopDescription
-                            description={translate('ownershipInfoStep.proofOfBeneficialOwner')}
-                            title={values.proofOfOwnership.map((file) => file.name).join(', ')}
-                            shouldShowRightIcon
-                            onPress={() => {
-                                onMove(5);
-                            }}
-                        />
-                    )}
-                    {isDocumentNeededStatus.isCopyOfIDNeeded && values.copyOfID.length > 0 && (
-                        <MenuItemWithTopDescription
-                            description={translate('ownershipInfoStep.copyOfID')}
-                            title={values.copyOfID.map((file) => file.name).join(', ')}
-                            shouldShowRightIcon
-                            onPress={() => {
-                                onMove(5);
-                            }}
-                        />
-                    )}
-                    {isDocumentNeededStatus.isProofOfAddressNeeded && values.addressProof.length > 0 && (
-                        <MenuItemWithTopDescription
-                            description={translate('ownershipInfoStep.proofOfAddress')}
-                            title={values.addressProof.map((file) => file.name).join(', ')}
-                            shouldShowRightIcon
-                            onPress={() => {
-                                onMove(5);
-                            }}
-                        />
-                    )}
-                    {isDocumentNeededStatus.isCodiceFiscaleNeeded && values.codiceFisacle.length > 0 && (
-                        <MenuItemWithTopDescription
-                            description={translate('ownershipInfoStep.codiceFiscale')}
-                            title={values.codiceFisacle.map((file) => file.name).join(', ')}
-                            shouldShowRightIcon
-                            onPress={() => {
-                                onMove(5);
-                            }}
-                        />
-                    )}
-                    <View style={[styles.ph5, styles.pb5, styles.flexGrow1, styles.justifyContentEnd]}>
-                        <Button
-                            success
-                            style={[styles.w100]}
-                            onPress={onNext}
-                            large
-                            text={translate('common.confirm')}
-                        />
-                    </View>
-                </ScrollView>
-            )}
-        </SafeAreaConsumer>
+        <ConfirmationStep
+            isEditing={isEditing}
+            onNext={onNext}
+            onMove={onMove}
+            pageTitle={translate('ownershipInfoStep.letsDoubleCheck')}
+            summaryItems={summaryItems}
+            showOnfidoLinks={false}
+        />
     );
 }
 
diff --git a/src/pages/ReimbursementAccount/NonUSD/BusinessInfo/subSteps/Confirmation.tsx b/src/pages/ReimbursementAccount/NonUSD/BusinessInfo/subSteps/Confirmation.tsx
index 7a54d5ffca2b..e377f12240e4 100644
--- a/src/pages/ReimbursementAccount/NonUSD/BusinessInfo/subSteps/Confirmation.tsx
+++ b/src/pages/ReimbursementAccount/NonUSD/BusinessInfo/subSteps/Confirmation.tsx
@@ -1,15 +1,9 @@
+import {CONST as COMMON_CONST} from 'expensify-common/dist/CONST';
 import React, {useMemo} from 'react';
-import {View} from 'react-native';
 import {useOnyx} from 'react-native-onyx';
-import Button from '@components/Button';
-import DotIndicatorMessage from '@components/DotIndicatorMessage';
-import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
-import SafeAreaConsumer from '@components/SafeAreaConsumer';
-import ScrollView from '@components/ScrollView';
-import Text from '@components/Text';
+import ConfirmationStep from '@components/SubStepForms/ConfirmationStep';
 import useLocalize from '@hooks/useLocalize';
 import type {SubStepProps} from '@hooks/useSubStep/types';
-import useThemeStyles from '@hooks/useThemeStyles';
 import {getLatestErrorMessage} from '@libs/ErrorUtils';
 import getSubStepValues from '@pages/ReimbursementAccount/utils/getSubStepValues';
 import CONST from '@src/CONST';
@@ -29,6 +23,7 @@ const {
     BUSINESS_CONTACT_NUMBER,
     BUSINESS_CONFIRMATION_EMAIL,
     FORMATION_INCORPORATION_COUNTRY_CODE,
+    FORMATION_INCORPORATION_STATE,
     ANNUAL_VOLUME,
     APPLICANT_TYPE_ID,
     TRADE_VOLUME,
@@ -43,9 +38,15 @@ const displayAddress = (street: string, city: string, state: string, zipCode: st
     return country === CONST.COUNTRY.US || country === CONST.COUNTRY.CA ? `${street}, ${city}, ${state}, ${zipCode}, ${country}` : `${street}, ${city}, ${zipCode}, ${country}`;
 };
 
-function Confirmation({onNext, onMove}: SubStepProps) {
+const displayIncorporationLocation = (country: string, state: string) => {
+    const countryFullName = CONST.ALL_COUNTRIES[country as keyof typeof CONST.COUNTRY];
+    const stateFullName = COMMON_CONST.STATES[state as keyof typeof COMMON_CONST.STATES]?.stateName ?? COMMON_CONST.PROVINCES[state as keyof typeof COMMON_CONST.PROVINCES]?.provinceName;
+
+    return country === CONST.COUNTRY.US || country === CONST.COUNTRY.CA ? `${stateFullName}, ${countryFullName}` : `${countryFullName}`;
+};
+
+function Confirmation({onNext, onMove, isEditing}: SubStepProps) {
     const {translate} = useLocalize();
-    const styles = useThemeStyles();
 
     const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
     const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT);
@@ -71,122 +72,111 @@ function Confirmation({onNext, onMove}: SubStepProps) {
         [corpayOnboardingFields?.picklists.TradeVolumeRange, values],
     );
 
+    const summaryItems = useMemo(
+        () => [
+            {
+                title: values[COMPANY_NAME],
+                description: translate('businessInfoStep.legalBusinessName'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(0);
+                },
+            },
+            {
+                title: values[BUSINESS_REGISTRATION_INCORPORATION_NUMBER],
+                description: translate('businessInfoStep.registrationNumber'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(3);
+                },
+            },
+            {
+                title: values[TAX_ID_EIN_NUMBER],
+                description: translate('businessInfoStep.taxIDEIN'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(4);
+                },
+            },
+            {
+                title: displayAddress(values[COMPANY_STREET], values[COMPANY_CITY], values[COMPANY_STATE], values[COMPANY_POSTAL_CODE], values[COMPANY_COUNTRY_CODE]),
+                description: translate('businessInfoStep.businessAddress'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(1);
+                },
+            },
+            {
+                title: values[BUSINESS_CONTACT_NUMBER],
+                description: translate('common.phoneNumber'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(2);
+                },
+            },
+            {
+                title: values[BUSINESS_CONFIRMATION_EMAIL],
+                description: translate('common.email'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(2);
+                },
+            },
+            {
+                title: businessType,
+                description: translate('businessInfoStep.businessType'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(6);
+                },
+            },
+            {
+                title: displayIncorporationLocation(values[FORMATION_INCORPORATION_COUNTRY_CODE], values[FORMATION_INCORPORATION_STATE]),
+                description: translate('businessInfoStep.incorporation'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(5);
+                },
+            },
+            {
+                title: businessCategory,
+                description: translate('businessInfoStep.businessCategory'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(6);
+                },
+            },
+            {
+                title: paymentVolume,
+                description: translate('businessInfoStep.annualPaymentVolume'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(7);
+                },
+            },
+            {
+                title: tradeVolumeRange,
+                description: translate('businessInfoStep.averageReimbursementAmount'),
+                shouldShowRightIcon: true,
+                onPress: () => {
+                    onMove(8);
+                },
+            },
+        ],
+        [businessCategory, businessType, onMove, paymentVolume, tradeVolumeRange, translate, values],
+    );
+
     return (
-        <SafeAreaConsumer>
-            {({safeAreaPaddingBottomStyle}) => (
-                <ScrollView
-                    style={styles.pt0}
-                    contentContainerStyle={[styles.flexGrow1, safeAreaPaddingBottomStyle]}
-                >
-                    <Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mb3]}>{translate('businessInfoStep.letsDoubleCheck')}</Text>
-                    <MenuItemWithTopDescription
-                        description={translate('businessInfoStep.legalBusinessName')}
-                        title={values[COMPANY_NAME]}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(0);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('businessInfoStep.registrationNumber')}
-                        title={values[BUSINESS_REGISTRATION_INCORPORATION_NUMBER]}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(3);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('businessInfoStep.taxIDEIN')}
-                        title={values[TAX_ID_EIN_NUMBER]}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(4);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('businessInfoStep.businessAddress')}
-                        title={displayAddress(values[COMPANY_STREET], values[COMPANY_CITY], values[COMPANY_STATE], values[COMPANY_POSTAL_CODE], values[COMPANY_COUNTRY_CODE])}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(1);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('common.phoneNumber')}
-                        title={values[BUSINESS_CONTACT_NUMBER]}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(2);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('common.email')}
-                        title={values[BUSINESS_CONFIRMATION_EMAIL]}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(2);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('businessInfoStep.businessType')}
-                        title={businessType}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(6);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('businessInfoStep.incorporation')}
-                        title={values[FORMATION_INCORPORATION_COUNTRY_CODE]}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(5);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('businessInfoStep.businessCategory')}
-                        title={businessCategory}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(6);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('businessInfoStep.annualPaymentVolume')}
-                        title={paymentVolume}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(7);
-                        }}
-                    />
-                    <MenuItemWithTopDescription
-                        description={translate('businessInfoStep.averageReimbursementAmount')}
-                        title={tradeVolumeRange}
-                        shouldShowRightIcon
-                        onPress={() => {
-                            onMove(8);
-                        }}
-                    />
-                    <View style={[styles.p5, styles.flexGrow1, styles.justifyContentEnd]}>
-                        {!!error && error.length > 0 && (
-                            <DotIndicatorMessage
-                                textStyles={[styles.formError]}
-                                type="error"
-                                messages={{error}}
-                            />
-                        )}
-                        <Button
-                            success
-                            isLoading={reimbursementAccount?.isSavingCorpayOnboardingCompanyFields}
-                            style={[styles.w100, styles.mt2]}
-                            onPress={onNext}
-                            large
-                            text={translate('common.confirm')}
-                        />
-                    </View>
-                </ScrollView>
-            )}
-        </SafeAreaConsumer>
+        <ConfirmationStep
+            isEditing={isEditing}
+            error={error}
+            onNext={onNext}
+            onMove={onMove}
+            pageTitle={translate('businessInfoStep.letsDoubleCheck')}
+            summaryItems={summaryItems}
+            isLoading={reimbursementAccount?.isSavingCorpayOnboardingCompanyFields}
+            showOnfidoLinks={false}
+        />
     );
 }
 
diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/AddressBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/AddressBusiness.tsx
index d7e1d8df4de8..64e957a76d5c 100644
--- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/AddressBusiness.tsx
+++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/AddressBusiness.tsx
@@ -1,14 +1,9 @@
-import React, {useCallback} from 'react';
+import React from 'react';
 import {useOnyx} from 'react-native-onyx';
-import FormProvider from '@components/Form/FormProvider';
-import type {FormInputErrors, FormOnyxValues} from '@components/Form/types';
-import Text from '@components/Text';
+import AddressStep from '@components/SubStepForms/AddressStep';
 import useLocalize from '@hooks/useLocalize';
 import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit';
 import type {SubStepProps} from '@hooks/useSubStep/types';
-import useThemeStyles from '@hooks/useThemeStyles';
-import * as ValidationUtils from '@libs/ValidationUtils';
-import AddressFormFields from '@pages/ReimbursementAccount/AddressFormFields';
 import ONYXKEYS from '@src/ONYXKEYS';
 import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
 
@@ -23,33 +18,11 @@ const INPUT_KEYS = {
 
 const STEP_FIELDS = [COMPANY_BUSINESS_INFO_KEY.STREET, COMPANY_BUSINESS_INFO_KEY.CITY, COMPANY_BUSINESS_INFO_KEY.STATE, COMPANY_BUSINESS_INFO_KEY.ZIP_CODE];
 
-function AddressBusiness({onNext, isEditing}: SubStepProps) {
+function AddressBusiness({onNext, onMove, isEditing}: SubStepProps) {
     const {translate} = useLocalize();
-    const styles = useThemeStyles();
 
     const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
 
-    const validate = useCallback(
-        (values: FormOnyxValues<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM>): FormInputErrors<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM> => {
-            const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS);
-
-            if (values.addressStreet && !ValidationUtils.isValidAddress(values.addressStreet)) {
-                errors.addressStreet = translate('bankAccount.error.addressStreet');
-            }
-
-            if (values.addressCity && !ValidationUtils.isValidAddress(values.addressCity)) {
-                errors.addressCity = translate('bankAccount.error.addressCity');
-            }
-
-            if (values.addressZipCode && !ValidationUtils.isValidZipCode(values.addressZipCode)) {
-                errors.addressZipCode = translate('bankAccount.error.zipCode');
-            }
-
-            return errors;
-        },
-        [translate],
-    );
-
     const defaultValues = {
         street: reimbursementAccount?.achData?.addressStreet ?? '',
         city: reimbursementAccount?.achData?.addressCity ?? '',
@@ -64,23 +37,19 @@ function AddressBusiness({onNext, isEditing}: SubStepProps) {
     });
 
     return (
-        <FormProvider
+        <AddressStep<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM>
+            isEditing={isEditing}
+            onNext={onNext}
+            onMove={onMove}
             formID={ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM}
-            submitButtonText={translate(isEditing ? 'common.confirm' : 'common.next')}
-            validate={validate}
+            formTitle={translate('businessInfoStep.enterYourCompanysAddress')}
+            formPOBoxDisclaimer={translate('common.noPO')}
             onSubmit={handleSubmit}
-            submitButtonStyles={[styles.mb0]}
-            style={[styles.mh5, styles.flexGrow1]}
-        >
-            <Text style={[styles.textHeadlineLineHeightXXL]}>{translate('businessInfoStep.enterYourCompanysAddress')}</Text>
-            <Text style={[styles.pv3, styles.textSupporting]}>{translate('common.noPO')}</Text>
-            <AddressFormFields
-                inputKeys={INPUT_KEYS}
-                shouldSaveDraft={!isEditing}
-                defaultValues={defaultValues}
-                streetTranslationKey="common.companyAddress"
-            />
-        </FormProvider>
+            stepFields={STEP_FIELDS}
+            inputFieldsIDs={INPUT_KEYS}
+            defaultValues={defaultValues}
+            streetTranslationKey="common.companyAddress"
+        />
     );
 }
 
diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx
index b523381e4457..50444cb569af 100644
--- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx
+++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx
@@ -1,38 +1,32 @@
 import React, {useCallback} from 'react';
 import {useOnyx} from 'react-native-onyx';
-import FormProvider from '@components/Form/FormProvider';
-import InputWrapper from '@components/Form/InputWrapper';
 import type {FormInputErrors, FormOnyxValues} from '@components/Form/types';
-import Text from '@components/Text';
-import TextInput from '@components/TextInput';
+import SingleFieldStep from '@components/SubStepForms/SingleFieldStep';
 import useLocalize from '@hooks/useLocalize';
 import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit';
 import type {SubStepProps} from '@hooks/useSubStep/types';
-import useThemeStyles from '@hooks/useThemeStyles';
-import * as ValidationUtils from '@libs/ValidationUtils';
-import CONST from '@src/CONST';
+import {getFieldRequiredErrors, isValidCompanyName} from '@libs/ValidationUtils';
 import ONYXKEYS from '@src/ONYXKEYS';
 import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
 
 const COMPANY_NAME_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_NAME;
 const STEP_FIELDS = [COMPANY_NAME_KEY];
 
-function NameBusiness({onNext, isEditing}: SubStepProps) {
+function NameBusiness({onNext, onMove, isEditing}: SubStepProps) {
     const {translate} = useLocalize();
-    const styles = useThemeStyles();
 
     const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
 
     const defaultCompanyName = reimbursementAccount?.achData?.companyName ?? '';
-    const bankAccountID = reimbursementAccount?.achData?.bankAccountID ?? -1;
+    const bankAccountID = reimbursementAccount?.achData?.bankAccountID;
 
     const shouldDisableCompanyName = !!(bankAccountID && defaultCompanyName && reimbursementAccount?.achData?.state !== 'SETUP');
 
     const validate = useCallback(
         (values: FormOnyxValues<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM>): FormInputErrors<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM> => {
-            const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS);
+            const errors = getFieldRequiredErrors(values, STEP_FIELDS);
 
-            if (values.companyName && !ValidationUtils.isValidCompanyName(values.companyName)) {
+            if (values.companyName && !isValidCompanyName(values.companyName)) {
                 errors.companyName = translate('bankAccount.error.companyName');
             }
 
@@ -48,28 +42,21 @@ function NameBusiness({onNext, isEditing}: SubStepProps) {
     });
 
     return (
-        <FormProvider
+        <SingleFieldStep<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM>
+            isEditing={isEditing}
+            onNext={onNext}
+            onMove={onMove}
             formID={ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM}
-            submitButtonText={translate(isEditing ? 'common.confirm' : 'common.next')}
+            formTitle={translate('businessInfoStep.enterTheNameOfYourBusiness')}
             validate={validate}
             onSubmit={handleSubmit}
-            style={[styles.mh5, styles.flexGrow1]}
-            submitButtonStyles={[styles.mb0]}
-        >
-            <Text style={[styles.textHeadlineLineHeightXXL]}>{translate('businessInfoStep.enterTheNameOfYourBusiness')}</Text>
-            <InputWrapper
-                InputComponent={TextInput}
-                label={translate('businessInfoStep.businessName')}
-                aria-label={translate('businessInfoStep.businessName')}
-                role={CONST.ROLE.PRESENTATION}
-                inputID={COMPANY_NAME_KEY}
-                containerStyles={[styles.mt6]}
-                disabled={shouldDisableCompanyName}
-                defaultValue={defaultCompanyName}
-                shouldSaveDraft={!isEditing}
-                shouldUseDefaultValue={shouldDisableCompanyName}
-            />
-        </FormProvider>
+            inputId={COMPANY_NAME_KEY}
+            inputLabel={translate('businessInfoStep.businessName')}
+            defaultValue={defaultCompanyName}
+            shouldUseDefaultValue={shouldDisableCompanyName}
+            disabled={shouldDisableCompanyName}
+            shouldShowHelpLinks={false}
+        />
     );
 }
 
diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx
index 9e82accfe2f3..610206768844 100644
--- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx
+++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx
@@ -1,15 +1,11 @@
 import React, {useCallback} from 'react';
 import {useOnyx} from 'react-native-onyx';
-import FormProvider from '@components/Form/FormProvider';
-import InputWrapper from '@components/Form/InputWrapper';
 import type {FormInputErrors, FormOnyxValues} from '@components/Form/types';
-import Text from '@components/Text';
-import TextInput from '@components/TextInput';
+import SingleFieldStep from '@components/SubStepForms/SingleFieldStep';
 import useLocalize from '@hooks/useLocalize';
 import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit';
 import type {SubStepProps} from '@hooks/useSubStep/types';
-import useThemeStyles from '@hooks/useThemeStyles';
-import * as ValidationUtils from '@libs/ValidationUtils';
+import {getFieldRequiredErrors, isValidUSPhone} from '@libs/ValidationUtils';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
@@ -17,9 +13,8 @@ import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
 const COMPANY_PHONE_NUMBER_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_PHONE;
 const STEP_FIELDS = [COMPANY_PHONE_NUMBER_KEY];
 
-function PhoneNumberBusiness({onNext, isEditing}: SubStepProps) {
+function PhoneNumberBusiness({onNext, onMove, isEditing}: SubStepProps) {
     const {translate} = useLocalize();
-    const styles = useThemeStyles();
 
     const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
 
@@ -27,9 +22,9 @@ function PhoneNumberBusiness({onNext, isEditing}: SubStepProps) {
 
     const validate = useCallback(
         (values: FormOnyxValues<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM>): FormInputErrors<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM> => {
-            const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS);
+            const errors = getFieldRequiredErrors(values, STEP_FIELDS);
 
-            if (values.companyPhone && !ValidationUtils.isValidUSPhone(values.companyPhone, true)) {
+            if (values.companyPhone && !isValidUSPhone(values.companyPhone, true)) {
                 errors.companyPhone = translate('bankAccount.error.phoneNumber');
             }
 
@@ -46,28 +41,21 @@ function PhoneNumberBusiness({onNext, isEditing}: SubStepProps) {
     });
 
     return (
-        <FormProvider
+        <SingleFieldStep<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM>
+            isEditing={isEditing}
+            onNext={onNext}
+            onMove={onMove}
             formID={ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM}
-            submitButtonText={translate(isEditing ? 'common.confirm' : 'common.next')}
+            formTitle={translate('businessInfoStep.enterYourCompanysPhoneNumber')}
             validate={validate}
             onSubmit={handleSubmit}
-            style={[styles.mh5, styles.flexGrow1]}
-            submitButtonStyles={[styles.mb0]}
-        >
-            <Text style={[styles.textHeadlineLineHeightXXL]}>{translate('businessInfoStep.enterYourCompanysPhoneNumber')}</Text>
-            <InputWrapper
-                InputComponent={TextInput}
-                inputID={COMPANY_PHONE_NUMBER_KEY}
-                label={translate('common.phoneNumber')}
-                aria-label={translate('common.phoneNumber')}
-                role={CONST.ROLE.PRESENTATION}
-                inputMode={CONST.INPUT_MODE.TEL}
-                placeholder={translate('common.phoneNumberPlaceholder')}
-                defaultValue={defaultCompanyPhoneNumber}
-                shouldSaveDraft={!isEditing}
-                containerStyles={[styles.mt6]}
-            />
-        </FormProvider>
+            inputId={COMPANY_PHONE_NUMBER_KEY}
+            inputMode={CONST.INPUT_MODE.TEL}
+            inputLabel={translate('common.phoneNumber')}
+            defaultValue={defaultCompanyPhoneNumber}
+            shouldShowHelpLinks={false}
+            placeholder={translate('common.phoneNumberPlaceholder')}
+        />
     );
 }
 
diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx
index 48f1b7f0665f..4a249541bb82 100644
--- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx
+++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx
@@ -1,36 +1,32 @@
 import React, {useCallback} from 'react';
 import {useOnyx} from 'react-native-onyx';
-import FormProvider from '@components/Form/FormProvider';
-import InputWrapper from '@components/Form/InputWrapper';
 import type {FormInputErrors, FormOnyxValues} from '@components/Form/types';
-import Text from '@components/Text';
-import TextInput from '@components/TextInput';
+import SingleFieldStep from '@components/SubStepForms/SingleFieldStep';
 import useLocalize from '@hooks/useLocalize';
 import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit';
 import type {SubStepProps} from '@hooks/useSubStep/types';
-import useThemeStyles from '@hooks/useThemeStyles';
-import * as ValidationUtils from '@libs/ValidationUtils';
-import CONST from '@src/CONST';
+import {getFieldRequiredErrors, isValidTaxID} from '@libs/ValidationUtils';
 import ONYXKEYS from '@src/ONYXKEYS';
 import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
 
 const COMPANY_TAX_ID_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_TAX_ID;
 const STEP_FIELDS = [COMPANY_TAX_ID_KEY];
-function TaxIdBusiness({onNext, isEditing}: SubStepProps) {
+function TaxIdBusiness({onNext, onMove, isEditing}: SubStepProps) {
     const {translate} = useLocalize();
-    const styles = useThemeStyles();
 
     const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
 
-    const defaultCompanyTaxId = reimbursementAccount?.achData?.companyTaxID ?? '';
-    const bankAccountID = reimbursementAccount?.achData?.bankAccountID ?? 0;
-    const shouldDisableCompanyTaxID = !!(bankAccountID && defaultCompanyTaxId && reimbursementAccount?.achData?.state !== 'SETUP');
+    // This is default value for the input to be display
+    /* eslint-disable-next-line rulesdir/no-default-id-values */
+    const defaultCompanyTaxID = reimbursementAccount?.achData?.companyTaxID ?? '';
+    const bankAccountID = reimbursementAccount?.achData?.bankAccountID;
+    const shouldDisableCompanyTaxID = !!(bankAccountID && defaultCompanyTaxID && reimbursementAccount?.achData?.state !== 'SETUP');
 
     const validate = useCallback(
         (values: FormOnyxValues<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM>): FormInputErrors<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM> => {
-            const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS);
+            const errors = getFieldRequiredErrors(values, STEP_FIELDS);
 
-            if (values.companyTaxID && !ValidationUtils.isValidTaxID(values.companyTaxID)) {
+            if (values.companyTaxID && !isValidTaxID(values.companyTaxID)) {
                 errors.companyTaxID = translate('bankAccount.error.taxID');
             }
 
@@ -46,30 +42,22 @@ function TaxIdBusiness({onNext, isEditing}: SubStepProps) {
     });
 
     return (
-        <FormProvider
+        <SingleFieldStep<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM>
+            isEditing={isEditing}
+            onNext={onNext}
+            onMove={onMove}
             formID={ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM}
-            submitButtonText={translate(isEditing ? 'common.confirm' : 'common.next')}
+            formTitle={translate('businessInfoStep.enterYourCompanysTaxIdNumber')}
             validate={validate}
             onSubmit={handleSubmit}
-            style={[styles.mh5, styles.flexGrow1]}
-            submitButtonStyles={[styles.mb0]}
-        >
-            <Text style={[styles.textHeadlineLineHeightXXL]}>{translate('businessInfoStep.enterYourCompanysTaxIdNumber')}</Text>
-            <InputWrapper
-                InputComponent={TextInput}
-                inputID={COMPANY_TAX_ID_KEY}
-                label={translate('businessInfoStep.taxIDNumber')}
-                aria-label={translate('businessInfoStep.taxIDNumber')}
-                role={CONST.ROLE.PRESENTATION}
-                defaultValue={defaultCompanyTaxId}
-                inputMode={CONST.INPUT_MODE.NUMERIC}
-                disabled={shouldDisableCompanyTaxID}
-                shouldSaveDraft={!isEditing}
-                shouldUseDefaultValue={shouldDisableCompanyTaxID}
-                containerStyles={[styles.mt6]}
-                placeholder={translate('businessInfoStep.taxIDNumberPlaceholder')}
-            />
-        </FormProvider>
+            inputId={COMPANY_TAX_ID_KEY}
+            inputLabel={translate('businessInfoStep.taxIDNumber')}
+            defaultValue={defaultCompanyTaxID}
+            shouldUseDefaultValue={shouldDisableCompanyTaxID}
+            disabled={shouldDisableCompanyTaxID}
+            shouldShowHelpLinks={false}
+            placeholder={translate('businessInfoStep.taxIDNumberPlaceholder')}
+        />
     );
 }
 
diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx
index 5ef5e7c75c8d..15a74fe0a22f 100644
--- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx
+++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx
@@ -1,18 +1,14 @@
 import {Str} from 'expensify-common';
 import React, {useCallback, useMemo} from 'react';
 import {useOnyx} from 'react-native-onyx';
-import FormProvider from '@components/Form/FormProvider';
-import InputWrapper from '@components/Form/InputWrapper';
 import type {FormInputErrors, FormOnyxValues} from '@components/Form/types';
-import Text from '@components/Text';
-import TextInput from '@components/TextInput';
+import SingleFieldStep from '@components/SubStepForms/SingleFieldStep';
 import useLocalize from '@hooks/useLocalize';
 import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit';
 import type {SubStepProps} from '@hooks/useSubStep/types';
-import useThemeStyles from '@hooks/useThemeStyles';
 import {getDefaultCompanyWebsite} from '@libs/BankAccountUtils';
-import * as ValidationUtils from '@libs/ValidationUtils';
-import * as BankAccounts from '@userActions/BankAccounts';
+import {getFieldRequiredErrors, isValidWebsite} from '@libs/ValidationUtils';
+import {addBusinessWebsiteForDraft} from '@userActions/BankAccounts';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
@@ -20,9 +16,8 @@ import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
 const COMPANY_WEBSITE_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_WEBSITE;
 const STEP_FIELDS = [COMPANY_WEBSITE_KEY];
 
-function WebsiteBusiness({onNext, isEditing}: SubStepProps) {
+function WebsiteBusiness({onNext, onMove, isEditing}: SubStepProps) {
     const {translate} = useLocalize();
-    const styles = useThemeStyles();
     const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
     const [session] = useOnyx(ONYXKEYS.SESSION);
     const [user] = useOnyx(ONYXKEYS.USER);
@@ -32,9 +27,9 @@ function WebsiteBusiness({onNext, isEditing}: SubStepProps) {
 
     const validate = useCallback(
         (values: FormOnyxValues<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM>): FormInputErrors<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM> => {
-            const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS);
+            const errors = getFieldRequiredErrors(values, STEP_FIELDS);
 
-            if (values.website && !ValidationUtils.isValidWebsite(Str.sanitizeURL(values.website, CONST.COMPANY_WEBSITE_DEFAULT_SCHEME))) {
+            if (values.website && !isValidWebsite(Str.sanitizeURL(values.website, CONST.COMPANY_WEBSITE_DEFAULT_SCHEME))) {
                 errors.website = translate('bankAccount.error.website');
             }
 
@@ -46,35 +41,28 @@ function WebsiteBusiness({onNext, isEditing}: SubStepProps) {
         fieldIds: STEP_FIELDS,
         onNext: (values) => {
             const website = Str.sanitizeURL((values as {website: string})?.website, CONST.COMPANY_WEBSITE_DEFAULT_SCHEME);
-            BankAccounts.addBusinessWebsiteForDraft(website);
+            addBusinessWebsiteForDraft(website);
             onNext();
         },
         shouldSaveDraft: true,
     });
 
     return (
-        <FormProvider
+        <SingleFieldStep<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM>
+            isEditing={isEditing}
+            onNext={onNext}
+            onMove={onMove}
             formID={ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM}
-            submitButtonText={translate(isEditing ? 'common.confirm' : 'common.next')}
+            formTitle={translate('businessInfoStep.enterYourCompanysWebsite')}
+            formDisclaimer={translate('common.websiteExample')}
             validate={validate}
             onSubmit={handleSubmit}
-            style={[styles.mh5, styles.flexGrow1]}
-            submitButtonStyles={[styles.mb0]}
-        >
-            <Text style={[styles.textHeadlineLineHeightXXL]}>{translate('businessInfoStep.enterYourCompanysWebsite')}</Text>
-            <Text style={[styles.label, styles.textSupporting]}>{translate('common.websiteExample')}</Text>
-            <InputWrapper
-                InputComponent={TextInput}
-                inputID={COMPANY_WEBSITE_KEY}
-                label={translate('businessInfoStep.companyWebsite')}
-                aria-label={translate('businessInfoStep.companyWebsite')}
-                role={CONST.ROLE.PRESENTATION}
-                containerStyles={[styles.mt6]}
-                defaultValue={defaultCompanyWebsite}
-                shouldSaveDraft={!isEditing}
-                inputMode={CONST.INPUT_MODE.URL}
-            />
-        </FormProvider>
+            inputId={COMPANY_WEBSITE_KEY}
+            inputLabel={translate('businessInfoStep.companyWebsite')}
+            defaultValue={defaultCompanyWebsite}
+            inputMode={CONST.INPUT_MODE.URL}
+            shouldShowHelpLinks={false}
+        />
     );
 }
 
diff --git a/src/pages/ReportChangeWorkspacePage.tsx b/src/pages/ReportChangeWorkspacePage.tsx
new file mode 100644
index 000000000000..d07ed20513a4
--- /dev/null
+++ b/src/pages/ReportChangeWorkspacePage.tsx
@@ -0,0 +1,95 @@
+import React, {useCallback} from 'react';
+import {useOnyx} from 'react-native-onyx';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import UserListItem from '@components/SelectionList/UserListItem';
+import useDebouncedState from '@hooks/useDebouncedState';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import useThemeStyles from '@hooks/useThemeStyles';
+import type {WorkspaceListItem} from '@hooks/useWorkspaceList';
+import useWorkspaceList from '@hooks/useWorkspaceList';
+import {changeReportPolicy} from '@libs/actions/Report';
+import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
+import type {ReportChangeWorkspaceNavigatorParamList} from '@libs/Navigation/types';
+import {isWorkspaceEligibleForReportChange} from '@libs/PolicyUtils';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import type SCREENS from '@src/SCREENS';
+import type {WithReportOrNotFoundProps} from './home/report/withReportOrNotFound';
+import withReportOrNotFound from './home/report/withReportOrNotFound';
+
+type ReportChangeWorkspacePageProps = WithReportOrNotFoundProps & PlatformStackScreenProps<ReportChangeWorkspaceNavigatorParamList, typeof SCREENS.REPORT_CHANGE_WORKSPACE.ROOT>;
+
+function ReportChangeWorkspacePage({report}: ReportChangeWorkspacePageProps) {
+    const reportID = report?.reportID;
+    const {isOffline} = useNetwork();
+    const styles = useThemeStyles();
+    const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
+    const {translate} = useLocalize();
+
+    const [policies, fetchStatus] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
+    const oldPolicy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`];
+    const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email});
+    const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP);
+    const shouldShowLoadingIndicator = isLoadingApp && !isOffline;
+
+    const selectPolicy = useCallback(
+        (policyID?: string) => {
+            if (!policyID) {
+                return;
+            }
+            Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(reportID));
+            changeReportPolicy(reportID, policyID);
+        },
+        [reportID],
+    );
+
+    const {sections, shouldShowNoResultsFoundMessage, shouldShowSearchInput} = useWorkspaceList({
+        policies,
+        currentUserLogin,
+        isOffline,
+        selectedPolicyID: report.policyID,
+        searchTerm: debouncedSearchTerm,
+        additionalFilter: (newPolicy) => isWorkspaceEligibleForReportChange(newPolicy, report, oldPolicy, currentUserLogin),
+    });
+
+    return (
+        <ScreenWrapper
+            testID={ReportChangeWorkspacePage.displayName}
+            includeSafeAreaPaddingBottom
+            shouldEnableMaxHeight
+        >
+            {({didScreenTransitionEnd}) => (
+                <>
+                    <HeaderWithBackButton
+                        title={translate('iou.changeWorkspace')}
+                        onBackButtonPress={Navigation.goBack}
+                    />
+                    {shouldShowLoadingIndicator ? (
+                        <FullScreenLoadingIndicator style={[styles.flex1, styles.pRelative]} />
+                    ) : (
+                        <SelectionList<WorkspaceListItem>
+                            ListItem={UserListItem}
+                            sections={sections}
+                            onSelectRow={(option) => selectPolicy(option.policyID)}
+                            textInputLabel={shouldShowSearchInput ? translate('common.search') : undefined}
+                            textInputValue={searchTerm}
+                            onChangeText={setSearchTerm}
+                            headerMessage={shouldShowNoResultsFoundMessage ? translate('common.noResultsFound') : ''}
+                            initiallyFocusedOptionKey={report.policyID}
+                            showLoadingPlaceholder={fetchStatus.status === 'loading' || !didScreenTransitionEnd}
+                        />
+                    )}
+                </>
+            )}
+        </ScreenWrapper>
+    );
+}
+
+ReportChangeWorkspacePage.displayName = 'ReportChangeWorkspacePage';
+
+export default withReportOrNotFound()(ReportChangeWorkspacePage);
diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx
index 2ec71a04a965..fc7f0beadb82 100644
--- a/src/pages/Search/AdvancedSearchFilters.tsx
+++ b/src/pages/Search/AdvancedSearchFilters.tsx
@@ -293,7 +293,7 @@ function getFilterDisplayTitle(filters: Partial<SearchAdvancedFiltersForm>, filt
         return dateValue;
     }
 
-    const nonDateFilterKey = filterKey as Exclude<SearchFilterKey, SearchDateFilterKeys>;
+    const nonDateFilterKey = filterKey as Exclude<SearchFilterKey, SearchDateFilterKeys | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.GROUP_BY>;
 
     if (nonDateFilterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT) {
         const {lessThan, greaterThan} = filters;
diff --git a/src/pages/Search/SearchMoneyRequestReportPage.tsx b/src/pages/Search/SearchMoneyRequestReportPage.tsx
index 922ee515b6c3..a2af16a67a6e 100644
--- a/src/pages/Search/SearchMoneyRequestReportPage.tsx
+++ b/src/pages/Search/SearchMoneyRequestReportPage.tsx
@@ -12,6 +12,7 @@ import type {SearchQueryJSON} from '@components/Search/types';
 import useLocalize from '@hooks/useLocalize';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
 import useThemeStyles from '@hooks/useThemeStyles';
+import Navigation from '@libs/Navigation/Navigation';
 import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
 import type {SearchFullscreenNavigatorParamList} from '@libs/Navigation/types';
 import {buildSearchQueryJSON} from '@libs/SearchQueryUtils';
@@ -52,7 +53,9 @@ function TemporaryMoneyRequestReportView({report, policy}: TemporaryMoneyRequest
                 policy={policy}
                 reportActions={[]}
                 transactionThreadReportID={undefined}
-                onBackButtonPress={() => {}}
+                onBackButtonPress={() => {
+                    Navigation.goBack();
+                }}
             />
         </View>
     );
diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx
index 226f83d99006..1732980aabf4 100644
--- a/src/pages/Search/SearchPage.tsx
+++ b/src/pages/Search/SearchPage.tsx
@@ -19,7 +19,6 @@ import Navigation from '@libs/Navigation/Navigation';
 import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
 import type {SearchFullscreenNavigatorParamList} from '@libs/Navigation/types';
 import {buildCannedSearchQuery, buildSearchQueryJSON, getPolicyIDFromSearchQuery} from '@libs/SearchQueryUtils';
-import CONST from '@src/CONST';
 import ROUTES from '@src/ROUTES';
 import type SCREENS from '@src/SCREENS';
 import SearchPageNarrow from './SearchPageNarrow';
@@ -32,7 +31,7 @@ function SearchPage({route}: SearchPageProps) {
     const {shouldUseNarrowLayout} = useResponsiveLayout();
     const styles = useThemeStyles();
 
-    const {q, name, groupBy} = route.params;
+    const {q, name} = route.params;
 
     const {queryJSON, policyID} = useMemo(() => {
         const parsedQuery = buildSearchQueryJSON(q);
@@ -44,8 +43,6 @@ function SearchPage({route}: SearchPageProps) {
     const handleOnBackButtonPress = () => Navigation.goBack(ROUTES.SEARCH_ROOT.getRoute({query: buildCannedSearchQuery()}));
     const {clearSelectedTransactions} = useSearchContext();
 
-    const shouldGroupByReports = groupBy === CONST.SEARCH.GROUP_BY.REPORTS;
-
     const isSearchNameModified = name === q;
     const searchName = isSearchNameModified ? undefined : name;
 
@@ -54,7 +51,6 @@ function SearchPage({route}: SearchPageProps) {
             <SearchPageNarrow
                 queryJSON={queryJSON}
                 policyID={policyID}
-                shouldGroupByReports={shouldGroupByReports}
                 searchName={searchName}
             />
         );
@@ -83,10 +79,7 @@ function SearchPage({route}: SearchPageProps) {
                                         breadcrumbLabel={translate('common.reports')}
                                         shouldDisplaySearch={false}
                                     />
-                                    <SearchTypeMenu
-                                        queryJSON={queryJSON}
-                                        shouldGroupByReports={shouldGroupByReports}
-                                    />
+                                    <SearchTypeMenu queryJSON={queryJSON} />
                                 </View>
                             ) : (
                                 <HeaderWithBackButton
@@ -104,15 +97,11 @@ function SearchPage({route}: SearchPageProps) {
                             shouldShowOfflineIndicatorInWideScreen
                             offlineIndicatorStyle={styles.mtAuto}
                         >
-                            <SearchPageHeader
-                                queryJSON={queryJSON}
-                                shouldGroupByReports={shouldGroupByReports}
-                            />
+                            <SearchPageHeader queryJSON={queryJSON} />
                             <SearchStatusBar queryJSON={queryJSON} />
                             <Search
                                 key={queryJSON.hash}
                                 queryJSON={queryJSON}
-                                shouldGroupByReports={shouldGroupByReports}
                             />
                         </ScreenWrapper>
                     </View>
diff --git a/src/pages/Search/SearchPageNarrow.tsx b/src/pages/Search/SearchPageNarrow.tsx
index 668fb1291365..8a747b5d3871 100644
--- a/src/pages/Search/SearchPageNarrow.tsx
+++ b/src/pages/Search/SearchPageNarrow.tsx
@@ -35,10 +35,9 @@ type SearchPageNarrowProps = {
     queryJSON?: SearchQueryJSON;
     policyID?: string;
     searchName?: string;
-    shouldGroupByReports?: boolean;
 };
 
-function SearchPageNarrow({queryJSON, policyID, searchName, shouldGroupByReports}: SearchPageNarrowProps) {
+function SearchPageNarrow({queryJSON, policyID, searchName}: SearchPageNarrowProps) {
     const {translate} = useLocalize();
     const {shouldUseNarrowLayout} = useResponsiveLayout();
     const {windowHeight} = useWindowDimensions();
@@ -157,7 +156,6 @@ function SearchPageNarrow({queryJSON, policyID, searchName, shouldGroupByReports
                                             topBarOffset.set(StyleUtils.searchHeaderDefaultOffset);
                                             setSearchRouterListVisible(true);
                                         }}
-                                        shouldGroupByReports={shouldGroupByReports}
                                     />
                                 </View>
                                 <View style={[styles.appBG]}>
@@ -185,7 +183,6 @@ function SearchPageNarrow({queryJSON, policyID, searchName, shouldGroupByReports
                         <SearchPageHeader
                             queryJSON={queryJSON}
                             searchName={searchName}
-                            shouldGroupByReports={shouldGroupByReports}
                         />
                     </>
                 )}
@@ -197,7 +194,6 @@ function SearchPageNarrow({queryJSON, policyID, searchName, shouldGroupByReports
                             onSearchListScroll={scrollHandler}
                             onContentSizeChange={onContentSizeChange}
                             contentContainerStyle={!selectionMode?.isEnabled ? [styles.searchListContentContainerStyles] : undefined}
-                            shouldGroupByReports={shouldGroupByReports}
                         />
                     </View>
                 )}
diff --git a/src/pages/Search/SearchTypeMenu.tsx b/src/pages/Search/SearchTypeMenu.tsx
index 110ae4290195..4c5fb2522220 100644
--- a/src/pages/Search/SearchTypeMenu.tsx
+++ b/src/pages/Search/SearchTypeMenu.tsx
@@ -37,10 +37,9 @@ import SavedSearchItemThreeDotMenu from './SavedSearchItemThreeDotMenu';
 
 type SearchTypeMenuProps = {
     queryJSON: SearchQueryJSON;
-    shouldGroupByReports?: boolean;
 };
 
-function SearchTypeMenu({queryJSON, shouldGroupByReports}: SearchTypeMenuProps) {
+function SearchTypeMenu({queryJSON}: SearchTypeMenuProps) {
     const {type, hash} = queryJSON;
     const styles = useThemeStyles();
     const {singleExecution} = useSingleExecution();
@@ -171,8 +170,8 @@ function SearchTypeMenu({queryJSON, shouldGroupByReports}: SearchTypeMenuProps)
     const isCannedQuery = isCannedSearchQuery(queryJSON);
     const activeItemIndex = isCannedQuery
         ? typeMenuItems.findIndex((item) => {
-              if (shouldGroupByReports) {
-                  return item.translationPath === 'common.expenseReports';
+              if (queryJSON.groupBy === CONST.SEARCH.GROUP_BY.REPORTS) {
+                  return item.translationPath === 'common.expenseReports' && item.type === type;
               }
               return item.type === type;
           })
diff --git a/src/pages/TransactionDuplicate/Confirmation.tsx b/src/pages/TransactionDuplicate/Confirmation.tsx
index 805fda5c298a..10f4fec06539 100644
--- a/src/pages/TransactionDuplicate/Confirmation.tsx
+++ b/src/pages/TransactionDuplicate/Confirmation.tsx
@@ -50,7 +50,7 @@ function Confirmation() {
         (action) => ReportActionsUtils.isMoneyRequestAction(action) && ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID === reviewDuplicates?.transactionID,
     );
 
-    const transactionsMergeParams = useMemo(() => TransactionUtils.buildTransactionsMergeParams(reviewDuplicates, transaction), [reviewDuplicates, transaction]);
+    const transactionsMergeParams = useMemo(() => TransactionUtils.buildMergeDuplicatesParams(reviewDuplicates, transaction), [reviewDuplicates, transaction]);
     const isReportOwner = iouReport?.ownerAccountID === currentUserPersonalDetails?.accountID;
 
     const mergeDuplicates = useCallback(() => {
diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx
index e9dc78b56c1f..a18a50073ceb 100644
--- a/src/pages/WorkspaceSwitcherPage/index.tsx
+++ b/src/pages/WorkspaceSwitcherPage/index.tsx
@@ -2,34 +2,23 @@ import React, {useCallback, useMemo} from 'react';
 import {useOnyx} from 'react-native-onyx';
 import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
 import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import * as Expensicons from '@components/Icon/Expensicons';
 import ScreenWrapper from '@components/ScreenWrapper';
 import SelectionList from '@components/SelectionList';
-import type {ListItem, SectionListDataType} from '@components/SelectionList/types';
 import UserListItem from '@components/SelectionList/UserListItem';
 import useActiveWorkspace from '@hooks/useActiveWorkspace';
 import useDebouncedState from '@hooks/useDebouncedState';
 import useLocalize from '@hooks/useLocalize';
 import useNetwork from '@hooks/useNetwork';
 import useThemeStyles from '@hooks/useThemeStyles';
+import type {WorkspaceListItem} from '@hooks/useWorkspaceList';
+import useWorkspaceList from '@hooks/useWorkspaceList';
 import Navigation from '@libs/Navigation/Navigation';
-import {isPolicyAdmin, shouldShowPolicy, sortWorkspacesBySelected} from '@libs/PolicyUtils';
-import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils';
 import {getWorkspacesBrickRoads, getWorkspacesUnreadStatuses} from '@libs/WorkspacesSettingsUtils';
-import type {BrickRoad} from '@libs/WorkspacesSettingsUtils';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
-import {isEmptyObject} from '@src/types/utils/EmptyObject';
 import switchPolicyAfterInteractions from './switchPolicyAfterInteractions';
 import WorkspaceCardCreateAWorkspace from './WorkspaceCardCreateAWorkspace';
 
-type WorkspaceListItem = {
-    text: string;
-    policyID?: string;
-    isPolicyAdmin?: boolean;
-    brickRoadIndicator?: BrickRoad;
-} & ListItem;
-
 const WorkspaceCardCreateAWorkspaceInstance = <WorkspaceCardCreateAWorkspace />;
 
 function WorkspaceSwitcherPage() {
@@ -79,6 +68,17 @@ function WorkspaceSwitcherPage() {
         [unreadStatusesForPolicies],
     );
 
+    const {sections, shouldShowNoResultsFoundMessage, shouldShowSearchInput, shouldShowCreateWorkspace} = useWorkspaceList({
+        policies,
+        isOffline,
+        currentUserLogin,
+        selectedPolicyID: activeWorkspaceID,
+        searchTerm: debouncedSearchTerm,
+        isWorkspaceSwitcher: true,
+        hasUnreadData,
+        getIndicatorTypeForPolicy,
+    });
+
     const selectPolicy = useCallback(
         (policyID?: string) => {
             const newPolicyID = policyID === activeWorkspaceID ? undefined : policyID;
@@ -91,55 +91,6 @@ function WorkspaceSwitcherPage() {
         [activeWorkspaceID],
     );
 
-    const usersWorkspaces = useMemo<WorkspaceListItem[]>(() => {
-        if (!policies || isEmptyObject(policies)) {
-            return [];
-        }
-
-        return Object.values(policies)
-            .filter((policy) => shouldShowPolicy(policy, !!isOffline, currentUserLogin) && !policy?.isJoinRequestPending)
-            .map((policy) => ({
-                text: policy?.name ?? '',
-                policyID: policy?.id,
-                brickRoadIndicator: getIndicatorTypeForPolicy(policy?.id),
-                icons: [
-                    {
-                        source: policy?.avatarURL ? policy.avatarURL : getDefaultWorkspaceAvatar(policy?.name),
-                        fallbackIcon: Expensicons.FallbackWorkspaceAvatar,
-                        name: policy?.name,
-                        type: CONST.ICON_TYPE_WORKSPACE,
-                        id: policy?.id,
-                    },
-                ],
-                isBold: hasUnreadData(policy?.id),
-                keyForList: policy?.id,
-                isPolicyAdmin: isPolicyAdmin(policy),
-                isSelected: activeWorkspaceID === policy?.id,
-            }));
-    }, [policies, isOffline, currentUserLogin, getIndicatorTypeForPolicy, hasUnreadData, activeWorkspaceID]);
-
-    const filteredAndSortedUserWorkspaces = useMemo<WorkspaceListItem[]>(
-        () =>
-            usersWorkspaces
-                .filter((policy) => policy.text?.toLowerCase().includes(debouncedSearchTerm?.toLowerCase() ?? ''))
-                .sort((policy1, policy2) => sortWorkspacesBySelected({policyID: policy1.policyID, name: policy1.text}, {policyID: policy2.policyID, name: policy2.text}, activeWorkspaceID)),
-        [debouncedSearchTerm, usersWorkspaces, activeWorkspaceID],
-    );
-
-    const sections = useMemo(() => {
-        const options: Array<SectionListDataType<WorkspaceListItem>> = [
-            {
-                data: filteredAndSortedUserWorkspaces,
-                shouldShow: true,
-                indexOffset: 1,
-            },
-        ];
-        return options;
-    }, [filteredAndSortedUserWorkspaces]);
-
-    const headerMessage = filteredAndSortedUserWorkspaces.length === 0 && usersWorkspaces.length ? translate('common.noResultsFound') : '';
-    const shouldShowCreateWorkspace = usersWorkspaces.length === 0;
-
     return (
         <ScreenWrapper
             testID={WorkspaceSwitcherPage.displayName}
@@ -160,10 +111,10 @@ function WorkspaceSwitcherPage() {
                             ListItem={UserListItem}
                             sections={sections}
                             onSelectRow={(option) => selectPolicy(option.policyID)}
-                            textInputLabel={usersWorkspaces.length >= CONST.STANDARD_LIST_ITEM_LIMIT ? translate('common.search') : undefined}
+                            textInputLabel={shouldShowSearchInput ? translate('common.search') : undefined}
                             textInputValue={searchTerm}
                             onChangeText={setSearchTerm}
-                            headerMessage={headerMessage}
+                            headerMessage={shouldShowNoResultsFoundMessage ? translate('common.noResultsFound') : ''}
                             listEmptyContent={WorkspaceCardCreateAWorkspaceInstance}
                             shouldShowListEmptyContent={shouldShowCreateWorkspace}
                             initiallyFocusedOptionKey={activeWorkspaceID ?? CONST.WORKSPACE_SWITCHER.NAME}
diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx
index f6874093ebd0..faf0aeb2e963 100644
--- a/src/pages/home/HeaderView.tsx
+++ b/src/pages/home/HeaderView.tsx
@@ -112,7 +112,6 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
     const [lastDayFreeTrial] = useOnyx(ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL);
     const [account] = useOnyx(ONYXKEYS.ACCOUNT);
     const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`);
-    const [sidePane] = useOnyx(ONYXKEYS.NVP_SIDE_PANE);
     const [isDismissedDiscountBanner, setIsDismissedDiscountBanner] = useState(false);
 
     const {translate} = useLocalize();
@@ -205,7 +204,6 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
     const isParentReportLoading = !!report?.parentReportID && !parentReport;
 
     const isReportInRHP = route.name === SCREENS.SEARCH.REPORT_RHP;
-    const shouldDisplaySidePane = !!sidePane;
     const shouldDisplaySearchRouter = !isReportInRHP || isSmallScreenWidth;
     const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED);
     const isChatUsedForOnboarding = isChatUsedForOnboardingReportUtils(report, onboardingPurposeSelected);
@@ -355,8 +353,8 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
                                     {!shouldUseNarrowLayout && isOpenTaskReport(report, parentReportAction) && <TaskHeaderActionButton report={report} />}
                                     {!isParentReportLoading && canJoin && !shouldUseNarrowLayout && joinButton}
                                 </View>
-                                {shouldDisplaySidePane && <HelpButton style={styles.ml2} />}
-                                {shouldDisplaySearchRouter && <SearchButton style={!shouldDisplaySidePane && styles.ml2} />}
+                                <HelpButton style={styles.ml2} />
+                                {shouldDisplaySearchRouter && <SearchButton style={styles.ml2} />}
                             </View>
                             <ConfirmModal
                                 isVisible={isDeleteTaskConfirmModalVisible}
diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx
index a133eec7b739..55828f162656 100644
--- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx
+++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx
@@ -582,6 +582,8 @@ const ContextMenuActions: ContextMenuAction[] = [
                     const reason = originalMessage?.reason;
                     const violationName = originalMessage?.violationName;
                     Clipboard.setString(translateLocal(`violationDismissal.${violationName}.${reason}` as TranslationPaths));
+                } else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.RESOLVED_DUPLICATES) {
+                    Clipboard.setString(translateLocal('violations.resolvedDuplicates'));
                 } else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_INTEGRATION) {
                     setClipboardMessage(getExportIntegrationMessageHTML(reportAction));
                 } else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.UPDATE_ROOM_DESCRIPTION) {
diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx
index 4208aa96f066..5513d3404d3f 100644
--- a/src/pages/home/report/PureReportActionItem.tsx
+++ b/src/pages/home/report/PureReportActionItem.tsx
@@ -110,6 +110,7 @@ import {
     getIOUForwardedMessage,
     getIOUSubmittedMessage,
     getIOUUnapprovedMessage,
+    getPolicyChangeMessage,
     getReportAutomaticallyApprovedMessage,
     getReportAutomaticallySubmittedMessage,
     getWhisperDisplayNames,
@@ -877,12 +878,16 @@ function PureReportActionItem({
             children = <ReportActionItemBasicMessage message={getReportActionText(action)} />;
         } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.UNHOLD) {
             children = <ReportActionItemBasicMessage message={translate('iou.unheldExpense')} />;
+        } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY) {
+            children = <ReportActionItemBasicMessage message={getPolicyChangeMessage(action)} />;
         } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.DELETED_TRANSACTION) {
             children = <ReportActionItemBasicMessage message={getDeletedTransactionMessage(action)} />;
         } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION) {
             children = <ReportActionItemBasicMessage message={translate('systemMessage.mergedWithCashTransaction')} />;
         } else if (isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION)) {
             children = <ReportActionItemBasicMessage message={getDismissedViolationMessageText(getOriginalMessage(action))} />;
+        } else if (isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.RESOLVED_DUPLICATES)) {
+            children = <ReportActionItemBasicMessage message={translate('violations.resolvedDuplicates')} />;
         } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_NAME) {
             children = <ReportActionItemBasicMessage message={getWorkspaceNameUpdatedMessage(action)} />;
         } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_DESCRIPTION) {
diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx
index 69373cb78ff4..92bed91f2930 100644
--- a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx
+++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx
@@ -15,13 +15,13 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'
 import useDebounce from '@hooks/useDebounce';
 import useLocalize from '@hooks/useLocalize';
 import localeCompare from '@libs/LocaleCompare';
-import * as LoginUtils from '@libs/LoginUtils';
-import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import {areEmailsFromSamePrivateDomain} from '@libs/LoginUtils';
+import {getDisplayNameOrDefault} from '@libs/PersonalDetailsUtils';
 import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils';
-import * as ReportUtils from '@libs/ReportUtils';
-import * as SuggestionsUtils from '@libs/SuggestionUtils';
+import {canReportBeMentionedWithinPolicy, doesReportBelongToWorkspace, getDisplayNameForParticipant, isGroupChat, isReportParticipant} from '@libs/ReportUtils';
+import {trimLeadingSpace} from '@libs/SuggestionUtils';
 import {isValidRoomName} from '@libs/ValidationUtils';
-import * as ReportUserActions from '@userActions/Report';
+import {searchInServer} from '@userActions/Report';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import type {PersonalDetails, PersonalDetailsList, Report} from '@src/types/onyx';
@@ -58,7 +58,7 @@ type SuggestionPersonalDetailsList = Record<
 >;
 
 function getDisplayName(details: PersonalDetails) {
-    const displayNameFromAccountID = ReportUtils.getDisplayNameForParticipant({accountID: details.accountID});
+    const displayNameFromAccountID = getDisplayNameForParticipant({accountID: details.accountID});
     if (!displayNameFromAccountID) {
         return details.login?.length ? details.login : '';
     }
@@ -102,7 +102,7 @@ function SuggestionMention(
     // Smaller weight means higher order in suggestion list
     const getPersonalDetailsWeight = useCallback(
         (detail: PersonalDetails, policyEmployeeAccountIDs: number[]): number => {
-            if (ReportUtils.isReportParticipant(detail.accountID, currentReport)) {
+            if (isReportParticipant(detail.accountID, currentReport)) {
                 return 0;
             }
             if (policyEmployeeAccountIDs.includes(detail.accountID)) {
@@ -114,7 +114,7 @@ function SuggestionMention(
     );
     const weightedPersonalDetails: PersonalDetailsList | SuggestionPersonalDetailsList | undefined = useMemo(() => {
         const policyEmployeeAccountIDs = getPolicyEmployeeAccountIDs(policyID);
-        if (!ReportUtils.isGroupChat(currentReport) && !ReportUtils.doesReportBelongToWorkspace(currentReport, policyEmployeeAccountIDs, policyID)) {
+        if (!isGroupChat(currentReport) && !doesReportBelongToWorkspace(currentReport, policyEmployeeAccountIDs, policyID)) {
             return personalDetails;
         }
         return lodashMapValues(personalDetails, (detail) =>
@@ -157,7 +157,7 @@ function SuggestionMention(
         useCallback(() => {
             const foundSuggestionsCount = suggestionValues.suggestedMentions.length;
             if (suggestionValues.prefixType === '#' && foundSuggestionsCount < 5 && isGroupPolicyReport) {
-                ReportUserActions.searchInServer(suggestionValues.mentionPrefix, policyID);
+                searchInServer(suggestionValues.mentionPrefix, policyID);
             }
         }, [suggestionValues.suggestedMentions.length, suggestionValues.prefixType, suggestionValues.mentionPrefix, policyID, isGroupPolicyReport]),
         CONST.TIMING.SEARCH_OPTION_LIST_DEBOUNCE_TIME,
@@ -169,7 +169,7 @@ function SuggestionMention(
                 return displayText;
             }
             // If the emails are not in the same private domain, we also return the displayText
-            if (!LoginUtils.areEmailsFromSamePrivateDomain(displayText, currentUserPersonalDetails.login ?? '')) {
+            if (!areEmailsFromSamePrivateDomain(displayText, currentUserPersonalDetails.login ?? '')) {
                 return Str.removeSMSDomain(displayText);
             }
 
@@ -203,7 +203,7 @@ function SuggestionMention(
             const mentionCode = getMentionCode(mentionObject, suggestionValues.prefixType);
             const commentAfterMention = value.slice(suggestionValues.atSignIndex + suggestionValues.mentionPrefix.length + 1);
 
-            updateComment(`${commentBeforeAtSign}${mentionCode} ${SuggestionsUtils.trimLeadingSpace(commentAfterMention)}`, true);
+            updateComment(`${commentBeforeAtSign}${mentionCode} ${trimLeadingSpace(commentAfterMention)}`, true);
             const selectionPosition = suggestionValues.atSignIndex + mentionCode.length + CONST.SPACE_LENGTH;
             setSelection({
                 start: selectionPosition,
@@ -280,7 +280,9 @@ function SuggestionMention(
                 });
             }
 
-            const filteredPersonalDetails = Object.values(personalDetailsParam ?? {}).filter((detail, index, array) => {
+            // Create a set to track logins that have already been seen
+            const seenLogins = new Set<string>();
+            const filteredPersonalDetails = Object.values(personalDetailsParam ?? {}).filter((detail) => {
                 // If we don't have user's primary login, that member is not known to the current user and hence we do not allow them to be mentioned
                 if (!detail?.login || detail.isOptimisticPersonalDetail) {
                     return false;
@@ -289,7 +291,7 @@ function SuggestionMention(
                 if (CONST.RESTRICTED_EMAILS.includes(detail.login) || CONST.RESTRICTED_ACCOUNT_IDS.includes(detail.accountID)) {
                     return false;
                 }
-                const displayName = PersonalDetailsUtils.getDisplayNameOrDefault(detail);
+                const displayName = getDisplayNameOrDefault(detail);
                 const displayText = displayName === formatPhoneNumber(detail.login) ? displayName : `${displayName} ${detail.login}`;
                 if (searchValue && !displayText.toLowerCase().includes(searchValue.toLowerCase())) {
                     return false;
@@ -304,7 +306,11 @@ function SuggestionMention(
 
                 // on staging server, in specific cases (see issue) BE returns duplicated personalDetails
                 // entries with the same `login` which we need to filter out
-                return array.findIndex((arrayDetail) => arrayDetail?.login === detail?.login) === index;
+                if (seenLogins.has(detail.login)) {
+                    return false;
+                }
+                seenLogins.add(detail.login);
+                return true;
             }) as Array<PersonalDetails & {weight: number}>;
 
             // At this point we are sure that the details are not null, since empty user details have been filtered in the previous step
@@ -312,7 +318,7 @@ function SuggestionMention(
 
             sortedPersonalDetails.slice(0, CONST.AUTO_COMPLETE_SUGGESTER.MAX_AMOUNT_OF_SUGGESTIONS - suggestions.length).forEach((detail) => {
                 suggestions.push({
-                    text: formatLoginPrivateDomain(PersonalDetailsUtils.getDisplayNameOrDefault(detail), detail?.login),
+                    text: formatLoginPrivateDomain(getDisplayNameOrDefault(detail), detail?.login),
                     alternateText: `@${formatLoginPrivateDomain(detail?.login, detail?.login)}`,
                     handle: detail?.login,
                     icons: [
@@ -336,7 +342,7 @@ function SuggestionMention(
         (searchTerm: string, reportBatch: OnyxCollection<Report>): Mention[] => {
             const filteredRoomMentions: Mention[] = [];
             Object.values(reportBatch ?? {}).forEach((report) => {
-                if (!ReportUtils.canReportBeMentionedWithinPolicy(report, policyID)) {
+                if (!canReportBeMentionedWithinPolicy(report, policyID)) {
                     return;
                 }
                 if (report?.reportName?.toLowerCase().includes(searchTerm.toLowerCase())) {
diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx
index 6924725eb99b..5c140589e4f3 100644
--- a/src/pages/home/report/ReportActionsList.tsx
+++ b/src/pages/home/report/ReportActionsList.tsx
@@ -177,6 +177,8 @@ function ReportActionsList({
     const [accountID] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.accountID});
     const participantsContext = useContext(PersonalDetailsContext);
 
+    const [isScrollToBottomEnabled, setIsScrollToBottomEnabled] = useState(false);
+
     useEffect(() => {
         const unsubscriber = Visibility.onVisibilityChange(() => {
             setIsVisible(Visibility.isVisible());
@@ -458,10 +460,11 @@ function ReportActionsList({
                     Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(report.reportID));
                     return;
                 }
-                reportScrollManager.scrollToBottom();
+
+                setIsScrollToBottomEnabled(true);
             });
         },
-        [reportScrollManager, report.reportID],
+        [report.reportID],
     );
     useEffect(() => {
         // Why are we doing this, when in the cleanup of the useEffect we are already calling the unsubscribe function?
@@ -667,8 +670,12 @@ function ReportActionsList({
     const onLayoutInner = useCallback(
         (event: LayoutChangeEvent) => {
             onLayout(event);
+            if (isScrollToBottomEnabled) {
+                reportScrollManager.scrollToBottom();
+                setIsScrollToBottomEnabled(false);
+            }
         },
-        [onLayout],
+        [isScrollToBottomEnabled, onLayout, reportScrollManager],
     );
     const onContentSizeChangeInner = useCallback(
         (w: number, h: number) => {
diff --git a/src/pages/home/report/withReportOrNotFound.tsx b/src/pages/home/report/withReportOrNotFound.tsx
index 55fc168d3d7c..9c94d2c3f501 100644
--- a/src/pages/home/report/withReportOrNotFound.tsx
+++ b/src/pages/home/report/withReportOrNotFound.tsx
@@ -5,19 +5,20 @@ import React, {useEffect} from 'react';
 import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
 import {useOnyx} from 'react-native-onyx';
 import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import {openReport} from '@libs/actions/Report';
 import getComponentDisplayName from '@libs/getComponentDisplayName';
 import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
-import * as ReportUtils from '@libs/ReportUtils';
+import {canAccessReport} from '@libs/ReportUtils';
 import type {
     ParticipantsNavigatorParamList,
     PrivateNotesNavigatorParamList,
+    ReportChangeWorkspaceNavigatorParamList,
     ReportDescriptionNavigatorParamList,
     ReportDetailsNavigatorParamList,
     ReportSettingsNavigatorParamList,
     RoomMembersNavigatorParamList,
 } from '@navigation/types';
 import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
-import * as Report from '@userActions/Report';
 import ONYXKEYS from '@src/ONYXKEYS';
 import type SCREENS from '@src/SCREENS';
 import type * as OnyxTypes from '@src/types/onyx';
@@ -49,7 +50,8 @@ type ScreenProps =
     | PlatformStackScreenProps<ReportDetailsNavigatorParamList, typeof SCREENS.REPORT_DETAILS.ROOT>
     | PlatformStackScreenProps<ReportDetailsNavigatorParamList, typeof SCREENS.REPORT_DETAILS.SHARE_CODE>
     | PlatformStackScreenProps<ReportSettingsNavigatorParamList, typeof SCREENS.REPORT_SETTINGS.ROOT>
-    | PlatformStackScreenProps<RoomMembersNavigatorParamList, typeof SCREENS.ROOM_MEMBERS.DETAILS>;
+    | PlatformStackScreenProps<RoomMembersNavigatorParamList, typeof SCREENS.ROOM_MEMBERS.DETAILS>
+    | PlatformStackScreenProps<ReportChangeWorkspaceNavigatorParamList, typeof SCREENS.REPORT_CHANGE_WORKSPACE.ROOT>;
 
 type WithReportOrNotFoundProps = WithReportOrNotFoundOnyxProps & {
     route: ScreenProps['route'];
@@ -82,13 +84,13 @@ export default function (
                     return;
                 }
 
-                Report.openReport(props.route.params.reportID);
+                openReport(props.route.params.reportID);
                 // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
             }, [shouldFetchReport, isReportLoaded, props.route.params.reportID]);
 
             if (shouldRequireReportID || isReportIdInRoute) {
                 const shouldShowFullScreenLoadingIndicator = !isReportLoaded && (isLoadingReportData !== false || shouldFetchReport);
-                const shouldShowNotFoundPage = !isReportLoaded || !ReportUtils.canAccessReport(report, policies, betas);
+                const shouldShowNotFoundPage = !isReportLoaded || !canAccessReport(report, policies, betas);
 
                 // If the content was shown, but it's not anymore, that means the report was deleted, and we are probably navigating out of this screen.
                 // Return null for this case to avoid rendering FullScreenLoadingIndicator or NotFoundPage when animating transition.
diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx
index 6f064d136182..e04a0a6ed83b 100644
--- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx
+++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx
@@ -27,7 +27,7 @@ import useWindowDimensions from '@hooks/useWindowDimensions';
 import {startMoneyRequest} from '@libs/actions/IOU';
 import {openExternalLink, openOldDotLink} from '@libs/actions/Link';
 import {navigateToQuickAction} from '@libs/actions/QuickActionNavigation';
-import {startNewChat} from '@libs/actions/Report';
+import {createNewReport, startNewChat} from '@libs/actions/Report';
 import {isAnonymousUser} from '@libs/actions/Session';
 import {canActionTask as canActionTaskUtils, canModifyTask as canModifyTaskUtils, completeTask} from '@libs/actions/Task';
 import {setSelfTourViewed} from '@libs/actions/Welcome';
@@ -36,7 +36,13 @@ import interceptAnonymousUser from '@libs/interceptAnonymousUser';
 import navigateAfterInteraction from '@libs/Navigation/navigateAfterInteraction';
 import Navigation from '@libs/Navigation/Navigation';
 import {hasSeenTourSelector} from '@libs/onboardingSelectors';
-import {areAllGroupPoliciesExpenseChatDisabled, canSendInvoice as canSendInvoicePolicyUtils, shouldShowPolicy} from '@libs/PolicyUtils';
+import {
+    areAllGroupPoliciesExpenseChatDisabled,
+    canSendInvoice as canSendInvoicePolicyUtils,
+    getGroupPaidPoliciesWithExpenseChatEnabled,
+    isPaidGroupPolicy,
+    shouldShowPolicy,
+} from '@libs/PolicyUtils';
 import {canCreateRequest, generateReportID, getDisplayNameForParticipant, getIcons, getReportName, getWorkspaceChats, isArchivedReport, isPolicyExpenseChat} from '@libs/ReportUtils';
 import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils';
 import {getNavatticURL} from '@libs/TourUtils';
@@ -195,7 +201,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT
     const prevIsFocused = usePrevious(isFocused);
     const {isOffline} = useNetwork();
 
-    const {canUseSpotnanaTravel} = usePermissions();
+    const {canUseSpotnanaTravel, canUseTableReportView} = usePermissions();
     const canSendInvoice = useMemo(() => canSendInvoicePolicyUtils(allPolicies as OnyxCollection<OnyxTypes.Policy>, session?.email), [allPolicies, session?.email]);
     const isValidReport = !(isEmptyObject(quickActionReport) || isArchivedReport(reportNameValuePairs));
     const {environment} = useEnvironment();
@@ -212,6 +218,8 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT
         isCreateMenuActive && (!shouldUseNarrowLayout || isFocused),
     );
 
+    const groupPoliciesWithChatEnabled = useMemo(() => getGroupPaidPoliciesWithExpenseChatEnabled(allPolicies as OnyxCollection<OnyxTypes.Policy>), [allPolicies]);
+
     /**
      * There are scenarios where users who have not yet had their group workspace-chats in NewDot (isPolicyExpenseChatEnabled). In those scenarios, things can get confusing if they try to submit/track expenses. To address this, we block them from Creating, Tracking, Submitting expenses from NewDot if they are:
      * 1. on at least one group policy
@@ -470,6 +478,38 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT
 
     const menuItems = [
         ...expenseMenuItems,
+        ...(canUseTableReportView
+            ? [
+                  {
+                      icon: Expensicons.Document,
+                      text: translate('report.newReport.createReport'),
+                      onSelected: () => {
+                          interceptAnonymousUser(() => {
+                              if (groupPoliciesWithChatEnabled.length === 0) {
+                                  setModalVisible(true);
+                                  return;
+                              }
+
+                              // If the user's default workspace is a paid group workspace with chat enabled, we create a report with it by default
+                              if (activePolicy && activePolicy.isPolicyExpenseChatEnabled && isPaidGroupPolicy(activePolicy)) {
+                                  const createdReportID = createNewReport(currentUserPersonalDetails, activePolicyID);
+                                  Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: createdReportID, backTo: Navigation.getActiveRoute()}));
+                                  return;
+                              }
+
+                              if (groupPoliciesWithChatEnabled.length === 1) {
+                                  const createdReportID = createNewReport(currentUserPersonalDetails, groupPoliciesWithChatEnabled.at(0)?.id);
+                                  Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: createdReportID, backTo: Navigation.getActiveRoute()}));
+                                  return;
+                              }
+
+                              // If the user's default workspace is personal and the user has more than one group workspace which is paid and has chat enabled, we need to redirect them to the workspace selection screen
+                              Navigation.navigate(ROUTES.NEW_REPORT_WORKSPACE_SELECTION);
+                          });
+                      },
+                  },
+              ]
+            : []),
         {
             icon: Expensicons.ChatBubble,
             text: translate('sidebarScreen.fabNewChat'),
diff --git a/src/pages/home/sidebar/SidebarLinks.tsx b/src/pages/home/sidebar/SidebarLinks.tsx
index 2e84f9805f6a..1985c6500d52 100644
--- a/src/pages/home/sidebar/SidebarLinks.tsx
+++ b/src/pages/home/sidebar/SidebarLinks.tsx
@@ -68,7 +68,16 @@ function SidebarLinks({insets, optionListItems, isLoading, priorityMode = CONST.
             // or when continuously clicking different LHNs, only apply to small screen
             // since getTopmostReportId always returns on other devices
             const reportActionID = Navigation.getTopmostReportActionId();
-            if ((option.reportID === Navigation.getTopmostReportId() && !reportActionID) || (shouldUseNarrowLayout && isActiveReport(option.reportID) && !reportActionID)) {
+
+            // Prevent opening a new Report page if the user quickly taps on another conversation
+            // before the first one is displayed.
+            const shouldBlockReportNavigation = Navigation.getActiveRoute() !== '/home' && shouldUseNarrowLayout;
+
+            if (
+                (option.reportID === Navigation.getTopmostReportId() && !reportActionID) ||
+                (shouldUseNarrowLayout && isActiveReport(option.reportID) && !reportActionID) ||
+                shouldBlockReportNavigation
+            ) {
                 return;
             }
             Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(option.reportID));
diff --git a/src/pages/iou/ReceiptDropUI.tsx b/src/pages/iou/ReceiptDropUI.tsx
index db7ff0c6c57a..8b57718a1f41 100644
--- a/src/pages/iou/ReceiptDropUI.tsx
+++ b/src/pages/iou/ReceiptDropUI.tsx
@@ -16,13 +16,13 @@ type ReceiptDropUIProps = {
     receiptImageTopPosition?: number;
 };
 
-function ReceiptDropUI({onDrop, receiptImageTopPosition = 0}: ReceiptDropUIProps) {
+function ReceiptDropUI({onDrop, receiptImageTopPosition}: ReceiptDropUIProps) {
     const styles = useThemeStyles();
     const {translate} = useLocalize();
     return (
         <DragAndDropConsumer onDrop={onDrop}>
             <View style={[styles.fileDropOverlay, styles.w100, styles.h100, styles.justifyContentCenter, styles.alignItemsCenter]}>
-                <View style={styles.fileUploadImageWrapper(receiptImageTopPosition)}>
+                <View style={receiptImageTopPosition ? styles.fileUploadImageWrapper(receiptImageTopPosition) : undefined}>
                     <ImageSVG
                         src={ReceiptUpload}
                         contentFit="contain"
diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
index c133e833fc6d..d67be8b55554 100644
--- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
+++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
@@ -1,13 +1,18 @@
+import {Str} from 'expensify-common';
 import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
 import {View} from 'react-native';
 import type {OnyxEntry} from 'react-native-onyx';
 import {useOnyx} from 'react-native-onyx';
+import type {FileObject} from '@components/AttachmentModal';
+import ConfirmModal from '@components/ConfirmModal';
+import DragAndDropProvider from '@components/DragAndDrop/Provider';
 import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
 import HeaderWithBackButton from '@components/HeaderWithBackButton';
 import * as Expensicons from '@components/Icon/Expensicons';
 import LocationPermissionModal from '@components/LocationPermissionModal';
 import MoneyRequestConfirmationList from '@components/MoneyRequestConfirmationList';
 import {usePersonalDetails} from '@components/OnyxProvider';
+import PDFThumbnail from '@components/PDFThumbnail';
 import ScreenWrapper from '@components/ScreenWrapper';
 import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
 import useFetchRoute from '@hooks/useFetchRoute';
@@ -17,7 +22,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
 import useWindowDimensions from '@hooks/useWindowDimensions';
 import DateUtils from '@libs/DateUtils';
 import {canUseTouchScreen} from '@libs/DeviceCapabilities';
-import {isLocalFile as isLocalFileFileUtils} from '@libs/fileDownload/FileUtils';
+import {isLocalFile as isLocalFileFileUtils, resizeImageIfNeeded, validateReceipt} from '@libs/fileDownload/FileUtils';
 import getCurrentPosition from '@libs/getCurrentPosition';
 import {isMovingTransactionFromTrackExpense as isMovingTransactionFromTrackExpenseIOUUtils, navigateToStartMoneyRequestStep, shouldUseTransactionDraft} from '@libs/IOUUtils';
 import Log from '@libs/Log';
@@ -27,6 +32,7 @@ import {getParticipantsOption, getReportOption} from '@libs/OptionsListUtils';
 import {generateReportID, getBankAccountRoute} from '@libs/ReportUtils';
 import playSound, {SOUNDS} from '@libs/Sound';
 import {getDefaultTaxCode, getRateID, getRequestType, getValidWaypoints} from '@libs/TransactionUtils';
+import ReceiptDropUI from '@pages/iou/ReceiptDropUI';
 import type {GpsPoint} from '@userActions/IOU';
 import {
     createDistanceRequest as createDistanceRequestIOUActions,
@@ -38,6 +44,7 @@ import {
     sendMoneyWithWallet,
     setMoneyRequestBillable,
     setMoneyRequestCategory,
+    setMoneyRequestReceipt,
     splitBill,
     splitBillAndOpenReport,
     startMoneyRequest,
@@ -48,6 +55,7 @@ import {
 } from '@userActions/IOU';
 import {openDraftWorkspaceRequest} from '@userActions/Policy/Policy';
 import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
 import type SCREENS from '@src/SCREENS';
@@ -93,6 +101,13 @@ function IOURequestStepConfirmation({
     const {isOffline} = useNetwork();
     const [startLocationPermissionFlow, setStartLocationPermissionFlow] = useState(false);
     const [selectedParticipantList, setSelectedParticipantList] = useState<Participant[]>([]);
+    const [isDraggingOver, setIsDraggingOver] = useState(false);
+
+    const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false);
+    const [attachmentInvalidReasonTitle, setAttachmentInvalidReasonTitle] = useState<TranslationPaths>();
+    const [attachmentInvalidReason, setAttachmentValidReason] = useState<TranslationPaths>();
+    const [pdfFile, setPdfFile] = useState<null | FileObject>(null);
+    const [isLoadingReceipt, setIsLoadingReceipt] = useState(false);
 
     const [receiptFile, setReceiptFile] = useState<OnyxEntry<Receipt>>();
     const requestType = getRequestType(transaction);
@@ -156,6 +171,16 @@ function IOURequestStepConfirmation({
     const isPolicyExpenseChat = useMemo(() => participants?.some((participant) => participant.isPolicyExpenseChat), [participants]);
     const formHasBeenSubmitted = useRef(false);
 
+    const confirmModalPrompt = useMemo(() => {
+        if (!attachmentInvalidReason) {
+            return '';
+        }
+        if (attachmentInvalidReason === 'attachmentPicker.sizeExceededWithLimit') {
+            return translate(attachmentInvalidReason, {maxUploadSizeInMB: CONST.API_ATTACHMENT_VALIDATIONS.RECEIPT_MAX_SIZE / (1024 * 1024)});
+        }
+        return translate(attachmentInvalidReason);
+    }, [attachmentInvalidReason, translate]);
+
     useFetchRoute(transaction, transaction?.comment?.waypoints, action, shouldUseTransactionDraft(action) ? CONST.TRANSACTION.STATE.DRAFT : CONST.TRANSACTION.STATE.CURRENT);
 
     useEffect(() => {
@@ -208,6 +233,51 @@ function IOURequestStepConfirmation({
         // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
     }, [transactionID, requestType, defaultCategory, policy?.id]);
 
+    /**
+     * Sets the upload receipt error modal content when an invalid receipt is uploaded
+     */
+    const setUploadReceiptError = (isInvalid: boolean, title: TranslationPaths, reason: TranslationPaths) => {
+        setIsAttachmentInvalid(isInvalid);
+        setAttachmentInvalidReasonTitle(title);
+        setAttachmentValidReason(reason);
+        setPdfFile(null);
+    };
+
+    const hideReceiptModal = () => {
+        setIsAttachmentInvalid(false);
+    };
+
+    /**
+     * Sets the Receipt object when dragging and dropping a file
+     */
+    const setReceiptOnDrop = (originalFile: FileObject, isPdfValidated?: boolean) => {
+        validateReceipt(originalFile, setUploadReceiptError).then((isFileValid) => {
+            if (!isFileValid) {
+                return;
+            }
+
+            // If we have a pdf file and if it is not validated then set the pdf file for validation and return
+            if (Str.isPDF(originalFile.name ?? '') && !isPdfValidated) {
+                setPdfFile(originalFile);
+                setIsLoadingReceipt(true);
+                return;
+            }
+
+            // With the image size > 24MB, we use manipulateAsync to resize the image.
+            // It takes a long time so we should display a loading indicator while the resize image progresses.
+            if (Str.isImage(originalFile.name ?? '') && (originalFile?.size ?? 0) > CONST.API_ATTACHMENT_VALIDATIONS.MAX_SIZE) {
+                setIsLoadingReceipt(true);
+            }
+            resizeImageIfNeeded(originalFile).then((file) => {
+                setIsLoadingReceipt(false);
+                // Store the receipt on the transaction object in Onyx
+                const source = URL.createObjectURL(file as Blob);
+                // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+                setMoneyRequestReceipt(transactionID, source, file.name || '', true);
+            });
+        });
+    };
+
     const navigateBack = useCallback(() => {
         // If the action is categorize and there's no policies other than personal one, we simply call goBack(), i.e: dismiss the whole flow together
         // We don't need to subscribe to policy_ collection as we only need to check on the latest collection value
@@ -746,79 +816,125 @@ function IOURequestStepConfirmation({
         return <FullScreenLoadingIndicator />;
     }
 
+    const PDFThumbnailView = pdfFile ? (
+        <PDFThumbnail
+            style={styles.invisiblePDF}
+            previewSourceURL={pdfFile.uri ?? ''}
+            onLoadSuccess={() => {
+                setPdfFile(null);
+                setIsLoadingReceipt(false);
+                setReceiptOnDrop(pdfFile, true);
+            }}
+            onPassword={() => {
+                setIsLoadingReceipt(false);
+                setUploadReceiptError(true, 'attachmentPicker.attachmentError', 'attachmentPicker.protectedPDFNotSupported');
+            }}
+            onLoadError={() => {
+                setIsLoadingReceipt(false);
+                setUploadReceiptError(true, 'attachmentPicker.attachmentError', 'attachmentPicker.errorWhileSelectingCorruptedAttachment');
+            }}
+        />
+    ) : null;
+
+    const shouldShowThreeDotsButton =
+        requestType === CONST.IOU.REQUEST_TYPE.MANUAL && (iouType === CONST.IOU.TYPE.SUBMIT || iouType === CONST.IOU.TYPE.TRACK) && !isMovingTransactionFromTrackExpense;
+
     return (
         <ScreenWrapper
             shouldEnableMaxHeight={canUseTouchScreen()}
             testID={IOURequestStepConfirmation.displayName}
+            headerGapStyles={isDraggingOver ? [styles.isDraggingOver] : []}
         >
-            <View style={styles.flex1}>
-                <HeaderWithBackButton
-                    title={headerTitle}
-                    onBackButtonPress={navigateBack}
-                    shouldShowThreeDotsButton={
-                        requestType === CONST.IOU.REQUEST_TYPE.MANUAL && (iouType === CONST.IOU.TYPE.SUBMIT || iouType === CONST.IOU.TYPE.TRACK) && !isMovingTransactionFromTrackExpense
-                    }
-                    threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)}
-                    threeDotsMenuItems={[
-                        {
-                            icon: Expensicons.Receipt,
-                            text: translate('receipt.addReceipt'),
-                            onSelected: navigateToAddReceipt,
-                        },
-                    ]}
-                />
-                {isLoading && <FullScreenLoadingIndicator />}
-                {!!gpsRequired && (
-                    <LocationPermissionModal
-                        startPermissionFlow={startLocationPermissionFlow}
-                        resetPermissionFlow={() => setStartLocationPermissionFlow(false)}
-                        onGrant={() => {
-                            navigateAfterInteraction(() => {
-                                createTransaction(selectedParticipantList, true);
-                            });
-                        }}
-                        onDeny={() => {
-                            updateLastLocationPermissionPrompt();
-                            navigateAfterInteraction(() => {
-                                createTransaction(selectedParticipantList, false);
-                            });
-                        }}
-                        onInitialGetLocationCompleted={() => {
-                            setIsConfirming(false);
+            <DragAndDropProvider
+                setIsDraggingOver={setIsDraggingOver}
+                isDisabled={!shouldShowThreeDotsButton}
+            >
+                <View style={styles.flex1}>
+                    <HeaderWithBackButton
+                        title={headerTitle}
+                        onBackButtonPress={navigateBack}
+                        shouldShowThreeDotsButton={shouldShowThreeDotsButton}
+                        threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)}
+                        threeDotsMenuItems={[
+                            {
+                                icon: Expensicons.Receipt,
+                                text: translate('receipt.addReceipt'),
+                                onSelected: navigateToAddReceipt,
+                            },
+                        ]}
+                    />
+                    {(isLoading || isLoadingReceipt) && <FullScreenLoadingIndicator />}
+                    {PDFThumbnailView}
+                    <ReceiptDropUI
+                        onDrop={(e) => {
+                            const file = e?.dataTransfer?.files[0];
+                            if (file) {
+                                file.uri = URL.createObjectURL(file);
+                                setReceiptOnDrop(file);
+                            }
                         }}
                     />
-                )}
-                <MoneyRequestConfirmationList
-                    transaction={transaction}
-                    selectedParticipants={participants}
-                    iouAmount={Math.abs(transaction?.amount ?? 0)}
-                    iouAttendees={transaction?.attendees ?? []}
-                    iouComment={transaction?.comment?.comment ?? ''}
-                    iouCurrencyCode={transaction?.currency}
-                    iouIsBillable={transaction?.billable}
-                    onToggleBillable={setBillable}
-                    iouCategory={transaction?.category}
-                    onConfirm={onConfirm}
-                    onSendMoney={sendMoney}
-                    receiptPath={receiptPath}
-                    receiptFilename={receiptFilename}
-                    iouType={iouType}
-                    reportID={reportID}
-                    isPolicyExpenseChat={isPolicyExpenseChat}
-                    policyID={getIOURequestPolicyID(transaction, report)}
-                    bankAccountRoute={getBankAccountRoute(report)}
-                    iouMerchant={transaction?.merchant}
-                    iouCreated={transaction?.created}
-                    isDistanceRequest={isDistanceRequest}
-                    isPerDiemRequest={isPerDiemRequest}
-                    shouldShowSmartScanFields={isMovingTransactionFromTrackExpense ? transaction?.amount !== 0 : requestType !== CONST.IOU.REQUEST_TYPE.SCAN}
-                    action={action}
-                    payeePersonalDetails={payeePersonalDetails}
-                    shouldPlaySound={iouType === CONST.IOU.TYPE.PAY}
-                    isConfirmed={isConfirmed}
-                    isConfirming={isConfirming}
-                />
-            </View>
+                    <ConfirmModal
+                        title={attachmentInvalidReasonTitle ? translate(attachmentInvalidReasonTitle) : ''}
+                        onConfirm={hideReceiptModal}
+                        onCancel={hideReceiptModal}
+                        isVisible={isAttachmentInvalid}
+                        prompt={confirmModalPrompt}
+                        confirmText={translate('common.close')}
+                        shouldShowCancelButton={false}
+                    />
+                    {!!gpsRequired && (
+                        <LocationPermissionModal
+                            startPermissionFlow={startLocationPermissionFlow}
+                            resetPermissionFlow={() => setStartLocationPermissionFlow(false)}
+                            onGrant={() => {
+                                navigateAfterInteraction(() => {
+                                    createTransaction(selectedParticipantList, true);
+                                });
+                            }}
+                            onDeny={() => {
+                                updateLastLocationPermissionPrompt();
+                                navigateAfterInteraction(() => {
+                                    createTransaction(selectedParticipantList, false);
+                                });
+                            }}
+                            onInitialGetLocationCompleted={() => {
+                                setIsConfirming(false);
+                            }}
+                        />
+                    )}
+                    <MoneyRequestConfirmationList
+                        transaction={transaction}
+                        selectedParticipants={participants}
+                        iouAmount={Math.abs(transaction?.amount ?? 0)}
+                        iouAttendees={transaction?.attendees ?? []}
+                        iouComment={transaction?.comment?.comment ?? ''}
+                        iouCurrencyCode={transaction?.currency}
+                        iouIsBillable={transaction?.billable}
+                        onToggleBillable={setBillable}
+                        iouCategory={transaction?.category}
+                        onConfirm={onConfirm}
+                        onSendMoney={sendMoney}
+                        receiptPath={receiptPath}
+                        receiptFilename={receiptFilename}
+                        iouType={iouType}
+                        reportID={reportID}
+                        isPolicyExpenseChat={isPolicyExpenseChat}
+                        policyID={getIOURequestPolicyID(transaction, report)}
+                        bankAccountRoute={getBankAccountRoute(report)}
+                        iouMerchant={transaction?.merchant}
+                        iouCreated={transaction?.created}
+                        isDistanceRequest={isDistanceRequest}
+                        isPerDiemRequest={isPerDiemRequest}
+                        shouldShowSmartScanFields={isMovingTransactionFromTrackExpense ? transaction?.amount !== 0 : requestType !== CONST.IOU.REQUEST_TYPE.SCAN}
+                        action={action}
+                        payeePersonalDetails={payeePersonalDetails}
+                        shouldPlaySound={iouType === CONST.IOU.TYPE.PAY}
+                        isConfirmed={isConfirmed}
+                        isConfirming={isConfirming}
+                    />
+                </View>
+            </DragAndDropProvider>
         </ScreenWrapper>
     );
 }
diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx
index 3cdb62e0d42a..5817ab06e111 100644
--- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx
+++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx
@@ -5,7 +5,6 @@ import {ActivityIndicator, PanResponder, PixelRatio, View} from 'react-native';
 import {useOnyx} from 'react-native-onyx';
 import {RESULTS} from 'react-native-permissions';
 import type Webcam from 'react-webcam';
-import type {TupleToUnion} from 'type-fest';
 import Hand from '@assets/images/hand.svg';
 import ReceiptUpload from '@assets/images/receipt-upload.svg';
 import Shutter from '@assets/images/shutter.svg';
@@ -31,7 +30,7 @@ import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
 import {clearUserLocation, setUserLocation} from '@libs/actions/UserLocation';
 import {isMobile, isMobileWebKit} from '@libs/Browser';
-import {base64ToFile, resizeImageIfNeeded, splitExtensionFromFileName, validateImageForCorruption} from '@libs/fileDownload/FileUtils';
+import {base64ToFile, resizeImageIfNeeded, validateReceipt} from '@libs/fileDownload/FileUtils';
 import getCurrentPosition from '@libs/getCurrentPosition';
 import {shouldStartLocationPermissionFlow} from '@libs/IOUUtils';
 import Log from '@libs/Log';
@@ -232,7 +231,7 @@ function IOURequestStepScan({
         });
     }, [transaction?.amount, iouType]);
 
-    const hideRecieptModal = () => {
+    const hideReceiptModal = () => {
         setIsAttachmentInvalid(false);
     };
 
@@ -246,36 +245,6 @@ function IOURequestStepScan({
         setPdfFile(null);
     };
 
-    function validateReceipt(file: FileObject) {
-        return validateImageForCorruption(file)
-            .then(() => {
-                const {fileExtension} = splitExtensionFromFileName(file?.name ?? '');
-                if (
-                    !CONST.API_ATTACHMENT_VALIDATIONS.ALLOWED_RECEIPT_EXTENSIONS.includes(
-                        fileExtension.toLowerCase() as TupleToUnion<typeof CONST.API_ATTACHMENT_VALIDATIONS.ALLOWED_RECEIPT_EXTENSIONS>,
-                    )
-                ) {
-                    setUploadReceiptError(true, 'attachmentPicker.wrongFileType', 'attachmentPicker.notAllowedExtension');
-                    return false;
-                }
-
-                if (!Str.isImage(file.name ?? '') && (file?.size ?? 0) > CONST.API_ATTACHMENT_VALIDATIONS.RECEIPT_MAX_SIZE) {
-                    setUploadReceiptError(true, 'attachmentPicker.attachmentTooLarge', 'attachmentPicker.sizeExceededWithLimit');
-                    return false;
-                }
-
-                if ((file?.size ?? 0) < CONST.API_ATTACHMENT_VALIDATIONS.MIN_SIZE) {
-                    setUploadReceiptError(true, 'attachmentPicker.attachmentTooSmall', 'attachmentPicker.sizeNotMet');
-                    return false;
-                }
-                return true;
-            })
-            .catch(() => {
-                setUploadReceiptError(true, 'attachmentPicker.attachmentError', 'attachmentPicker.errorWhileSelectingCorruptedAttachment');
-                return false;
-            });
-    }
-
     const navigateBack = useCallback(() => {
         Navigation.goBack(backTo);
     }, [backTo]);
@@ -518,7 +487,7 @@ function IOURequestStepScan({
      * Sets the Receipt objects and navigates the user to the next page
      */
     const setReceiptAndNavigate = (originalFile: FileObject, isPdfValidated?: boolean) => {
-        validateReceipt(originalFile).then((isFileValid) => {
+        validateReceipt(originalFile, setUploadReceiptError).then((isFileValid) => {
             if (!isFileValid) {
                 return;
             }
@@ -854,8 +823,8 @@ function IOURequestStepScan({
                         />
                         <ConfirmModal
                             title={attachmentInvalidReasonTitle ? translate(attachmentInvalidReasonTitle) : ''}
-                            onConfirm={hideRecieptModal}
-                            onCancel={hideRecieptModal}
+                            onConfirm={hideReceiptModal}
+                            onCancel={hideReceiptModal}
                             isVisible={isAttachmentInvalid}
                             prompt={getConfirmModalPrompt()}
                             confirmText={translate('common.close')}
diff --git a/src/pages/settings/Profile/ProfilePage.tsx b/src/pages/settings/Profile/ProfilePage.tsx
index 06093b88e306..b305c483a586 100755
--- a/src/pages/settings/Profile/ProfilePage.tsx
+++ b/src/pages/settings/Profile/ProfilePage.tsx
@@ -17,8 +17,8 @@ import Section from '@components/Section';
 import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
 import useLocalize from '@hooks/useLocalize';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useScrollEnabled from '@hooks/useScrollEnabled';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
 import useStyleUtils from '@hooks/useStyleUtils';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
@@ -39,7 +39,7 @@ function ProfilePage() {
     const StyleUtils = useStyleUtils();
     const {translate} = useLocalize();
     const {shouldUseNarrowLayout} = useResponsiveLayout();
-    const {safeAreaPaddingBottomStyle} = useStyledSafeAreaInsets();
+    const {safeAreaPaddingBottomStyle} = useSafeAreaPaddings();
     const scrollEnabled = useScrollEnabled();
     const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST);
     const [privatePersonalDetails] = useOnyx(ONYXKEYS.PRIVATE_PERSONAL_DETAILS);
diff --git a/src/pages/settings/Security/CloseAccountPage.tsx b/src/pages/settings/Security/CloseAccountPage.tsx
index e5fd7dd36ebf..d6eae91b1180 100644
--- a/src/pages/settings/Security/CloseAccountPage.tsx
+++ b/src/pages/settings/Security/CloseAccountPage.tsx
@@ -1,5 +1,5 @@
 import {Str} from 'expensify-common';
-import React, {useEffect, useState} from 'react';
+import React, {useEffect, useLayoutEffect, useState} from 'react';
 import {View} from 'react-native';
 import {useOnyx} from 'react-native-onyx';
 import ConfirmModal from '@components/ConfirmModal';
@@ -13,11 +13,12 @@ import Text from '@components/Text';
 import TextInput from '@components/TextInput';
 import useLocalize from '@hooks/useLocalize';
 import useThemeStyles from '@hooks/useThemeStyles';
+import {parseFSAttributes} from '@libs/Fullstory';
 import Navigation from '@libs/Navigation/Navigation';
-import * as ValidationUtils from '@libs/ValidationUtils';
+import {getFieldRequiredErrors} from '@libs/ValidationUtils';
 import variables from '@styles/variables';
-import * as CloseAccount from '@userActions/CloseAccount';
-import * as User from '@userActions/User';
+import {clearError} from '@userActions/CloseAccount';
+import {closeAccount} from '@userActions/User';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import INPUT_IDS from '@src/types/form/CloseAccountForm';
@@ -35,14 +36,22 @@ function CloseAccountPage() {
     // nothing runs on mount and we pass empty dependencies to prevent this from running on every re-render.
     // TODO: We should refactor this so that the data in instead passed directly as a prop instead of "side loading" the data
     // here, we left this as is during refactor to limit the breaking changes.
-    useEffect(() => () => CloseAccount.clearError(), []);
+    useEffect(() => () => clearError(), []);
+
+    /**
+     * Extracts values from the non-scraped attribute WEB_PROP_ATTR at build time
+     * to ensure necessary properties are available for further processing.
+     * Reevaluates "fs-class" to dynamically apply styles or behavior based on
+     * updated attribute values.
+     */
+    useLayoutEffect(parseFSAttributes, []);
 
     const hideConfirmModal = () => {
         setConfirmModalVisibility(false);
     };
 
     const onConfirm = () => {
-        User.closeAccount(reasonForLeaving);
+        closeAccount(reasonForLeaving);
         hideConfirmModal();
     };
 
@@ -60,7 +69,7 @@ function CloseAccountPage() {
 
     const validate = (values: FormOnyxValues<typeof ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM>): FormInputErrors<typeof ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM> => {
         const userEmailOrPhone = session?.email ? formatPhoneNumber(session.email) : null;
-        const errors = ValidationUtils.getFieldRequiredErrors(values, ['phoneOrEmail']);
+        const errors = getFieldRequiredErrors(values, ['phoneOrEmail']);
 
         if (values.phoneOrEmail && userEmailOrPhone && sanitizePhoneOrEmail(userEmailOrPhone) !== sanitizePhoneOrEmail(values.phoneOrEmail)) {
             errors.phoneOrEmail = translate('closeAccountPage.enterYourDefaultContactMethod');
@@ -88,7 +97,11 @@ function CloseAccountPage() {
                     style={[styles.flexGrow1, styles.mh5]}
                     isSubmitActionDangerous
                 >
-                    <View style={[styles.flexGrow1]}>
+                    <View
+                        fsClass={CONST.FULL_STORY.UNMASK}
+                        testID={CONST.FULL_STORY.UNMASK}
+                        style={[styles.flexGrow1]}
+                    >
                         <Text>{translate('closeAccountPage.reasonForLeavingPrompt')}</Text>
                         <InputWrapper
                             InputComponent={TextInput}
diff --git a/src/pages/settings/Wallet/InternationalDepositAccount/substeps/Success.tsx b/src/pages/settings/Wallet/InternationalDepositAccount/substeps/Success.tsx
index 3a0731010c82..6c14e092fd01 100644
--- a/src/pages/settings/Wallet/InternationalDepositAccount/substeps/Success.tsx
+++ b/src/pages/settings/Wallet/InternationalDepositAccount/substeps/Success.tsx
@@ -1,19 +1,25 @@
 import React from 'react';
 import ConfirmationPage from '@components/ConfirmationPage';
+import ScrollView from '@components/ScrollView';
 import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
 import type {CustomSubStepProps} from '@pages/settings/Wallet/InternationalDepositAccount/types';
 
 function Confirmation({onNext}: CustomSubStepProps) {
     const {translate} = useLocalize();
+    const styles = useThemeStyles();
 
     return (
-        <ConfirmationPage
-            heading={translate('addPersonalBankAccountPage.successTitle')}
-            description={translate('addPersonalBankAccountPage.successMessage')}
-            shouldShowButton
-            buttonText={translate('common.continue')}
-            onButtonPress={onNext}
-        />
+        <ScrollView contentContainerStyle={styles.flexGrow1}>
+            <ConfirmationPage
+                heading={translate('addPersonalBankAccountPage.successTitle')}
+                description={translate('addPersonalBankAccountPage.successMessage')}
+                shouldShowButton
+                buttonText={translate('common.continue')}
+                onButtonPress={onNext}
+                containerStyle={styles.h100}
+            />
+        </ScrollView>
     );
 }
 
diff --git a/src/pages/settings/Wallet/ReportCardLostPage.tsx b/src/pages/settings/Wallet/ReportCardLostPage.tsx
index 52e5024209d4..64cb1c0422a8 100644
--- a/src/pages/settings/Wallet/ReportCardLostPage.tsx
+++ b/src/pages/settings/Wallet/ReportCardLostPage.tsx
@@ -11,18 +11,18 @@ import ValidateCodeActionModal from '@components/ValidateCodeActionModal';
 import useBeforeRemove from '@hooks/useBeforeRemove';
 import useLocalize from '@hooks/useLocalize';
 import usePrevious from '@hooks/usePrevious';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useThemeStyles from '@hooks/useThemeStyles';
+import {setErrors} from '@libs/actions/FormActions';
 import {requestValidateCodeAction} from '@libs/actions/User';
-import * as ErrorUtils from '@libs/ErrorUtils';
+import {getLatestErrorMessageField} from '@libs/ErrorUtils';
 import Navigation from '@libs/Navigation/Navigation';
 import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
 import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
-import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import {getFormattedAddress} from '@libs/PersonalDetailsUtils';
 import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
+import {clearCardListErrors, requestReplacementExpensifyCard} from '@userActions/Card';
 import type {ReplacementReason} from '@userActions/Card';
-import * as CardActions from '@userActions/Card';
-import * as FormActions from '@userActions/FormActions';
 import type {TranslationPaths} from '@src/languages/types';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
@@ -74,14 +74,14 @@ function ReportCardLostPage({
     const [shouldShowReasonError, setShouldShowReasonError] = useState(false);
 
     const physicalCard = cardList?.[cardID];
-    const validateError = ErrorUtils.getLatestErrorMessageField(physicalCard);
+    const validateError = getLatestErrorMessageField(physicalCard);
     const [isValidateCodeActionModalVisible, setIsValidateCodeActionModalVisible] = useState(false);
 
     const prevIsLoading = usePrevious(formData?.isLoading);
 
-    const {paddingBottom} = useStyledSafeAreaInsets();
+    const {paddingBottom} = useSafeAreaPaddings();
 
-    const formattedAddress = PersonalDetailsUtils.getFormattedAddress(privatePersonalDetails ?? {});
+    const formattedAddress = getFormattedAddress(privatePersonalDetails ?? {});
     const primaryLogin = account?.primaryLogin ?? '';
 
     useBeforeRemove(() => setIsValidateCodeActionModalVisible(false));
@@ -99,7 +99,7 @@ function ReportCardLostPage({
             return;
         }
 
-        FormActions.setErrors(ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM, physicalCard?.errors ?? {});
+        setErrors(ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM, physicalCard?.errors ?? {});
     }, [formData?.isLoading, physicalCard?.errors]);
 
     const handleValidateCodeEntered = useCallback(
@@ -107,7 +107,7 @@ function ReportCardLostPage({
             if (!physicalCard) {
                 return;
             }
-            CardActions.requestReplacementExpensifyCard(physicalCard.cardID, reason?.key as ReplacementReason, validateCode);
+            requestReplacementExpensifyCard(physicalCard.cardID, reason?.key as ReplacementReason, validateCode);
         },
         [physicalCard, reason?.key],
     );
@@ -198,7 +198,7 @@ function ReportCardLostPage({
                             sendValidateCode={sendValidateCode}
                             validateError={validateError}
                             clearError={() => {
-                                CardActions.clearCardListErrors(physicalCard.cardID);
+                                clearCardListErrors(physicalCard.cardID);
                             }}
                             onClose={() => setIsValidateCodeActionModalVisible(false)}
                             isVisible={isValidateCodeActionModalVisible}
diff --git a/src/pages/settings/Wallet/TransferBalancePage.tsx b/src/pages/settings/Wallet/TransferBalancePage.tsx
index 3d1a21d9cec1..9c573cacb40e 100644
--- a/src/pages/settings/Wallet/TransferBalancePage.tsx
+++ b/src/pages/settings/Wallet/TransferBalancePage.tsx
@@ -1,7 +1,6 @@
 import React, {useEffect} from 'react';
 import {View} from 'react-native';
-import type {OnyxEntry} from 'react-native-onyx';
-import {withOnyx} from 'react-native-onyx';
+import {useOnyx} from 'react-native-onyx';
 import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
 import ConfirmationPage from '@components/ConfirmationPage';
 import CurrentWalletBalance from '@components/CurrentWalletBalance';
@@ -14,45 +13,39 @@ import ScrollView from '@components/ScrollView';
 import Text from '@components/Text';
 import useLocalize from '@hooks/useLocalize';
 import useNetwork from '@hooks/useNetwork';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useThemeStyles from '@hooks/useThemeStyles';
-import * as CurrencyUtils from '@libs/CurrencyUtils';
-import * as ErrorUtils from '@libs/ErrorUtils';
+import {
+    dismissSuccessfulTransferBalancePage,
+    resetWalletTransferData,
+    saveWalletTransferAccountTypeAndID,
+    saveWalletTransferMethodType,
+    transferWalletBalance,
+} from '@libs/actions/PaymentMethods';
+import {convertToDisplayString} from '@libs/CurrencyUtils';
+import {getLatestErrorMessage} from '@libs/ErrorUtils';
 import Navigation from '@libs/Navigation/Navigation';
-import * as PaymentUtils from '@libs/PaymentUtils';
+import {calculateWalletTransferBalanceFee, formatPaymentMethods, hasExpensifyPaymentMethod} from '@libs/PaymentUtils';
 import variables from '@styles/variables';
-import * as PaymentMethods from '@userActions/PaymentMethods';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
-import type {BankAccountList, FundList, UserWallet, WalletTransfer} from '@src/types/onyx';
 import type PaymentMethod from '@src/types/onyx/PaymentMethod';
 import type {FilterMethodPaymentType} from '@src/types/onyx/WalletTransfer';
 import {isEmptyObject} from '@src/types/utils/EmptyObject';
 
-type TransferBalancePageOnyxProps = {
-    /** User's wallet information */
-    userWallet: OnyxEntry<UserWallet>;
-
-    /** List of bank accounts */
-    bankAccountList: OnyxEntry<BankAccountList>;
-
-    /** List of user's card objects */
-    fundList: OnyxEntry<FundList>;
-
-    /** Wallet balance transfer props */
-    walletTransfer: OnyxEntry<WalletTransfer>;
-};
-
-type TransferBalancePageProps = TransferBalancePageOnyxProps;
-
 const TRANSFER_TIER_NAMES: string[] = [CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM];
 
-function TransferBalancePage({bankAccountList, fundList, userWallet, walletTransfer}: TransferBalancePageProps) {
+function TransferBalancePage() {
     const styles = useThemeStyles();
     const {numberFormat, translate} = useLocalize();
     const {isOffline} = useNetwork();
-    const {paddingBottom} = useStyledSafeAreaInsets();
+    const {paddingBottom} = useSafeAreaPaddings();
+
+    const [userWallet] = useOnyx(ONYXKEYS.USER_WALLET);
+    const [walletTransfer] = useOnyx(ONYXKEYS.WALLET_TRANSFER);
+    const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST);
+    const [fundList] = useOnyx(ONYXKEYS.FUND_LIST);
     const paymentCardList = fundList ?? {};
 
     const paymentTypes = [
@@ -61,7 +54,7 @@ function TransferBalancePage({bankAccountList, fundList, userWallet, walletTrans
             title: translate('transferAmountPage.instant'),
             description: translate('transferAmountPage.instantSummary', {
                 rate: numberFormat(CONST.WALLET.TRANSFER_METHOD_TYPE_FEE.INSTANT.RATE),
-                minAmount: CurrencyUtils.convertToDisplayString(CONST.WALLET.TRANSFER_METHOD_TYPE_FEE.INSTANT.MINIMUM_FEE),
+                minAmount: convertToDisplayString(CONST.WALLET.TRANSFER_METHOD_TYPE_FEE.INSTANT.MINIMUM_FEE),
             }),
             icon: Expensicons.Bolt,
             type: CONST.PAYMENT_METHODS.DEBIT_CARD,
@@ -79,7 +72,7 @@ function TransferBalancePage({bankAccountList, fundList, userWallet, walletTrans
      * Get the selected/default payment method account for wallet transfer
      */
     function getSelectedPaymentMethodAccount(): PaymentMethod | undefined {
-        const paymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList ?? {}, paymentCardList, styles);
+        const paymentMethods = formatPaymentMethods(bankAccountList ?? {}, paymentCardList, styles);
 
         const defaultAccount = paymentMethods.find((method) => method.isDefault);
         const selectedAccount = paymentMethods.find(
@@ -89,15 +82,15 @@ function TransferBalancePage({bankAccountList, fundList, userWallet, walletTrans
     }
 
     function navigateToChooseTransferAccount(filterPaymentMethodType: FilterMethodPaymentType) {
-        PaymentMethods.saveWalletTransferMethodType(filterPaymentMethodType);
+        saveWalletTransferMethodType(filterPaymentMethodType);
 
         // If we only have a single option for the given paymentMethodType do not force the user to make a selection
-        const combinedPaymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList ?? {}, paymentCardList, styles);
+        const combinedPaymentMethods = formatPaymentMethods(bankAccountList ?? {}, paymentCardList, styles);
 
         const filteredMethods = combinedPaymentMethods.filter((paymentMethod) => paymentMethod.accountType === filterPaymentMethodType);
         if (filteredMethods.length === 1) {
             const account = filteredMethods.at(0);
-            PaymentMethods.saveWalletTransferAccountTypeAndID(filterPaymentMethodType ?? '', account?.methodID?.toString() ?? '-1');
+            saveWalletTransferAccountTypeAndID(filterPaymentMethodType, account?.methodID?.toString());
             return;
         }
 
@@ -106,14 +99,14 @@ function TransferBalancePage({bankAccountList, fundList, userWallet, walletTrans
 
     useEffect(() => {
         // Reset to the default account when the page is opened
-        PaymentMethods.resetWalletTransferData();
+        resetWalletTransferData();
 
         const selectedAccount = getSelectedPaymentMethodAccount();
         if (!selectedAccount) {
             return;
         }
 
-        PaymentMethods.saveWalletTransferAccountTypeAndID(selectedAccount?.accountType ?? '', selectedAccount?.methodID?.toString() ?? '-1');
+        saveWalletTransferAccountTypeAndID(selectedAccount?.accountType, selectedAccount?.methodID?.toString());
         // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps -- we only want this effect to run on initial render
     }, []);
 
@@ -122,7 +115,7 @@ function TransferBalancePage({bankAccountList, fundList, userWallet, walletTrans
             <ScreenWrapper testID={TransferBalancePage.displayName}>
                 <HeaderWithBackButton
                     title={translate('common.transferBalance')}
-                    onBackButtonPress={PaymentMethods.dismissSuccessfulTransferBalancePage}
+                    onBackButtonPress={dismissSuccessfulTransferBalancePage}
                 />
                 <ConfirmationPage
                     heading={translate('transferAmountPage.transferSuccess')}
@@ -133,7 +126,7 @@ function TransferBalancePage({bankAccountList, fundList, userWallet, walletTrans
                     }
                     shouldShowButton
                     buttonText={translate('common.done')}
-                    onButtonPress={PaymentMethods.dismissSuccessfulTransferBalancePage}
+                    onButtonPress={dismissSuccessfulTransferBalancePage}
                 />
             </ScreenWrapper>
         );
@@ -143,13 +136,13 @@ function TransferBalancePage({bankAccountList, fundList, userWallet, walletTrans
     const selectedPaymentType =
         selectedAccount && selectedAccount.accountType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT ? CONST.WALLET.TRANSFER_METHOD_TYPE.ACH : CONST.WALLET.TRANSFER_METHOD_TYPE.INSTANT;
 
-    const calculatedFee = PaymentUtils.calculateWalletTransferBalanceFee(userWallet?.currentBalance ?? 0, selectedPaymentType);
+    const calculatedFee = calculateWalletTransferBalanceFee(userWallet?.currentBalance ?? 0, selectedPaymentType);
     const transferAmount = userWallet?.currentBalance ?? 0 - calculatedFee;
     const isTransferable = transferAmount > 0;
     const isButtonDisabled = !isTransferable || !selectedAccount;
-    const errorMessage = ErrorUtils.getLatestErrorMessage(walletTransfer);
+    const errorMessage = getLatestErrorMessage(walletTransfer);
 
-    const shouldShowTransferView = PaymentUtils.hasExpensifyPaymentMethod(paymentCardList, bankAccountList ?? {}) && TRANSFER_TIER_NAMES.includes(userWallet?.tierName ?? '');
+    const shouldShowTransferView = hasExpensifyPaymentMethod(paymentCardList, bankAccountList ?? {}) && TRANSFER_TIER_NAMES.includes(userWallet?.tierName ?? '');
 
     return (
         <ScreenWrapper testID={TransferBalancePage.displayName}>
@@ -206,16 +199,16 @@ function TransferBalancePage({bankAccountList, fundList, userWallet, walletTrans
                     )}
                     <View style={styles.ph5}>
                         <Text style={[styles.mt5, styles.mb3, styles.textLabelSupporting, styles.justifyContentStart]}>{translate('transferAmountPage.fee')}</Text>
-                        <Text style={[styles.justifyContentStart]}>{CurrencyUtils.convertToDisplayString(calculatedFee)}</Text>
+                        <Text style={[styles.justifyContentStart]}>{convertToDisplayString(calculatedFee)}</Text>
                     </View>
                 </ScrollView>
                 <View>
                     <FormAlertWithSubmitButton
                         buttonText={translate('transferAmountPage.transfer', {
-                            amount: isTransferable ? CurrencyUtils.convertToDisplayString(transferAmount) : '',
+                            amount: isTransferable ? convertToDisplayString(transferAmount) : '',
                         })}
                         isLoading={walletTransfer?.loading}
-                        onSubmit={() => selectedAccount && PaymentMethods.transferWalletBalance(selectedAccount)}
+                        onSubmit={() => selectedAccount && transferWalletBalance(selectedAccount)}
                         isDisabled={isButtonDisabled || isOffline}
                         message={errorMessage}
                         isAlertVisible={!isEmptyObject(errorMessage)}
@@ -229,17 +222,4 @@ function TransferBalancePage({bankAccountList, fundList, userWallet, walletTrans
 
 TransferBalancePage.displayName = 'TransferBalancePage';
 
-export default withOnyx<TransferBalancePageProps, TransferBalancePageOnyxProps>({
-    userWallet: {
-        key: ONYXKEYS.USER_WALLET,
-    },
-    walletTransfer: {
-        key: ONYXKEYS.WALLET_TRANSFER,
-    },
-    bankAccountList: {
-        key: ONYXKEYS.BANK_ACCOUNT_LIST,
-    },
-    fundList: {
-        key: ONYXKEYS.FUND_LIST,
-    },
-})(TransferBalancePage);
+export default TransferBalancePage;
diff --git a/src/pages/signin/SMSDeliveryFailurePage.tsx b/src/pages/signin/SMSDeliveryFailurePage.tsx
index ac8d04f556fa..953a0dfc0a8b 100644
--- a/src/pages/signin/SMSDeliveryFailurePage.tsx
+++ b/src/pages/signin/SMSDeliveryFailurePage.tsx
@@ -29,7 +29,22 @@ function SMSDeliveryFailurePage() {
     }, [credentials?.login]);
 
     const SMSDeliveryFailureMessage = account?.smsDeliveryFailureStatus?.message;
+
+    type TimeData = {
+        days?: number;
+        hours?: number;
+        minutes?: number;
+    };
+
+    const timeData = useMemo<TimeData | null>(() => {
+        if (!SMSDeliveryFailureMessage) {
+            return null;
+        }
+        return JSON.parse(SMSDeliveryFailureMessage) as TimeData;
+    }, [SMSDeliveryFailureMessage]);
+
     const hasSMSDeliveryFailure = account?.smsDeliveryFailureStatus?.hasSMSDeliveryFailure;
+
     const isReset = account?.smsDeliveryFailureStatus?.isReset;
 
     const errorText = useMemo(() => (account ? getLatestErrorMessage(account) : ''), [account]);
@@ -48,7 +63,7 @@ function SMSDeliveryFailurePage() {
                 <View style={[styles.mv3, styles.flexRow]}>
                     <View style={[styles.flex1]}>
                         <Text>
-                            {translate('smsDeliveryFailurePage.validationFailed')} {SMSDeliveryFailureMessage}
+                            {translate('smsDeliveryFailurePage.validationFailed')} {timeData && translate('smsDeliveryFailurePage.pleaseWaitBeforeTryingAgain', {timeData})}
                         </Text>
                     </View>
                 </View>
diff --git a/src/pages/signin/SignInPage.tsx b/src/pages/signin/SignInPage.tsx
index 221ca93701be..44fd8776b43f 100644
--- a/src/pages/signin/SignInPage.tsx
+++ b/src/pages/signin/SignInPage.tsx
@@ -302,7 +302,7 @@ function SignInPage({shouldEnableMaxHeight = true}: SignInPageInnerProps, ref: F
         <ScreenWrapper
             shouldShowOfflineIndicator={false}
             shouldEnableMaxHeight={shouldEnableMaxHeight}
-            style={[styles.signInPage, StyleUtils.getSafeAreaPadding({...safeAreaInsets, bottom: 0, top: isInNarrowPaneModal ? 0 : safeAreaInsets.top}, 1)]}
+            style={[styles.signInPage, StyleUtils.getPlatformSafeAreaPadding({...safeAreaInsets, bottom: 0, top: isInNarrowPaneModal ? 0 : safeAreaInsets.top}, 1)]}
             testID={SignInPageThemeWrapper.displayName}
         >
             <SignInPageLayout
diff --git a/src/pages/tasks/NewTaskPage.tsx b/src/pages/tasks/NewTaskPage.tsx
index 33fef0a065ca..afe396891894 100644
--- a/src/pages/tasks/NewTaskPage.tsx
+++ b/src/pages/tasks/NewTaskPage.tsx
@@ -11,7 +11,7 @@ import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
 import ScreenWrapper from '@components/ScreenWrapper';
 import ScrollView from '@components/ScrollView';
 import useLocalize from '@hooks/useLocalize';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useThemeStyles from '@hooks/useThemeStyles';
 import blurActiveElement from '@libs/Accessibility/blurActiveElement';
 import {createTaskAndNavigate, dismissModalAndClearOutTaskInfo, getAssignee, getShareDestination, setShareDestinationValue} from '@libs/actions/Task';
@@ -48,7 +48,7 @@ function NewTaskPage({route}: NewTaskPageProps) {
     const hasDestinationError = task?.skipConfirmation && !task?.parentReportID;
     const isAllowedToCreateTask = useMemo(() => isEmptyObject(parentReport) || isAllowedToComment(parentReport), [parentReport]);
 
-    const {paddingBottom} = useStyledSafeAreaInsets();
+    const {paddingBottom} = useSafeAreaPaddings();
 
     const backTo = route.params?.backTo;
     const confirmButtonRef = useRef<View>(null);
diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
index 6cf2a73d3ece..e156aac0c465 100644
--- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
+++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
@@ -11,7 +11,7 @@ import Text from '@components/Text';
 import useLocalize from '@hooks/useLocalize';
 import useNetwork from '@hooks/useNetwork';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
-import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets';
+import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
 import useStyleUtils from '@hooks/useStyleUtils';
 import useThemeStyles from '@hooks/useThemeStyles';
 import {getCompanyFeeds} from '@libs/CardUtils';
@@ -75,7 +75,7 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
     const styles = useThemeStyles();
     const stylesutils = useStyleUtils();
     const {shouldUseNarrowLayout} = useResponsiveLayout();
-    const {safeAreaPaddingBottomStyle} = useStyledSafeAreaInsets();
+    const {safeAreaPaddingBottomStyle} = useSafeAreaPaddings();
     const {translate} = useLocalize();
     const hasAccountingConnection = !isEmptyObject(policy?.connections);
     const isAccountingEnabled = !!policy?.areConnectionsEnabled || !isEmptyObject(policy?.connections);
diff --git a/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAccountingMethodPage.tsx b/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAccountingMethodPage.tsx
index a5c1872158e9..f08f79895cbb 100644
--- a/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAccountingMethodPage.tsx
+++ b/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAccountingMethodPage.tsx
@@ -9,7 +9,7 @@ import type {SelectorType} from '@components/SelectionScreen';
 import Text from '@components/Text';
 import useLocalize from '@hooks/useLocalize';
 import useThemeStyles from '@hooks/useThemeStyles';
-import * as Connections from '@libs/actions/connections/NetSuiteCommands';
+import {updateNetSuiteAccountingMethod} from '@libs/actions/connections/NetSuiteCommands';
 import {settingsPendingAction} from '@libs/PolicyUtils';
 import Navigation from '@navigation/Navigation';
 import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
@@ -24,15 +24,15 @@ type MenuListItem = ListItem & {
 
 function NetSuiteAccountingMethodPage({policy}: WithPolicyConnectionsProps) {
     const {translate} = useLocalize();
-    const policyID = policy?.id ?? '-1';
+    const policyID = policy?.id;
     const styles = useThemeStyles();
     const config = policy?.connections?.netsuite?.options?.config;
     const autoSyncConfig = policy?.connections?.netsuite?.config;
     const accountingMethod = config?.accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH;
     const data: MenuListItem[] = Object.values(COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD).map((accountingMethodType) => ({
         value: accountingMethodType,
-        text: translate(`workspace.netsuite.advancedConfig.accountingMethods.values.${accountingMethodType}` as TranslationPaths),
-        alternateText: translate(`workspace.netsuite.advancedConfig.accountingMethods.alternateText.${accountingMethodType}` as TranslationPaths),
+        text: translate(`workspace.accountingMethods.values.${accountingMethodType}` as TranslationPaths),
+        alternateText: translate(`workspace.accountingMethods.alternateText.${accountingMethodType}` as TranslationPaths),
         keyForList: accountingMethodType,
         isSelected: accountingMethod === accountingMethodType,
     }));
@@ -43,7 +43,7 @@ function NetSuiteAccountingMethodPage({policy}: WithPolicyConnectionsProps) {
     const headerContent = useMemo(
         () => (
             <View>
-                <Text style={[styles.ph5, styles.pb5]}>{translate('workspace.netsuite.advancedConfig.accountingMethods.description')}</Text>
+                <Text style={[styles.ph5, styles.pb5]}>{translate('workspace.accountingMethods.description')}</Text>
             </View>
         ),
         [translate, styles.pb5, styles.ph5],
@@ -52,7 +52,7 @@ function NetSuiteAccountingMethodPage({policy}: WithPolicyConnectionsProps) {
     const selectExpenseReportApprovalLevel = useCallback(
         (row: MenuListItem) => {
             if (row.value !== config?.accountingMethod) {
-                Connections.updateNetSuiteAccountingMethod(policyID, row.value, config?.accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH);
+                updateNetSuiteAccountingMethod(policyID, row.value, config?.accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH);
             }
             Navigation.goBack(ROUTES.POLICY_ACCOUNTING_NETSUITE_AUTO_SYNC.getRoute(policyID));
         },
@@ -62,7 +62,7 @@ function NetSuiteAccountingMethodPage({policy}: WithPolicyConnectionsProps) {
     return (
         <SelectionScreen
             displayName={NetSuiteAccountingMethodPage.displayName}
-            title="workspace.netsuite.advancedConfig.accountingMethods.label"
+            title="workspace.accountingMethods.label"
             headerContent={headerContent}
             sections={[{data}]}
             listItem={RadioListItem}
diff --git a/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAdvancedPage.tsx b/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAdvancedPage.tsx
index 5d7df8b7a876..75ea09e65e70 100644
--- a/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAdvancedPage.tsx
+++ b/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAdvancedPage.tsx
@@ -100,9 +100,7 @@ function NetSuiteAdvancedPage({policy}: WithPolicyConnectionsProps) {
                 if (!autoSyncConfig?.autoSync?.enabled) {
                     return undefined;
                 }
-                return translate(
-                    `workspace.netsuite.advancedConfig.accountingMethods.alternateText.${accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH}` as TranslationPaths,
-                );
+                return translate(`workspace.accountingMethods.alternateText.${accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH}` as TranslationPaths);
             })(),
             subscribedSettings: [CONST.NETSUITE_CONFIG.AUTO_SYNC, CONST.NETSUITE_CONFIG.ACCOUNTING_METHOD],
         },
diff --git a/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAutoSyncPage.tsx b/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAutoSyncPage.tsx
index 2836b3d60075..70a364a3d56a 100644
--- a/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAutoSyncPage.tsx
+++ b/src/pages/workspace/accounting/netsuite/advanced/NetSuiteAutoSyncPage.tsx
@@ -8,15 +8,15 @@ import ScreenWrapper from '@components/ScreenWrapper';
 import useAccordionAnimation from '@hooks/useAccordionAnimation';
 import useLocalize from '@hooks/useLocalize';
 import useThemeStyles from '@hooks/useThemeStyles';
-import * as Connections from '@libs/actions/connections/NetSuiteCommands';
-import * as ErrorUtils from '@libs/ErrorUtils';
+import {updateNetSuiteAutoSync} from '@libs/actions/connections/NetSuiteCommands';
+import {getLatestErrorField} from '@libs/ErrorUtils';
 import Navigation from '@libs/Navigation/Navigation';
 import {settingsPendingAction} from '@libs/PolicyUtils';
 import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
 import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
 import withPolicyConnections from '@pages/workspace/withPolicyConnections';
 import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow';
-import * as Policy from '@userActions/Policy/Policy';
+import {clearNetSuiteAutoSyncErrorField} from '@userActions/Policy/Policy';
 import CONST from '@src/CONST';
 import type {TranslationPaths} from '@src/languages/types';
 import ROUTES from '@src/ROUTES';
@@ -26,7 +26,7 @@ function NetSuiteAutoSyncPage({policy, route}: WithPolicyConnectionsProps) {
     const {translate} = useLocalize();
     const config = policy?.connections?.netsuite?.options?.config;
     const autoSyncConfig = policy?.connections?.netsuite?.config;
-    const policyID = route.params.policyID ?? '-1';
+    const policyID = route.params.policyID;
     const accountingMethod = policy?.connections?.netsuite?.options?.config?.accountingMethod;
     const pendingAction =
         settingsPendingAction([CONST.NETSUITE_CONFIG.AUTO_SYNC], autoSyncConfig?.pendingFields) ?? settingsPendingAction([CONST.NETSUITE_CONFIG.ACCOUNTING_METHOD], config?.pendingFields);
@@ -57,10 +57,10 @@ function NetSuiteAutoSyncPage({policy, route}: WithPolicyConnectionsProps) {
                     wrapperStyle={[styles.pv2, styles.mh5]}
                     switchAccessibilityLabel={translate('workspace.netsuite.advancedConfig.autoSyncDescription')}
                     shouldPlaceSubtitleBelowSwitch
-                    onCloseError={() => Policy.clearNetSuiteAutoSyncErrorField(policyID)}
-                    onToggle={(isEnabled) => Connections.updateNetSuiteAutoSync(policyID, isEnabled)}
+                    onCloseError={() => clearNetSuiteAutoSyncErrorField(policyID)}
+                    onToggle={(isEnabled) => updateNetSuiteAutoSync(policyID, isEnabled)}
                     pendingAction={pendingAction}
-                    errors={ErrorUtils.getLatestErrorField(autoSyncConfig, CONST.NETSUITE_CONFIG.AUTO_SYNC)}
+                    errors={getLatestErrorField(autoSyncConfig, CONST.NETSUITE_CONFIG.AUTO_SYNC)}
                 />
 
                 <Accordion
@@ -71,10 +71,10 @@ function NetSuiteAutoSyncPage({policy, route}: WithPolicyConnectionsProps) {
                         <MenuItemWithTopDescription
                             title={
                                 accountingMethod === COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL
-                                    ? translate(`workspace.netsuite.advancedConfig.accountingMethods.values.${COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL}` as TranslationPaths)
-                                    : translate(`workspace.netsuite.advancedConfig.accountingMethods.values.${COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH}` as TranslationPaths)
+                                    ? translate(`workspace.accountingMethods.values.${COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL}` as TranslationPaths)
+                                    : translate(`workspace.accountingMethods.values.${COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH}` as TranslationPaths)
                             }
-                            description={translate('workspace.netsuite.advancedConfig.accountingMethods.label')}
+                            description={translate('workspace.accountingMethods.label')}
                             shouldShowRightIcon
                             onPress={() => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_ACCOUNTING_METHOD.getRoute(policyID))}
                         />
diff --git a/src/pages/workspace/accounting/qbo/advanced/QuickbooksAccountingMethodPage.tsx b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAccountingMethodPage.tsx
new file mode 100644
index 000000000000..4023ae1b0192
--- /dev/null
+++ b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAccountingMethodPage.tsx
@@ -0,0 +1,82 @@
+import {CONST as COMMON_CONST} from 'expensify-common';
+import React, {useCallback, useMemo} from 'react';
+import {View} from 'react-native';
+import type {ValueOf} from 'type-fest';
+import RadioListItem from '@components/SelectionList/RadioListItem';
+import type {ListItem} from '@components/SelectionList/types';
+import SelectionScreen from '@components/SelectionScreen';
+import type {SelectorType} from '@components/SelectionScreen';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {updateQuickbooksOnlineAccountingMethod} from '@libs/actions/connections/QuickbooksOnline';
+import {settingsPendingAction} from '@libs/PolicyUtils';
+import Navigation from '@navigation/Navigation';
+import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
+import withPolicyConnections from '@pages/workspace/withPolicyConnections';
+import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
+import ROUTES from '@src/ROUTES';
+
+type MenuListItem = ListItem & {
+    value: ValueOf<typeof COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD>;
+};
+
+function QuickbooksAccountingMethodPage({policy}: WithPolicyConnectionsProps) {
+    const {translate} = useLocalize();
+    const policyID = policy?.id;
+    const styles = useThemeStyles();
+    const config = policy?.connections?.quickbooksOnline?.config;
+    const accountingMethod = config?.accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH;
+    const data: MenuListItem[] = Object.values(COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD).map((accountingMethodType) => ({
+        value: accountingMethodType,
+        text: translate(`workspace.accountingMethods.values.${accountingMethodType}` as TranslationPaths),
+        alternateText: translate(`workspace.accountingMethods.alternateText.${accountingMethodType}` as TranslationPaths),
+        keyForList: accountingMethodType,
+        isSelected: accountingMethod === accountingMethodType,
+    }));
+
+    const pendingAction =
+        settingsPendingAction([CONST.QUICKBOOKS_CONFIG.AUTO_SYNC], config?.pendingFields) ?? settingsPendingAction([CONST.QUICKBOOKS_CONFIG.ACCOUNTING_METHOD], config?.pendingFields);
+
+    const headerContent = useMemo(
+        () => (
+            <View>
+                <Text style={[styles.ph5, styles.pb5]}>{translate('workspace.accountingMethods.description')}</Text>
+            </View>
+        ),
+        [translate, styles.pb5, styles.ph5],
+    );
+
+    const selectExpenseReportApprovalLevel = useCallback(
+        (row: MenuListItem) => {
+            if (row.value !== config?.accountingMethod) {
+                updateQuickbooksOnlineAccountingMethod(policyID, row.value, config?.accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH);
+            }
+            Navigation.goBack(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_AUTO_SYNC.getRoute(policyID));
+        },
+        [config?.accountingMethod, policyID],
+    );
+
+    return (
+        <SelectionScreen
+            displayName={QuickbooksAccountingMethodPage.displayName}
+            title="workspace.accountingMethods.label"
+            headerContent={headerContent}
+            sections={[{data}]}
+            listItem={RadioListItem}
+            onSelectRow={(selection: SelectorType) => selectExpenseReportApprovalLevel(selection as MenuListItem)}
+            initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList}
+            policyID={policyID}
+            accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN]}
+            featureName={CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED}
+            onBackButtonPress={() => Navigation.goBack(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_AUTO_SYNC.getRoute(policyID))}
+            connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO}
+            pendingAction={pendingAction}
+        />
+    );
+}
+
+QuickbooksAccountingMethodPage.displayName = 'QuickbooksAccountingMethodPage';
+
+export default withPolicyConnections(QuickbooksAccountingMethodPage);
diff --git a/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx
index 14be50461112..d2ecb144f76f 100644
--- a/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx
+++ b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx
@@ -1,3 +1,4 @@
+import {CONST as COMMON_CONST} from 'expensify-common';
 import React, {useMemo} from 'react';
 import {View} from 'react-native';
 import Accordion from '@components/Accordion';
@@ -8,16 +9,16 @@ import useAccordionAnimation from '@hooks/useAccordionAnimation';
 import useLocalize from '@hooks/useLocalize';
 import useThemeStyles from '@hooks/useThemeStyles';
 import useWaitForNavigation from '@hooks/useWaitForNavigation';
-import * as QuickbooksOnline from '@libs/actions/connections/QuickbooksOnline';
-import * as ErrorUtils from '@libs/ErrorUtils';
+import {updateQuickbooksOnlineAutoCreateVendor, updateQuickbooksOnlineCollectionAccountID, updateQuickbooksOnlineSyncPeople} from '@libs/actions/connections/QuickbooksOnline';
+import {getLatestErrorField} from '@libs/ErrorUtils';
 import Navigation from '@libs/Navigation/Navigation';
-import * as PolicyUtils from '@libs/PolicyUtils';
-import {settingsPendingAction} from '@libs/PolicyUtils';
+import {areSettingsInErrorFields, settingsPendingAction} from '@libs/PolicyUtils';
 import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
 import withPolicyConnections from '@pages/workspace/withPolicyConnections';
 import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow';
 import {clearQBOErrorField} from '@userActions/Policy/Policy';
 import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
 import ROUTES from '@src/ROUTES';
 
 const reimbursementOrCollectionAccountIDs = [CONST.QUICKBOOKS_CONFIG.REIMBURSEMENT_ACCOUNT_ID, CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID];
@@ -28,8 +29,9 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) {
     const waitForNavigate = useWaitForNavigation();
     const {translate} = useLocalize();
 
-    const policyID = policy?.id ?? '-1';
+    const policyID = policy?.id;
     const qboConfig = policy?.connections?.quickbooksOnline?.config;
+    const accountingMethod = policy?.connections?.quickbooksOnline?.config?.accountingMethod;
     const {bankAccounts, creditCards, otherCurrentAssetAccounts, vendors} = policy?.connections?.quickbooksOnline?.data ?? {};
     const nonReimbursableBillDefaultVendorObject = vendors?.find((vendor) => vendor.id === qboConfig?.nonReimbursableBillDefaultVendor);
 
@@ -57,16 +59,16 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) {
             description: translate('workspace.qbo.advancedConfig.qboBillPaymentAccount'),
             onPress: waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR.getRoute(policyID))),
             subscribedSettings: reimbursementOrCollectionAccountIDs,
-            brickRoadIndicator: PolicyUtils.areSettingsInErrorFields(reimbursementOrCollectionAccountIDs, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
-            pendingAction: PolicyUtils.settingsPendingAction(reimbursementOrCollectionAccountIDs, qboConfig?.pendingFields),
+            brickRoadIndicator: areSettingsInErrorFields(reimbursementOrCollectionAccountIDs, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
+            pendingAction: settingsPendingAction(reimbursementOrCollectionAccountIDs, qboConfig?.pendingFields),
         },
         {
             title: selectedInvoiceCollectionAccountName,
             description: translate('workspace.qbo.advancedConfig.qboInvoiceCollectionAccount'),
             onPress: waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR.getRoute(policyID))),
             subscribedSettings: collectionAccountIDs,
-            brickRoadIndicator: PolicyUtils.areSettingsInErrorFields(collectionAccountIDs, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
-            pendingAction: PolicyUtils.settingsPendingAction(collectionAccountIDs, qboConfig?.pendingFields),
+            brickRoadIndicator: areSettingsInErrorFields(collectionAccountIDs, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
+            pendingAction: settingsPendingAction(collectionAccountIDs, qboConfig?.pendingFields),
         },
     ];
 
@@ -88,24 +90,14 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) {
     );
 
     const qboToggleSettingItems = [
-        {
-            title: translate('workspace.accounting.autoSync'),
-            subtitle: translate('workspace.qbo.advancedConfig.autoSyncDescription'),
-            switchAccessibilityLabel: translate('workspace.qbo.advancedConfig.autoSyncDescription'),
-            isActive: !!qboConfig?.autoSync?.enabled,
-            onToggle: () => QuickbooksOnline.updateQuickbooksOnlineAutoSync(policyID, !qboConfig?.autoSync?.enabled),
-            subscribedSetting: CONST.QUICKBOOKS_CONFIG.AUTO_SYNC,
-            errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.AUTO_SYNC),
-            pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.AUTO_SYNC], qboConfig?.pendingFields),
-        },
         {
             title: translate('workspace.qbo.advancedConfig.inviteEmployees'),
             subtitle: translate('workspace.qbo.advancedConfig.inviteEmployeesDescription'),
             switchAccessibilityLabel: translate('workspace.qbo.advancedConfig.inviteEmployeesDescription'),
             isActive: !!qboConfig?.syncPeople,
-            onToggle: () => QuickbooksOnline.updateQuickbooksOnlineSyncPeople(policyID, !qboConfig?.syncPeople),
+            onToggle: () => updateQuickbooksOnlineSyncPeople(policyID, !qboConfig?.syncPeople),
             subscribedSetting: CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE,
-            errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE),
+            errors: getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE),
             pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE], qboConfig?.pendingFields),
         },
         {
@@ -119,7 +111,7 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) {
                     : CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE;
                 const nonReimbursableVendorCurrentValue = nonReimbursableBillDefaultVendorObject?.id ?? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE;
 
-                QuickbooksOnline.updateQuickbooksOnlineAutoCreateVendor(
+                updateQuickbooksOnlineAutoCreateVendor(
                     policyID,
                     {
                         [autoCreateVendorConst]: isOn,
@@ -132,7 +124,7 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) {
                 );
             },
             subscribedSetting: CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR,
-            errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR),
+            errors: getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR),
             pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR], qboConfig?.pendingFields),
         },
         {
@@ -141,13 +133,13 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) {
             switchAccessibilityLabel: translate('workspace.qbo.advancedConfig.reimbursedReportsDescription'),
             isActive: isSyncReimbursedSwitchOn,
             onToggle: () =>
-                QuickbooksOnline.updateQuickbooksOnlineCollectionAccountID(
+                updateQuickbooksOnlineCollectionAccountID(
                     policyID,
                     isSyncReimbursedSwitchOn ? '' : [...qboAccountOptions, ...invoiceAccountCollectionOptions].at(0)?.id,
                     qboConfig?.collectionAccountID,
                 ),
             subscribedSetting: CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID,
-            errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID),
+            errors: getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID),
             pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID], qboConfig?.pendingFields),
         },
     ];
@@ -162,6 +154,26 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) {
             contentContainerStyle={[styles.pb2, styles.ph5]}
             connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO}
         >
+            <OfflineWithFeedback pendingAction={settingsPendingAction([CONST.QUICKBOOKS_CONFIG.AUTO_SYNC, CONST.QUICKBOOKS_CONFIG.ACCOUNTING_METHOD], qboConfig?.pendingFields)}>
+                <MenuItemWithTopDescription
+                    title={qboConfig?.autoSync?.enabled ? translate('common.enabled') : translate('common.disabled')}
+                    description={translate('workspace.accounting.autoSync')}
+                    shouldShowRightIcon
+                    wrapperStyle={[styles.sectionMenuItemTopDescription]}
+                    onPress={() => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_AUTO_SYNC.getRoute(policyID))}
+                    brickRoadIndicator={
+                        areSettingsInErrorFields([CONST.QUICKBOOKS_CONFIG.AUTO_SYNC, CONST.QUICKBOOKS_CONFIG.ACCOUNTING_METHOD], qboConfig?.errorFields)
+                            ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR
+                            : undefined
+                    }
+                    hintText={(() => {
+                        if (!qboConfig?.autoSync?.enabled) {
+                            return undefined;
+                        }
+                        return translate(`workspace.accountingMethods.alternateText.${accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH}` as TranslationPaths);
+                    })()}
+                />
+            </OfflineWithFeedback>
             {qboToggleSettingItems.map((item) => (
                 <ToggleSettingOptionRow
                     key={item.title}
diff --git a/src/pages/workspace/accounting/qbo/advanced/QuickbooksAutoSyncPage.tsx b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAutoSyncPage.tsx
new file mode 100644
index 000000000000..f4a5814342dc
--- /dev/null
+++ b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAutoSyncPage.tsx
@@ -0,0 +1,79 @@
+import {CONST as COMMON_CONST} from 'expensify-common';
+import React from 'react';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {updateQuickbooksOnlineAutoSync} from '@libs/actions/connections/QuickbooksOnline';
+import {getLatestErrorField} from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import {settingsPendingAction} from '@libs/PolicyUtils';
+import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
+import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
+import withPolicyConnections from '@pages/workspace/withPolicyConnections';
+import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow';
+import {clearQuickbooksOnlineAutoSyncErrorField} from '@userActions/Policy/Policy';
+import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
+import ROUTES from '@src/ROUTES';
+
+function QuickbooksAutoSyncPage({policy, route}: WithPolicyConnectionsProps) {
+    const styles = useThemeStyles();
+    const {translate} = useLocalize();
+    const config = policy?.connections?.quickbooksOnline?.config;
+    const policyID = route.params.policyID;
+    const accountingMethod = config?.accountingMethod ?? COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH;
+    const pendingAction =
+        settingsPendingAction([CONST.QUICKBOOKS_CONFIG.AUTO_SYNC], config?.pendingFields) ?? settingsPendingAction([CONST.QUICKBOOKS_CONFIG.ACCOUNTING_METHOD], config?.pendingFields);
+
+    return (
+        <AccessOrNotFoundWrapper
+            policyID={policyID}
+            accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN, CONST.POLICY.ACCESS_VARIANTS.PAID]}
+            featureName={CONST.POLICY.MORE_FEATURES.ARE_CATEGORIES_ENABLED}
+        >
+            <ScreenWrapper
+                includeSafeAreaPaddingBottom={false}
+                style={[styles.defaultModalContainer]}
+                testID={QuickbooksAutoSyncPage.displayName}
+            >
+                <HeaderWithBackButton
+                    title={translate('common.settings')}
+                    onBackButtonPress={() => Navigation.goBack(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ADVANCED.getRoute(policyID))}
+                />
+                <ToggleSettingOptionRow
+                    title={translate('workspace.accounting.autoSync')}
+                    subtitle={translate('workspace.qbo.autoSyncDescription')}
+                    isActive={!!config?.autoSync?.enabled}
+                    wrapperStyle={[styles.pv2, styles.mh5]}
+                    switchAccessibilityLabel={translate('workspace.qbo.advancedConfig.autoSyncDescription')}
+                    shouldPlaceSubtitleBelowSwitch
+                    onCloseError={() => clearQuickbooksOnlineAutoSyncErrorField(policyID)}
+                    onToggle={(isEnabled) => updateQuickbooksOnlineAutoSync(policyID, isEnabled)}
+                    pendingAction={pendingAction}
+                    errors={getLatestErrorField(config, CONST.QUICKBOOKS_CONFIG.AUTO_SYNC)}
+                />
+                {!!config?.autoSync?.enabled && (
+                    <OfflineWithFeedback pendingAction={pendingAction}>
+                        <MenuItemWithTopDescription
+                            title={
+                                accountingMethod === COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL
+                                    ? translate(`workspace.accountingMethods.values.${COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.ACCRUAL}` as TranslationPaths)
+                                    : translate(`workspace.accountingMethods.values.${COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD.CASH}` as TranslationPaths)
+                            }
+                            description={translate('workspace.accountingMethods.label')}
+                            shouldShowRightIcon
+                            onPress={() => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNTING_METHOD.getRoute(policyID))}
+                        />
+                    </OfflineWithFeedback>
+                )}
+            </ScreenWrapper>
+        </AccessOrNotFoundWrapper>
+    );
+}
+
+QuickbooksAutoSyncPage.displayName = 'QuickbooksAutoSyncPage';
+
+export default withPolicyConnections(QuickbooksAutoSyncPage);
diff --git a/src/stories/SelectionList.stories.tsx b/src/stories/SelectionList.stories.tsx
index b3dc4c5ae2d2..e993d23dc0ba 100644
--- a/src/stories/SelectionList.stories.tsx
+++ b/src/stories/SelectionList.stories.tsx
@@ -3,7 +3,7 @@ import React, {useMemo, useState} from 'react';
 import Badge from '@components/Badge';
 import SelectionList from '@components/SelectionList';
 import RadioListItem from '@components/SelectionList/RadioListItem';
-import type {BaseSelectionListProps, ListItem} from '@components/SelectionList/types';
+import type {ListItem, SelectionListProps} from '@components/SelectionList/types';
 import withNavigationFallback from '@components/withNavigationFallback';
 // eslint-disable-next-line no-restricted-imports
 import {defaultStyles} from '@styles/index';
@@ -71,7 +71,7 @@ const SECTIONS = [
     },
 ];
 
-function Default(props: BaseSelectionListProps<ListItem>) {
+function Default(props: SelectionListProps<ListItem>) {
     const [selectedIndex, setSelectedIndex] = useState(1);
 
     const sections = props.sections.map((section) => {
@@ -110,7 +110,7 @@ Default.args = {
     initiallyFocusedOptionKey: 'option-2',
 };
 
-function WithTextInput(props: BaseSelectionListProps<ListItem>) {
+function WithTextInput(props: SelectionListProps<ListItem>) {
     const [searchText, setSearchText] = useState('');
     const [selectedIndex, setSelectedIndex] = useState(1);
 
@@ -162,7 +162,7 @@ WithTextInput.args = {
     onChangeText: () => {},
 };
 
-function WithHeaderMessage(props: BaseSelectionListProps<ListItem>) {
+function WithHeaderMessage(props: SelectionListProps<ListItem>) {
     return (
         <WithTextInput
             // eslint-disable-next-line react/jsx-props-no-spreading
@@ -177,7 +177,7 @@ WithHeaderMessage.args = {
     sections: [],
 };
 
-function WithAlternateText(props: BaseSelectionListProps<ListItem>) {
+function WithAlternateText(props: SelectionListProps<ListItem>) {
     const [selectedIndex, setSelectedIndex] = useState(1);
 
     const sections = props.sections.map((section) => {
@@ -218,7 +218,7 @@ WithAlternateText.args = {
     ...Default.args,
 };
 
-function MultipleSelection(props: BaseSelectionListProps<ListItem>) {
+function MultipleSelection(props: SelectionListProps<ListItem>) {
     const [selectedIds, setSelectedIds] = useState(['option-1', 'option-2']);
 
     const memo = useMemo(() => {
@@ -288,7 +288,7 @@ MultipleSelection.args = {
     onSelectAll: () => {},
 };
 
-function WithSectionHeader(props: BaseSelectionListProps<ListItem>) {
+function WithSectionHeader(props: SelectionListProps<ListItem>) {
     const [selectedIds, setSelectedIds] = useState(['option-1', 'option-2']);
 
     const memo = useMemo(() => {
@@ -356,7 +356,7 @@ WithSectionHeader.args = {
     ...MultipleSelection.args,
 };
 
-function WithConfirmButton(props: BaseSelectionListProps<ListItem>) {
+function WithConfirmButton(props: SelectionListProps<ListItem>) {
     const [selectedIds, setSelectedIds] = useState(['option-1', 'option-2']);
 
     const memo = useMemo(() => {
diff --git a/src/stories/TransactionItemRow.stories.tsx b/src/stories/TransactionItemRow.stories.tsx
new file mode 100644
index 000000000000..7afe1e0ae3d7
--- /dev/null
+++ b/src/stories/TransactionItemRow.stories.tsx
@@ -0,0 +1,76 @@
+import type {Meta, StoryFn} from '@storybook/react';
+import React from 'react';
+import ThemeProvider from '@components/ThemeProvider';
+import ThemeStylesProvider from '@components/ThemeStylesProvider';
+import TransactionItemRow from '@components/TransactionItemRow';
+import CONST from '@src/CONST';
+import type Transaction from '@src/types/onyx/Transaction';
+import transaction from './objects/Transaction';
+
+type TransactionItemRowStory = StoryFn<typeof TransactionItemRow>;
+
+type TransactionItemRowProps = {
+    transactionItem: Transaction;
+    shouldUseNarrowLayout: boolean;
+    isSelected: boolean;
+    shouldShowTooltip: boolean;
+};
+
+const story: Meta<typeof TransactionItemRow> = {
+    title: 'Components/TransactionItemRow',
+    component: TransactionItemRow,
+    args: {
+        transactionItem: transaction,
+        shouldUseNarrowLayout: false,
+        isSelected: false,
+        shouldShowTooltip: true,
+    },
+    argTypes: {
+        transactionItem: {
+            control: 'object',
+        },
+        shouldUseNarrowLayout: {
+            control: 'boolean',
+        },
+        isSelected: {
+            control: 'boolean',
+        },
+        shouldShowTooltip: {
+            control: 'boolean',
+        },
+    },
+    parameters: {
+        useLightTheme: true,
+    },
+};
+
+function Template({transactionItem, shouldUseNarrowLayout, isSelected, shouldShowTooltip}: TransactionItemRowProps, {parameters}: {parameters: {useLightTheme?: boolean}}) {
+    const theme = parameters.useLightTheme ? CONST.THEME.LIGHT : CONST.THEME.DARK;
+
+    return (
+        <ThemeProvider theme={theme}>
+            <ThemeStylesProvider>
+                <TransactionItemRow
+                    transactionItem={transactionItem}
+                    shouldUseNarrowLayout={shouldUseNarrowLayout}
+                    isSelected={isSelected}
+                    shouldShowTooltip={shouldShowTooltip}
+                />
+            </ThemeStylesProvider>
+        </ThemeProvider>
+    );
+}
+
+const LightTheme: TransactionItemRowStory = Template.bind({});
+const DarkTheme: TransactionItemRowStory = Template.bind({});
+
+LightTheme.parameters = {
+    useLightTheme: true,
+};
+
+DarkTheme.parameters = {
+    useLightTheme: false,
+};
+
+export default story;
+export {LightTheme, DarkTheme};
diff --git a/src/stories/objects/Transaction.ts b/src/stories/objects/Transaction.ts
new file mode 100644
index 000000000000..177b97eed1bc
--- /dev/null
+++ b/src/stories/objects/Transaction.ts
@@ -0,0 +1,39 @@
+import type Transaction from '@src/types/onyx/Transaction';
+
+const transaction: Transaction & {mcc: string; modifiedMCC: string} = {
+    amount: -769900,
+    bank: '',
+    billable: false,
+    cardID: 0,
+    cardName: 'Cash Expense',
+    cardNumber: '',
+    category: 'CARS',
+    comment: {
+        comment: '',
+    },
+    created: '2025-02-18',
+    currency: 'PLN',
+    filename: '',
+    hasEReceipt: false,
+    inserted: '2025-02-18 14:23:29',
+    managedCard: false,
+    mcc: '',
+    merchant: "Mario's",
+    modifiedAmount: 0,
+    modifiedCreated: '',
+    modifiedCurrency: '',
+    modifiedMCC: '',
+    modifiedMerchant: '',
+    originalAmount: 0,
+    originalCurrency: '',
+    parentTransactionID: '',
+    posted: '',
+    receipt: {},
+    reimbursable: false,
+    reportID: '0',
+    status: 'Posted',
+    tag: 'private',
+    transactionID: '1564303948126109676',
+};
+
+export default transaction;
diff --git a/src/styles/index.ts b/src/styles/index.ts
index 2213b95497dd..6650743c5659 100644
--- a/src/styles/index.ts
+++ b/src/styles/index.ts
@@ -521,6 +521,9 @@ const styles = (theme: ThemeColors) =>
         textBold: {
             fontWeight: FontUtils.fontWeight.bold,
         },
+        textItalic: {
+            ...FontUtils.fontFamily.platform.MONOSPACE_ITALIC,
+        },
 
         textVersion: {
             color: theme.iconColorfulBackground,
@@ -792,6 +795,13 @@ const styles = (theme: ThemeColors) =>
             color: theme.textLight,
         },
 
+        buttonBlendContainer: {
+            backgroundColor: theme.appBG,
+            opacity: 1,
+            position: 'relative',
+            overflow: 'hidden',
+        },
+
         hoveredComponentBG: {
             backgroundColor: theme.hoverComponentBG,
         },
@@ -5484,6 +5494,10 @@ const styles = (theme: ThemeColors) =>
             borderLeftWidth: isExtraLargeScreenWidth ? 1 : 0,
             borderLeftColor: theme.border,
         }),
+
+        expenseWidgetRadius: {
+            borderRadius: variables.componentBorderRadiusNormal,
+        },
     } satisfies Styles);
 
 type ThemeStyles = ReturnType<typeof styles>;
diff --git a/src/styles/theme/themes/dark.ts b/src/styles/theme/themes/dark.ts
index 4d5894812195..725966d487a8 100644
--- a/src/styles/theme/themes/dark.ts
+++ b/src/styles/theme/themes/dark.ts
@@ -154,6 +154,7 @@ const darkTheme = {
 
     statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
     navigationBarButtonsStyle: CONST.NAVIGATION_BAR_BUTTONS_STYLE.LIGHT,
+    navigationBarBackgroundColor: `${colors.productDark100}CD`, // CD is 80% opacity (80% of 0xFF)
     colorScheme: CONST.COLOR_SCHEME.DARK,
 } satisfies ThemeColors;
 
diff --git a/src/styles/theme/themes/light.ts b/src/styles/theme/themes/light.ts
index 1a187e85b0a2..add3bf183a42 100644
--- a/src/styles/theme/themes/light.ts
+++ b/src/styles/theme/themes/light.ts
@@ -154,6 +154,7 @@ const lightTheme = {
 
     statusBarStyle: CONST.STATUS_BAR_STYLE.DARK_CONTENT,
     navigationBarButtonsStyle: CONST.NAVIGATION_BAR_BUTTONS_STYLE.DARK,
+    navigationBarBackgroundColor: `${colors.productLight100}CD`, // CD is 80% opacity (80% of 0xFF)
     colorScheme: CONST.COLOR_SCHEME.LIGHT,
 } satisfies ThemeColors;
 
diff --git a/src/styles/theme/types.ts b/src/styles/theme/types.ts
index 9dfb26e611d9..51de2a662f4a 100644
--- a/src/styles/theme/types.ts
+++ b/src/styles/theme/types.ts
@@ -109,6 +109,7 @@ type ThemeColors = {
     // e.g. the StatusBar displays either "light-content" or "dark-content" based on the theme
     statusBarStyle: StatusBarStyle;
     navigationBarButtonsStyle: NavBarButtonStyle;
+    navigationBarBackgroundColor: Color;
     colorScheme: ColorScheme;
 };
 
diff --git a/src/styles/utils/flex.ts b/src/styles/utils/flex.ts
index f5df6eef8739..662050f21102 100644
--- a/src/styles/utils/flex.ts
+++ b/src/styles/utils/flex.ts
@@ -65,6 +65,10 @@ export default {
         justifyContent: 'space-around',
     },
 
+    justifyContentEvenly: {
+        justifyContent: 'space-evenly',
+    },
+
     alignSelfStretch: {
         alignSelf: 'stretch',
     },
diff --git a/src/styles/utils/getNavigationBarType/index.android.ts b/src/styles/utils/getNavigationBarType/index.android.ts
new file mode 100644
index 000000000000..71a081010ddd
--- /dev/null
+++ b/src/styles/utils/getNavigationBarType/index.android.ts
@@ -0,0 +1,17 @@
+import NavBarManager from '@libs/NavBarManager';
+import CONST from '@src/CONST';
+import type GetNavigationBarType from './types';
+
+const getNavigationBarType: GetNavigationBarType = (insets) => {
+    const bottomInset = insets?.bottom ?? 0;
+
+    // If the bottom safe area inset is 0, we consider the device to have no navigation bar (or it being hidden by default).
+    // This could be mean either hidden soft keys, gesture navigation without a gesture bar or physical buttons.
+    if (bottomInset === 0) {
+        return CONST.NAVIGATION_BAR_TYPE.NONE;
+    }
+
+    return NavBarManager.getType();
+};
+
+export default getNavigationBarType;
diff --git a/src/styles/utils/getNavigationBarType/index.ios.ts b/src/styles/utils/getNavigationBarType/index.ios.ts
new file mode 100644
index 000000000000..1931ab0f85bb
--- /dev/null
+++ b/src/styles/utils/getNavigationBarType/index.ios.ts
@@ -0,0 +1,16 @@
+import CONST from '@src/CONST';
+import type GetNavigationBarType from './types';
+
+const getNavigationBarType: GetNavigationBarType = (insets) => {
+    const bottomInset = insets?.bottom ?? 0;
+
+    // If there is no bottom safe area inset, the device uses a physical navigation button.
+    if (bottomInset === 0) {
+        return CONST.NAVIGATION_BAR_TYPE.NONE;
+    }
+
+    // On iOS, if there is a bottom safe area inset, it means the device uses a gesture bar.
+    return CONST.NAVIGATION_BAR_TYPE.GESTURE_BAR;
+};
+
+export default getNavigationBarType;
diff --git a/src/styles/utils/getNavigationBarType/index.ts b/src/styles/utils/getNavigationBarType/index.ts
new file mode 100644
index 000000000000..32ea2065e938
--- /dev/null
+++ b/src/styles/utils/getNavigationBarType/index.ts
@@ -0,0 +1,9 @@
+import CONST from '@src/CONST';
+import type GetNavigationBarType from './types';
+
+const getNavigationBarType: GetNavigationBarType = () => {
+    // On web, there is no navigation bar.
+    return CONST.NAVIGATION_BAR_TYPE.NONE;
+};
+
+export default getNavigationBarType;
diff --git a/src/styles/utils/getNavigationBarType/types.ts b/src/styles/utils/getNavigationBarType/types.ts
new file mode 100644
index 000000000000..f0b30f4a2a72
--- /dev/null
+++ b/src/styles/utils/getNavigationBarType/types.ts
@@ -0,0 +1,6 @@
+import type {EdgeInsets} from 'react-native-safe-area-context';
+import type {NavigationBarType} from '@libs/NavBarManager/types';
+
+type GetNavigationBarType = (insets?: EdgeInsets) => NavigationBarType;
+
+export default GetNavigationBarType;
diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts
index 39d5e5ca959a..b6ee3085d981 100644
--- a/src/styles/utils/index.ts
+++ b/src/styles/utils/index.ts
@@ -24,6 +24,7 @@ import createReportActionContextMenuStyleUtils from './generators/ReportActionCo
 import createTooltipStyleUtils from './generators/TooltipStyleUtils';
 import getContextMenuItemStyles from './getContextMenuItemStyles';
 import getHighResolutionInfoWrapperStyle from './getHighResolutionInfoWrapperStyle';
+import getNavigationBarType from './getNavigationBarType/index';
 import getNavigationModalCardStyle from './getNavigationModalCardStyles';
 import getSafeAreaInsets from './getSafeAreaInsets';
 import getSignInBgStyles from './getSignInBgStyles';
@@ -331,10 +332,11 @@ type SafeAreaPadding = {
 };
 
 /**
- * Takes safe area insets and returns padding to use for a View
+ * Takes safe area insets and returns platform specific padding to use for a View
  */
-function getSafeAreaPadding(insets?: EdgeInsets, insetsPercentageProp?: number): SafeAreaPadding {
+function getPlatformSafeAreaPadding(insets?: EdgeInsets, insetsPercentageProp?: number): SafeAreaPadding {
     const platform = getPlatform();
+
     let insetsPercentage = insetsPercentageProp;
     if (insetsPercentage == null) {
         switch (platform) {
@@ -1231,7 +1233,7 @@ const staticStyleUtils = {
     getPaymentMethodMenuWidth,
     getSafeAreaInsets,
     getSafeAreaMargins,
-    getSafeAreaPadding,
+    getPlatformSafeAreaPadding,
     getSignInWordmarkWidthStyle,
     getTextColorStyle,
     getTransparentColor,
@@ -1257,6 +1259,7 @@ const staticStyleUtils = {
     getBorderRadiusStyle,
     getHighResolutionInfoWrapperStyle,
     getItemBackgroundColorStyle,
+    getNavigationBarType,
 };
 
 const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({
diff --git a/src/styles/utils/spacing.ts b/src/styles/utils/spacing.ts
index 2cdb95d4595b..526ae3a9b18d 100644
--- a/src/styles/utils/spacing.ts
+++ b/src/styles/utils/spacing.ts
@@ -732,4 +732,8 @@ export default {
     minHeight65: {
         minHeight: 260,
     },
+
+    maxHeight5: {
+        maxHeight: 20,
+    },
 } satisfies Record<string, ViewStyle>;
diff --git a/src/styles/variables.ts b/src/styles/variables.ts
index 22b60bd51d2e..2b39f2320b91 100644
--- a/src/styles/variables.ts
+++ b/src/styles/variables.ts
@@ -213,6 +213,10 @@ export default {
     photoUploadPopoverWidth: 335,
     onboardingModalWidth: 500,
     holdEducationModalWidth: 400,
+    changePolicyEducationModalWidth: 400,
+    changePolicyEducationModalIconWidth: 147.69,
+    changePolicyEducationModalIconHeight: 180,
+
     fontSizeToWidthRatio: getValueUsingPixelRatio(0.8, 1),
 
     // Emoji related variables
diff --git a/src/types/modules/react-native.d.ts b/src/types/modules/react-native.d.ts
index b5abe4f587a3..0b09824509b5 100644
--- a/src/types/modules/react-native.d.ts
+++ b/src/types/modules/react-native.d.ts
@@ -2,6 +2,7 @@
 import type {TargetedEvent} from 'react-native';
 import type {BootSplashModule} from '@libs/BootSplash/types';
 import type {EnvironmentCheckerModule} from '@libs/Environment/betaChecker/types';
+import type {NavBarButtonStyle, NavigationBarType} from '@libs/NavBarManager/types';
 import type {ShortcutManagerModule} from '@libs/ShortcutManager';
 import type StartupTimer from '@libs/StartupTimer/types';
 
@@ -10,7 +11,8 @@ type RNTextInputResetModule = {
 };
 
 type RNNavBarManagerModule = {
-    setButtonStyle: (style: 'light' | 'dark') => void;
+    setButtonStyle: (style: NavBarButtonStyle) => void;
+    getType(): NavigationBarType;
 };
 
 declare module 'react-native' {
diff --git a/src/types/onyx/DismissedProductTraining.ts b/src/types/onyx/DismissedProductTraining.ts
index ae6079b4b632..283c660be2e1 100644
--- a/src/types/onyx/DismissedProductTraining.ts
+++ b/src/types/onyx/DismissedProductTraining.ts
@@ -76,6 +76,11 @@ type DismissedProductTraining = {
      * When user dismisses the test manager on confirmantion page product training tooltip, we store the timestamp here.
      */
     [SCAN_TEST_CONFIRMATION]: string;
+
+    /**
+     * When user dismisses the ChangeReportPolicy feature training modal, we store the timestamp here.
+     */
+    [CONST.CHANGE_POLICY_TRAINING_MODAL]: string;
 };
 
 export default DismissedProductTraining;
diff --git a/src/types/onyx/OldDotAction.ts b/src/types/onyx/OldDotAction.ts
index 88c3126d0c52..11cee93ae0a0 100644
--- a/src/types/onyx/OldDotAction.ts
+++ b/src/types/onyx/OldDotAction.ts
@@ -2,7 +2,6 @@ import type {ValueOf} from 'type-fest';
 import type CONST from '@src/CONST';
 import type {
     ChangeFieldParams,
-    ChangePolicyParams,
     DelegateSubmitParams,
     ExportedToIntegrationParams,
     IntegrationsMessageParams,
@@ -52,20 +51,6 @@ type OriginalMessageChangeField = {
     originalMessage: Record<string, unknown> & ChangeFieldParams;
 };
 
-/**
- *
- */
-type OriginalMessageChangePolicy = {
-    /**
-     *
-     */
-    actionName: typeof CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY;
-    /**
-     *
-     */
-    originalMessage: ChangePolicyParams & Record<string, unknown>;
-};
-
 // Currently lacking Params
 // type OriginalMessageChangeType = {
 //     /**
@@ -346,10 +331,6 @@ type OldDotOriginalMessageMap = {
      *
      */
     [CONST.REPORT.ACTIONS.TYPE.CHANGE_FIELD]: OriginalMessageChangeField;
-    /**
-     *
-     */
-    [CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY]: OriginalMessageChangePolicy;
     /**
      *
      */
@@ -449,7 +430,6 @@ export default OldDotAction;
 export type {
     OriginalMessageChangeField,
     OldDotOriginalMessageActionName,
-    OriginalMessageChangePolicy,
     OriginalMessageDelegateSubmit,
     OriginalMessageExportedToCSV,
     OriginalMessageExportedToIntegration,
diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts
index 35fad9b57c11..e8f970448060 100644
--- a/src/types/onyx/OriginalMessage.ts
+++ b/src/types/onyx/OriginalMessage.ts
@@ -544,6 +544,15 @@ type OriginalMessageReimbursementDequeued = {
     currency: string;
 };
 
+/** Model of `CHANGEPOLICY` report action */
+type OriginalMessageChangePolicy = {
+    /** ID of the old policy */
+    fromPolicyID: string | undefined;
+
+    /** ID of the new policy */
+    toPolicyID: string;
+};
+
 /** Model of `moved` report action */
 type OriginalMessageMoved = {
     /** ID of the old policy */
@@ -729,7 +738,7 @@ type OriginalMessageMap = {
     [CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT]: OriginalMessageAddComment;
     [CONST.REPORT.ACTIONS.TYPE.APPROVED]: OriginalMessageApproved;
     [CONST.REPORT.ACTIONS.TYPE.CHANGE_FIELD]: never;
-    [CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY]: never;
+    [CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY]: OriginalMessageChangePolicy;
     [CONST.REPORT.ACTIONS.TYPE.CHANGE_TYPE]: never;
     [CONST.REPORT.ACTIONS.TYPE.CHRONOS_OOO_LIST]: OriginalMessageChronosOOOList;
     [CONST.REPORT.ACTIONS.TYPE.CLOSED]: OriginalMessageClosed;
@@ -763,6 +772,7 @@ type OriginalMessageMap = {
     [CONST.REPORT.ACTIONS.TYPE.DEMOTED_FROM_WORKSPACE]: OriginalMessageDemotedFromWorkspace;
     [CONST.REPORT.ACTIONS.TYPE.RENAMED]: OriginalMessageRenamed;
     [CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW]: OriginalMessageReportPreview;
+    [CONST.REPORT.ACTIONS.TYPE.RESOLVED_DUPLICATES]: never;
     [CONST.REPORT.ACTIONS.TYPE.SELECTED_FOR_RANDOM_AUDIT]: never;
     [CONST.REPORT.ACTIONS.TYPE.SHARE]: never;
     [CONST.REPORT.ACTIONS.TYPE.STRIPE_PAID]: never;
@@ -814,4 +824,5 @@ export type {
     OriginalMessageModifiedExpense,
     OriginalMessageExportIntegration,
     IssueNewCardOriginalMessage,
+    OriginalMessageChangePolicy,
 };
diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts
index 31a4bd39b721..e3170a208bc5 100644
--- a/src/types/onyx/Policy.ts
+++ b/src/types/onyx/Policy.ts
@@ -476,6 +476,9 @@ type QBOConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{
 
     /** Credentials of the current QBO connection */
     credentials: QBOCredentials;
+
+    /** The accounting Method for NetSuite conenction config */
+    accountingMethod?: ValueOf<typeof COMMON_CONST.INTEGRATIONS.ACCOUNTING_METHOD>;
 }>;
 
 /**
diff --git a/tests/perf-test/SidebarLinks.perf-test.tsx b/tests/perf-test/SidebarLinks.perf-test.tsx
index f6b9a6758b25..58663217c92a 100644
--- a/tests/perf-test/SidebarLinks.perf-test.tsx
+++ b/tests/perf-test/SidebarLinks.perf-test.tsx
@@ -15,6 +15,7 @@ jest.mock('../../src/libs/Navigation/Navigation', () => ({
     navigate: jest.fn(),
     isActiveRoute: jest.fn(),
     getTopmostReportId: jest.fn(),
+    getActiveRoute: jest.fn(),
     getTopmostReportActionId: jest.fn(),
     isNavigationReady: jest.fn(() => Promise.resolve()),
     isDisplayedInModal: jest.fn(() => false),
diff --git a/tests/ui/DebugReportActionsTest.tsx b/tests/ui/DebugReportActionsTest.tsx
new file mode 100644
index 000000000000..82dcab972bb2
--- /dev/null
+++ b/tests/ui/DebugReportActionsTest.tsx
@@ -0,0 +1,76 @@
+import {fireEvent, render, screen} from '@testing-library/react-native';
+import Onyx from 'react-native-onyx';
+import {LocaleContextProvider} from '@components/LocaleContextProvider';
+import OnyxProvider from '@components/OnyxProvider';
+import type Navigation from '@libs/Navigation/Navigation';
+import DebugReportActions from '@pages/Debug/Report/DebugReportActions';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import type {Policy, Report, ReportAction} from '@src/types/onyx';
+import createRandomPolicy from '../utils/collections/policies';
+import createRandomReportAction from '../utils/collections/reportActions';
+import createRandomReport from '../utils/collections/reports';
+import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct';
+
+jest.mock('@react-navigation/native', () => {
+    const actualNav = jest.requireActual<typeof Navigation>('@react-navigation/native');
+    return {
+        ...actualNav,
+        useIsFocused: () => true,
+        useFocusEffect: jest.fn(),
+    };
+});
+
+jest.mock('@src/libs/Navigation/Navigation', () => ({
+    navigate: jest.fn(),
+}));
+
+describe('DebugReportActions', () => {
+    beforeAll(() => {
+        Onyx.init({
+            keys: ONYXKEYS,
+            safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
+        });
+    });
+
+    afterEach(async () => {
+        await Onyx.clear();
+    });
+
+    it('should show no results message when search is empty', async () => {
+        const policyID = '12';
+        const reportID = '1';
+        const reportActionID = '123';
+        const policy: Policy = createRandomPolicy(Number(policyID));
+        const report: Report = {...createRandomReport(Number(reportID)), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, policyID};
+        const reportActionL: ReportAction = {
+            ...createRandomReportAction(Number(reportActionID)),
+            reportID,
+            message: {
+                html: '',
+                text: '',
+                type: '',
+            },
+        };
+        await Onyx.merge(`${ONYXKEYS.NVP_PREFERRED_LOCALE}`, 'en');
+        await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, policy);
+        await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report);
+        await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {
+            [reportActionID]: reportActionL,
+        });
+
+        render(
+            <OnyxProvider>
+                <LocaleContextProvider>
+                    <DebugReportActions reportID={reportID} />
+                </LocaleContextProvider>
+            </OnyxProvider>,
+        );
+
+        await waitForBatchedUpdatesWithAct();
+
+        const input = screen.getByTestId('selection-list-text-input');
+        fireEvent.changeText(input, 'testtesttesttest');
+        expect(await screen.findByText('No results found')).toBeOnTheScreen();
+    });
+});
diff --git a/tests/unit/BaseSelectionListTest.tsx b/tests/unit/BaseSelectionListTest.tsx
index 6589eec7db80..ba74a5fb6e08 100644
--- a/tests/unit/BaseSelectionListTest.tsx
+++ b/tests/unit/BaseSelectionListTest.tsx
@@ -3,12 +3,12 @@ import {fireEvent, render, screen} from '@testing-library/react-native';
 import {SectionList} from 'react-native';
 import BaseSelectionList from '@components/SelectionList/BaseSelectionList';
 import RadioListItem from '@components/SelectionList/RadioListItem';
-import type {BaseSelectionListProps, ListItem} from '@components/SelectionList/types';
+import type {ListItem, SelectionListProps} from '@components/SelectionList/types';
 import type Navigation from '@libs/Navigation/Navigation';
 import CONST from '@src/CONST';
 
 type BaseSelectionListSections<TItem extends ListItem> = {
-    sections: BaseSelectionListProps<TItem>['sections'];
+    sections: SelectionListProps<TItem>['sections'];
     canSelectMultiple?: boolean;
 };
 
diff --git a/tests/unit/PolicyUtilsTest.ts b/tests/unit/PolicyUtilsTest.ts
index ac386c68a2d6..f3b277ca5d7f 100644
--- a/tests/unit/PolicyUtilsTest.ts
+++ b/tests/unit/PolicyUtilsTest.ts
@@ -2,7 +2,16 @@
 import Onyx from 'react-native-onyx';
 import type {OnyxEntry} from 'react-native-onyx';
 import DateUtils from '@libs/DateUtils';
-import {getActivePolicies, getManagerAccountID, getPolicyNameByID, getRateDisplayValue, getSubmitToAccountID, getUnitRateValue, shouldShowPolicy} from '@libs/PolicyUtils';
+import {
+    getActivePolicies,
+    getManagerAccountID,
+    getPolicyNameByID,
+    getRateDisplayValue,
+    getSubmitToAccountID,
+    getUnitRateValue,
+    isWorkspaceEligibleForReportChange,
+    shouldShowPolicy,
+} from '@libs/PolicyUtils';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import type {PersonalDetailsList, Policy, PolicyEmployeeList, Report, Transaction} from '@src/types/onyx';
@@ -73,9 +82,11 @@ const categoryapprover2AccountID = 4;
 const tagapprover1AccountID = 5;
 const tagapprover2AccountID = 6;
 const ownerAccountID = 7;
+const approverAccountID = 8;
 const employeeEmail = 'employee@test.com';
 const adminEmail = 'admin@test.com';
 const categoryApprover1Email = 'categoryapprover1@test.com';
+const approverEmail = 'approver@test.com';
 
 const personalDetails: PersonalDetailsList = {
     '1': {
@@ -106,6 +117,10 @@ const personalDetails: PersonalDetailsList = {
         accountID: ownerAccountID,
         login: 'owner@test.com',
     },
+    '8': {
+        accountID: approverAccountID,
+        login: approverEmail,
+    },
 };
 
 const rules = {
@@ -589,4 +604,139 @@ describe('PolicyUtils', () => {
             expect(result).toBe(categoryapprover1AccountID);
         });
     });
+
+    describe('isWorkspaceEligibleForReportChange', () => {
+        beforeEach(() => {
+            wrapOnyxWithWaitForBatchedUpdates(Onyx);
+            Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, personalDetails);
+        });
+        afterEach(async () => {
+            await Onyx.clear();
+            await waitForBatchedUpdatesWithAct();
+        });
+
+        it('returns false if current user is not a member of the new policy', async () => {
+            const newPolicy = {
+                ...createRandomPolicy(1),
+                employeeList: {},
+            };
+            const report = createRandomReport(0);
+            const oldPolicy = createRandomPolicy(0);
+            const currentUserLogin = 'nonmember@tests.com';
+            await Onyx.set(ONYXKEYS.SESSION, {email: currentUserLogin, accountID: 0});
+
+            const result = isWorkspaceEligibleForReportChange(newPolicy, report, oldPolicy, currentUserLogin);
+            expect(result).toBe(false);
+        });
+
+        it('returns true if current user is the submitter', async () => {
+            const currentUserLogin = employeeEmail;
+            const currentUserAccountID = employeeAccountID;
+            await Onyx.set(ONYXKEYS.SESSION, {email: currentUserLogin, accountID: currentUserAccountID});
+
+            const newPolicy = {
+                ...createRandomPolicy(1),
+                employeeList: {
+                    [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.USER},
+                },
+            };
+            const oldPolicy = createRandomPolicy(0);
+            const report = {
+                ...createRandomReport(0),
+                ownerAccountID: currentUserAccountID,
+            };
+
+            const result = isWorkspaceEligibleForReportChange(newPolicy, report, oldPolicy, currentUserLogin);
+            expect(result).toBe(true);
+        });
+
+        it('returns true if current user is a policy admin', async () => {
+            const currentUserLogin = adminEmail;
+            const currentUserAccountID = adminAccountID;
+            await Onyx.set(ONYXKEYS.SESSION, {email: currentUserLogin, accountID: currentUserAccountID});
+
+            const newPolicy = {
+                ...createRandomPolicy(1),
+                employeeList: {
+                    [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.ADMIN},
+                },
+            };
+            const oldPolicy = createRandomPolicy(0);
+            const report = createRandomReport(0);
+
+            const result = isWorkspaceEligibleForReportChange(newPolicy, report, oldPolicy, currentUserLogin);
+            expect(result).toBe(true);
+        });
+
+        it('returns true if current user is the policy owner', async () => {
+            const currentUserLogin = 'owner@test.com';
+            const currentUserAccountID = ownerAccountID;
+            await Onyx.set(ONYXKEYS.SESSION, {email: currentUserLogin, accountID: currentUserAccountID});
+
+            const newPolicy = {
+                ...createRandomPolicy(1),
+                ownerAccountID: currentUserAccountID,
+                employeeList: {
+                    [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.ADMIN},
+                },
+            };
+            const oldPolicy = createRandomPolicy(0);
+            const report = createRandomReport(0);
+
+            const result = isWorkspaceEligibleForReportChange(newPolicy, report, oldPolicy, currentUserLogin);
+            expect(result).toBe(true);
+        });
+
+        it('returns true if current user is the approver and submitter is a member', async () => {
+            const currentUserLogin = approverEmail;
+            const currentUserAccountID = approverAccountID;
+            await Onyx.set(ONYXKEYS.SESSION, {email: currentUserLogin, accountID: currentUserAccountID});
+
+            const submitterLogin = employeeEmail;
+            const submitterAccountID = employeeAccountID;
+
+            const newPolicy = {
+                ...createRandomPolicy(1),
+                employeeList: {
+                    [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.USER},
+                    [submitterLogin]: {email: submitterLogin, role: CONST.POLICY.ROLE.USER},
+                },
+            };
+            const oldPolicy = {
+                ...createRandomPolicy(0),
+                employeeList: {
+                    [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.USER},
+                    [submitterLogin]: {email: submitterLogin, role: CONST.POLICY.ROLE.USER, submitsTo: currentUserLogin},
+                },
+                approver: currentUserLogin,
+            };
+            const report = {
+                ...createRandomReport(0),
+                ownerAccountID: submitterAccountID,
+            };
+
+            const result = isWorkspaceEligibleForReportChange(newPolicy, report, oldPolicy, currentUserLogin);
+            expect(result).toBe(true);
+        });
+
+        it('returns false if current user is approver but submitter not member', async () => {
+            const currentUserLogin = approverEmail;
+            const currentUserAccountID = approverAccountID;
+            await Onyx.set(ONYXKEYS.SESSION, {email: currentUserLogin, accountID: currentUserAccountID});
+
+            const newPolicy = {
+                ...createRandomPolicy(1),
+                employeeList: {
+                    [currentUserLogin]: {email: currentUserLogin, role: CONST.POLICY.ROLE.USER},
+                },
+            };
+            const report = {
+                ...createRandomReport(0),
+                ownerAccountID: employeeAccountID,
+            };
+            const oldPolicy = createRandomPolicy(0);
+
+            expect(isWorkspaceEligibleForReportChange(newPolicy, report, oldPolicy, currentUserLogin)).toBe(false);
+        });
+    });
 });
diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts
index 6151ac20ba30..567db5189d14 100644
--- a/tests/unit/ReportUtilsTest.ts
+++ b/tests/unit/ReportUtilsTest.ts
@@ -592,6 +592,7 @@ describe('ReportUtils', () => {
                 isUnreadWithMention: false,
                 stateNum: CONST.REPORT.STATE_NUM.OPEN,
                 statusNum: CONST.REPORT.STATUS_NUM.OPEN,
+                hasParentAccess: false,
             };
             expect(requiresAttentionFromCurrentUser(report)).toBe(true);
         });
diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts
index 92244607a976..0f57d573c4d5 100644
--- a/tests/unit/Search/SearchUIUtilsTest.ts
+++ b/tests/unit/Search/SearchUIUtilsTest.ts
@@ -1367,7 +1367,7 @@ describe('SearchUIUtils', () => {
 
             const expectedRoutes = [
                 ROUTES.SEARCH_ROOT.getRoute({query: 'type:expense status:all sortBy:date sortOrder:desc'}),
-                ROUTES.SEARCH_ROOT.getRoute({query: 'type:expense status:all sortBy:date sortOrder:desc', groupBy: 'reports'}),
+                ROUTES.SEARCH_ROOT.getRoute({query: 'type:expense status:all sortBy:date sortOrder:desc groupBy:reports'}),
                 ROUTES.SEARCH_ROOT.getRoute({query: 'type:chat status:all sortBy:date sortOrder:desc'}),
                 ROUTES.SEARCH_ROOT.getRoute({query: 'type:trip status:all sortBy:date sortOrder:desc'}),
             ];
diff --git a/tests/unit/SidePaneUtilsTest.ts b/tests/unit/SidePaneUtilsTest.ts
new file mode 100644
index 000000000000..c94f42c6585e
--- /dev/null
+++ b/tests/unit/SidePaneUtilsTest.ts
@@ -0,0 +1,75 @@
+import {substituteRouteParameters} from '@libs/SidePaneUtils';
+
+describe('substituteRouteParameters', () => {
+    test('should substitute simple route parameters', () => {
+        const route = '/workspaces/123/rules/456';
+        const params = {workspaceID: '123', ruleID: '456'};
+        expect(substituteRouteParameters(route, params)).toBe('/workspaces/:workspaceID/rules/:ruleID');
+    });
+
+    test('should handle routes with multiple occurrences of a parameter', () => {
+        const route = '/reports/987/items/987';
+        const params = {reportID: '987'};
+        expect(substituteRouteParameters(route, params)).toBe('/reports/:reportID/items/:reportID');
+    });
+
+    test('should ignore non-matching parameters', () => {
+        const route = '/settings/profile';
+        const params = {userID: '123'};
+        expect(substituteRouteParameters(route, params)).toBe('/settings/profile');
+    });
+
+    test('should work with nested objects in params', () => {
+        const route = '/users/789/orders/456';
+        const params = {user: {id: '789'}, order: {id: '456'}};
+        expect(substituteRouteParameters(route, params)).toBe('/users/:id/orders/:id'); // Could be problematic with duplicate param names
+    });
+
+    test('should handle parameters that do not exist in the route', () => {
+        const route = '/dashboard/overview';
+        const params = {dashboardID: '111'};
+        expect(substituteRouteParameters(route, params)).toBe('/dashboard/overview');
+    });
+
+    test('should handle routes with query parameters correctly', () => {
+        const route = '/reports/555/view?filter=active';
+        const params = {reportID: '555'};
+        expect(substituteRouteParameters(route, params)).toBe('/reports/:reportID/view?filter=active');
+    });
+
+    test('should not replace partial parameter values', () => {
+        const route = '/workspaces/123456/activities';
+        const params = {workspaceID: '123'};
+        expect(substituteRouteParameters(route, params)).toBe('/workspaces/123456/activities'); // '123' is a subset of '123456'
+    });
+
+    test('should return the original route if params is an empty object', () => {
+        const route = '/users/42/profile';
+        const params = {};
+        expect(substituteRouteParameters(route, params)).toBe('/users/42/profile');
+    });
+
+    test('should return the original route if params are null or undefined', () => {
+        const route = '/reports/23/details';
+        expect(substituteRouteParameters(route, null as unknown as Record<string, unknown>)).toBe('/reports/23/details');
+        expect(substituteRouteParameters(route, undefined as unknown as Record<string, unknown>)).toBe('/reports/23/details');
+    });
+
+    test('should properly replace overlapping values', () => {
+        const route = '/reports/123/report/123/details';
+        const params = {id: '123'};
+        expect(substituteRouteParameters(route, params)).toBe('/reports/:id/report/:id/details');
+    });
+
+    test('should handle deeply nested parameters', () => {
+        const route = '/company/789/employees/456/profile';
+        const params = {company: {id: '789'}, employee: {id: '456'}};
+        expect(substituteRouteParameters(route, params)).toBe('/company/:id/employees/:id/profile');
+    });
+
+    test('should prevent accidental replacements inside unrelated words', () => {
+        const route = '/analysis/321/report321/details';
+        const params = {reportID: '321'};
+        expect(substituteRouteParameters(route, params)).toBe('/analysis/:reportID/report321/details');
+    });
+});
diff --git a/tests/unit/SidebarUtilsTest.ts b/tests/unit/SidebarUtilsTest.ts
index 2771a2c5f78e..c5697f8385c6 100644
--- a/tests/unit/SidebarUtilsTest.ts
+++ b/tests/unit/SidebarUtilsTest.ts
@@ -1,6 +1,7 @@
 /* eslint-disable @typescript-eslint/naming-convention */
 import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
 import Onyx from 'react-native-onyx';
+import DateUtils from '@libs/DateUtils';
 import {getReportActionMessageText} from '@libs/ReportActionsUtils';
 import SidebarUtils from '@libs/SidebarUtils';
 import CONST from '@src/CONST';
@@ -232,6 +233,45 @@ describe('SidebarUtils', () => {
             expect(optionDataPinned?.isPinned).toBe(true);
             expect(optionDataUnpinned?.isPinned).toBe(false);
         });
+
+        it('returns null when report is archived', async () => {
+            const MOCK_REPORT: Report = {
+                reportID: '5',
+            };
+
+            const reportNameValuePairs = {
+                private_isArchived: DateUtils.getDBTime(),
+            };
+
+            await Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${MOCK_REPORT.reportID}`, reportNameValuePairs);
+
+            await waitForBatchedUpdates();
+
+            const MOCK_REPORT_ACTION = {
+                reportActionID: '1',
+                actionName: CONST.REPORT.ACTIONS.TYPE.CREATED,
+                actorAccountID: 12345,
+                created: '2024-08-08 18:20:44.171',
+                message: [
+                    {
+                        type: '',
+                        text: '',
+                    },
+                ],
+                errors: {
+                    someError: 'Some error occurred',
+                },
+            };
+            const MOCK_REPORT_ACTIONS: OnyxEntry<ReportActions> = {
+                // eslint-disable-next-line @typescript-eslint/naming-convention
+                '1': MOCK_REPORT_ACTION,
+            };
+            const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection<TransactionViolation[]> = {};
+
+            const result = SidebarUtils.getReasonAndReportActionThatHasRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS);
+
+            expect(result).toBeNull();
+        });
     });
 
     describe('shouldShowRedBrickRoad', () => {
@@ -376,6 +416,25 @@ describe('SidebarUtils', () => {
 
             expect(result).toBe(false);
         });
+
+        it('returns false when report is archived', () => {
+            const MOCK_REPORT: Report = {
+                reportID: '5',
+                errorFields: {
+                    export: {
+                        error: 'Some error occurred',
+                    },
+                },
+            };
+            // This report with reportID 5 is already archived from previous tests
+            // where we set reportNameValuePairs with private_isArchived
+            const MOCK_REPORT_ACTIONS: OnyxEntry<ReportActions> = {};
+            const MOCK_TRANSACTION_VIOLATIONS: OnyxCollection<TransactionViolation[]> = {};
+
+            const result = SidebarUtils.shouldShowRedBrickRoad(MOCK_REPORT, MOCK_REPORT_ACTIONS, false, MOCK_TRANSACTION_VIOLATIONS);
+
+            expect(result).toBe(false);
+        });
     });
 
     describe('getWelcomeMessage', () => {
